Files

Return to Package Diff Home.
Brought to you by Intrinsic.

Package Diff: react-native @ 0.57.8 .. 0.59.4

android/com/facebook/react/react-native/0.57.8/react-native-0.57.8.aar

Binary file android/com/facebook/react/react-native/0.57.8/react-native-0.57.8.aar has changed

android/com/facebook/react/react-native/0.57.8/react-native-0.57.8.aar.md5

@@ -1 +0,0 @@
-dc980481b0ad5483a7b888f007561c2a
\ No newline at end of file

android/com/facebook/react/react-native/0.57.8/react-native-0.57.8.aar.sha1

@@ -1 +0,0 @@
-890ccd8da55b5350e350d8e7329af5724d396e5d
\ No newline at end of file

android/com/facebook/react/react-native/0.57.8/react-native-0.57.8-javadoc.jar

Binary file android/com/facebook/react/react-native/0.57.8/react-native-0.57.8-javadoc.jar has changed

android/com/facebook/react/react-native/0.57.8/react-native-0.57.8-javadoc.jar.md5

@@ -1 +0,0 @@
-9d30534558032ec94fd9941fb1c7f835
\ No newline at end of file

android/com/facebook/react/react-native/0.57.8/react-native-0.57.8-javadoc.jar.sha1

@@ -1 +0,0 @@
-cb6b1213a6689cb6c3f526f4a4c277597460e559
\ No newline at end of file

android/com/facebook/react/react-native/0.57.8/react-native-0.57.8.pom

@@ -1,98 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <modelVersion>4.0.0</modelVersion>
- <groupId>com.facebook.react</groupId>
- <artifactId>react-native</artifactId>
- <version>0.57.8</version>
- <packaging>aar</packaging>
- <name>ReactNative</name>
- <description>A framework for building native apps with React</description>
- <url>https://github.com/facebook/react-native</url>
- <licenses>
- <license>
- <name>MIT License</name>
- <url>https://github.com/facebook/react-native/blob/master/LICENSE</url>
- <distribution>repo</distribution>
- </license>
- </licenses>
- <developers>
- <developer>
- <id>facebook</id>
- <name>Facebook</name>
- </developer>
- </developers>
- <scm>
- <connection>scm:git:https://github.com/facebook/react-native.git</connection>
- <developerConnection>scm:git:git@github.com:facebook/react-native.git</developerConnection>
- <url>https://github.com/facebook/react-native.git</url>
- </scm>
- <dependencies>
- <dependency>
- <groupId>com.facebook.infer.annotation</groupId>
- <artifactId>infer-annotation</artifactId>
- <version>0.11.2</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>javax.inject</groupId>
- <artifactId>javax.inject</artifactId>
- <version>1</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>com.android.support</groupId>
- <artifactId>appcompat-v7</artifactId>
- <version>27.1.1</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>com.facebook.fresco</groupId>
- <artifactId>fresco</artifactId>
- <version>1.10.0</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>com.facebook.fresco</groupId>
- <artifactId>imagepipeline-okhttp3</artifactId>
- <version>1.10.0</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>com.facebook.soloader</groupId>
- <artifactId>soloader</artifactId>
- <version>0.5.1</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>com.google.code.findbugs</groupId>
- <artifactId>jsr305</artifactId>
- <version>3.0.2</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>com.squareup.okhttp3</groupId>
- <artifactId>okhttp</artifactId>
- <version>3.11.0</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>com.squareup.okhttp3</groupId>
- <artifactId>okhttp-urlconnection</artifactId>
- <version>3.11.0</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>com.squareup.okio</groupId>
- <artifactId>okio</artifactId>
- <version>1.14.0</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>org.webkit</groupId>
- <artifactId>android-jsc</artifactId>
- <version>r174650</version>
- <scope>compile</scope>
- </dependency>
- </dependencies>
-</project>

android/com/facebook/react/react-native/0.57.8/react-native-0.57.8.pom.md5

@@ -1 +0,0 @@
-6d23d91766c9ad7631637aacb19b2088
\ No newline at end of file

android/com/facebook/react/react-native/0.57.8/react-native-0.57.8.pom.sha1

@@ -1 +0,0 @@
-9f5d1993ec12d9d9cec68eea732e8879656f4d0f
\ No newline at end of file

android/com/facebook/react/react-native/0.57.8/react-native-0.57.8-sources.jar

Binary file android/com/facebook/react/react-native/0.57.8/react-native-0.57.8-sources.jar has changed

android/com/facebook/react/react-native/0.57.8/react-native-0.57.8-sources.jar.md5

@@ -1 +0,0 @@
-4dd711471bf102cbda667a5336cedb6d
\ No newline at end of file

android/com/facebook/react/react-native/0.57.8/react-native-0.57.8-sources.jar.sha1

@@ -1 +0,0 @@
-448297aa6b6c242e64ca649fcd50c9c79ab24307
\ No newline at end of file

android/com/facebook/react/react-native/0.59.4/react-native-0.59.4.aar

Binary file android/com/facebook/react/react-native/0.59.4/react-native-0.59.4.aar has changed

android/com/facebook/react/react-native/0.59.4/react-native-0.59.4.aar.md5

@@ -0,0 +1 @@
+e27f6a42a3410f08de33f281e7dc8ea1
\ No newline at end of file

android/com/facebook/react/react-native/0.59.4/react-native-0.59.4.aar.sha1

@@ -0,0 +1 @@
+f089e982d4d98a14ca0315fd70726cd228f7fdec
\ No newline at end of file

android/com/facebook/react/react-native/0.59.4/react-native-0.59.4-javadoc.jar

Binary file android/com/facebook/react/react-native/0.59.4/react-native-0.59.4-javadoc.jar has changed

android/com/facebook/react/react-native/0.59.4/react-native-0.59.4-javadoc.jar.md5

@@ -0,0 +1 @@
+bf2f752b9e797fb8fbd7e813341647a0
\ No newline at end of file

android/com/facebook/react/react-native/0.59.4/react-native-0.59.4-javadoc.jar.sha1

@@ -0,0 +1 @@
+fdb34b7545c355b6ac35f8622886f660193de11b
\ No newline at end of file

android/com/facebook/react/react-native/0.59.4/react-native-0.59.4.pom

@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.facebook.react</groupId>
+ <artifactId>react-native</artifactId>
+ <version>0.59.4</version>
+ <packaging>aar</packaging>
+ <name>ReactNative</name>
+ <description>A framework for building native apps with React</description>
+ <url>https://github.com/facebook/react-native</url>
+ <licenses>
+ <license>
+ <name>MIT License</name>
+ <url>https://github.com/facebook/react-native/blob/master/LICENSE</url>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+ <developers>
+ <developer>
+ <id>facebook</id>
+ <name>Facebook</name>
+ </developer>
+ </developers>
+ <scm>
+ <connection>scm:git:https://github.com/facebook/react-native.git</connection>
+ <developerConnection>scm:git:git@github.com:facebook/react-native.git</developerConnection>
+ <url>https://github.com/facebook/react-native.git</url>
+ </scm>
+ <dependencies>
+ <dependency>
+ <groupId>com.facebook.infer.annotation</groupId>
+ <artifactId>infer-annotation</artifactId>
+ <version>0.11.2</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.inject</groupId>
+ <artifactId>javax.inject</artifactId>
+ <version>1</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.android.support</groupId>
+ <artifactId>appcompat-v7</artifactId>
+ <version>28.0.0</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.facebook.fresco</groupId>
+ <artifactId>fresco</artifactId>
+ <version>1.10.0</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.facebook.fresco</groupId>
+ <artifactId>imagepipeline-okhttp3</artifactId>
+ <version>1.10.0</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.facebook.soloader</groupId>
+ <artifactId>soloader</artifactId>
+ <version>0.6.0</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.findbugs</groupId>
+ <artifactId>jsr305</artifactId>
+ <version>3.0.2</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.squareup.okhttp3</groupId>
+ <artifactId>okhttp</artifactId>
+ <version>3.12.1</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.squareup.okhttp3</groupId>
+ <artifactId>okhttp-urlconnection</artifactId>
+ <version>3.12.1</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.squareup.okio</groupId>
+ <artifactId>okio</artifactId>
+ <version>1.15.0</version>
+ <scope>compile</scope>
+ </dependency>
+ </dependencies>
+</project>

android/com/facebook/react/react-native/0.59.4/react-native-0.59.4.pom.md5

@@ -0,0 +1 @@
+56786bf5fa2385f651ee59573e60c5e3
\ No newline at end of file

android/com/facebook/react/react-native/0.59.4/react-native-0.59.4.pom.sha1

@@ -0,0 +1 @@
+d864203478b32c47f252b5f413126457a928753d
\ No newline at end of file

android/com/facebook/react/react-native/0.59.4/react-native-0.59.4-sources.jar

Binary file android/com/facebook/react/react-native/0.59.4/react-native-0.59.4-sources.jar has changed

android/com/facebook/react/react-native/0.59.4/react-native-0.59.4-sources.jar.md5

@@ -0,0 +1 @@
+00bd6c37595546b3383cfee2c7a8d80b
\ No newline at end of file

android/com/facebook/react/react-native/0.59.4/react-native-0.59.4-sources.jar.sha1

@@ -0,0 +1 @@
+651b45a286c482b78c2098bca9109268814de3d0
\ No newline at end of file

android/com/facebook/react/react-native/maven-metadata.xml

@@ -3,10 +3,10 @@
<groupId>com.facebook.react</groupId>
<artifactId>react-native</artifactId>
<versioning>
- <release>0.57.8</release>
+ <release>0.59.4</release>
<versions>
- <version>0.57.8</version>
+ <version>0.59.4</version>
</versions>
- <lastUpdated>20181213102839</lastUpdated>
+ <lastUpdated>20190408215650</lastUpdated>
</versioning>
</metadata>

android/com/facebook/react/react-native/maven-metadata.xml.md5

@@ -1 +1 @@
-73175d9b93c4965c7552ec102f8ea09b
\ No newline at end of file
+a5f09d00f989ee5dc92117fa098da915
\ No newline at end of file

android/com/facebook/react/react-native/maven-metadata.xml.sha1

@@ -1 +1 @@
-18118d94ee68d061fdd2da5f0424326686d38455
\ No newline at end of file
+079305fc9f6ed4ff15b93cfcf3825c611ce07ab0
\ No newline at end of file

cli.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,4 +9,10 @@
'use strict';
-module.exports = require('./local-cli/cli.js');
+var cli = require('@react-native-community/cli');
+
+if (require.main === module) {
+ cli.run();
+}
+
+module.exports = cli;

flow/console.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

flow/create-react-class.js

@@ -1,16 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow strict
- * @nolint
- */
-
-// TODO (acdlite) Remove this file once flowtype/flow-typed/pull/773 is merged
-
-declare module 'create-react-class' {
- declare module.exports: React$CreateClass;
-}

flow/fbjs.js

@@ -1,20 +0,0 @@
-/**
- * Copyright (c) 2013-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-declare module 'fbjs/lib/invariant' {
- declare module.exports: <T>(
- condition: any,
- message: string,
- ...args: Array<any>
- ) => void;
-}
-
-declare module 'fbjs/lib/nullthrows' {
- declare module.exports: <T>(value: ?T) => T;
-}

flow/jest.js

@@ -1,23 +1,10 @@
/**
- * Copyright (c) 2004-present, Facebook, Inc.
+ * 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.
*
- * Modified from https://raw.githubusercontent.com/flowtype/flow-typed/b43dff3e0ed5ccf7033839045f4819e8db40faa9/definitions/npm/jest_v20.x.x/flow_v0.22.x-/jest_v20.x.x.js
- * Duplicated from www/flow/shared/jest.js
- * List of modifications:
- * - added function fail
- * - added jest.requireActual
- * - added jest.requireMock
- * - added JestMockFn.mockName
- * - added JestMockFn.mockRejectedValue
- * - added JestMockFn.mockRejectedValueOnce
- * - added JestMockFn.mockResolvedValue
- * - added JestMockFn.mockResolvedValueOnce
- * - added JestMockFn.mock.thrownErrors
- * - added JestMockFn.mock.returnValues
- * - added jest.setTimeout
+ * Copied from https://raw.githubusercontent.com/flow-typed/flow-typed/master/definitions/npm/jest_v23.x.x/flow_v0.39.x-/jest_v23.x.x.js
* @flow strict
* @format
*/
@@ -42,10 +29,10 @@
*/
instances: Array<TReturn>,
/**
- * An array containing the results of a method, and whether they were
- * returned or thrown.
+ * An array that contains all the object results that have been
+ * returned by this mock function call
*/
- results: Array<{isThrown: boolean}>,
+ results: Array<{isThrow: boolean, value: TReturn}>,
},
/**
* Resets all information stored in the mockFn.mock.calls and
@@ -89,33 +76,35 @@
*/
mockName(name: string): JestMockFn<TArguments, TReturn>,
/**
- * Sugar for: jest.fn().mockReturnValue(Promise.reject(value));
+ * Just a simple sugar function for returning `this`
*/
- mockRejectedValue(value: TReturn): JestMockFn<TArguments, TReturn>,
+ mockReturnThis(): void,
/**
- * Sugar for: jest.fn().mockReturnValueOnce(Promise.reject(value));
+ * Accepts a value that will be returned whenever the mock function is called.
*/
- mockRejectedValueOnce(value: TReturn): JestMockFn<TArguments, TReturn>,
+ mockReturnValue(value: TReturn): JestMockFn<TArguments, TReturn>,
/**
- * Sugar for: jest.fn().mockReturnValue(Promise.resolve(value));
+ * Sugar for only returning a value once inside your mock
*/
- mockResolvedValue(value: TReturn): JestMockFn<TArguments, TReturn>,
+ mockReturnValueOnce(value: TReturn): JestMockFn<TArguments, TReturn>,
/**
- * Sugar for: jest.fn().mockReturnValueOnce(Promise.resolve(value));
+ * Sugar for jest.fn().mockImplementation(() => Promise.resolve(value))
*/
- mockResolvedValueOnce(value: TReturn): JestMockFn<TArguments, TReturn>,
+ mockResolvedValue(value: TReturn): JestMockFn<TArguments, Promise<TReturn>>,
/**
- * Just a simple sugar function for returning `this`
+ * Sugar for jest.fn().mockImplementationOnce(() => Promise.resolve(value))
*/
- mockReturnThis(): void,
+ mockResolvedValueOnce(
+ value: TReturn,
+ ): JestMockFn<TArguments, Promise<TReturn>>,
/**
- * Deprecated: use jest.fn(() => value) instead
+ * Sugar for jest.fn().mockImplementation(() => Promise.reject(value))
*/
- mockReturnValue(value: TReturn): JestMockFn<TArguments, TReturn>,
+ mockRejectedValue(value: TReturn): JestMockFn<TArguments, Promise<any>>,
/**
- * Sugar for only returning a value once inside your mock
+ * Sugar for jest.fn().mockImplementationOnce(() => Promise.reject(value))
*/
- mockReturnValueOnce(value: TReturn): JestMockFn<TArguments, TReturn>,
+ mockRejectedValueOnce(value: TReturn): JestMockFn<TArguments, Promise<any>>,
};
type JestAsymmetricEqualityType = {
@@ -147,7 +136,10 @@
pass: boolean,
};
-type JestMatcher = (actual: any, expected: any) => JestMatcherResult;
+type JestMatcher = (
+ actual: any,
+ expected: any,
+) => JestMatcherResult | Promise<JestMatcherResult>;
type JestPromiseType = {
/**
@@ -163,20 +155,55 @@
};
/**
+ * Jest allows functions and classes to be used as test names in test() and
+ * describe()
+ */
+type JestTestName = string | Function;
+
+/**
+ * Plugin: jest-styled-components
+ */
+
+type JestStyledComponentsMatcherValue =
+ | string
+ | JestAsymmetricEqualityType
+ | RegExp
+ | typeof undefined;
+
+type JestStyledComponentsMatcherOptions = {
+ media?: string,
+ modifier?: string,
+ supports?: string,
+};
+
+type JestStyledComponentsMatchersType = {
+ toHaveStyleRule(
+ property: string,
+ value: JestStyledComponentsMatcherValue,
+ options?: JestStyledComponentsMatcherOptions,
+ ): void,
+};
+
+/**
* Plugin: jest-enzyme
*/
type EnzymeMatchersType = {
toBeChecked(): void,
toBeDisabled(): void,
toBeEmpty(): void,
+ toBeEmptyRender(): void,
toBePresent(): void,
toContainReact(element: React$Element<any>): void,
+ toExist(): void,
toHaveClassName(className: string): void,
toHaveHTML(html: string): void,
- toHaveProp(propKey: string, propValue?: any): void,
+ toHaveProp: ((propKey: string, propValue?: any) => void) &
+ ((props: Object) => void),
toHaveRef(refName: string): void,
- toHaveState(stateKey: string, stateValue?: any): void,
- toHaveStyle(styleKey: string, styleValue?: any): void,
+ toHaveState: ((stateKey: string, stateValue?: any) => void) &
+ ((state: Object) => void),
+ toHaveStyle: ((styleKey: string, styleValue?: any) => void) &
+ ((style: Object) => void),
toHaveTagName(tagName: string): void,
toHaveText(text: string): void,
toIncludeText(text: string): void,
@@ -185,133 +212,518 @@
toMatchSelector(selector: string): void,
};
-type JestExpectType = {
- not: JestExpectType & EnzymeMatchersType,
+// DOM testing library extensions https://github.com/kentcdodds/dom-testing-library#custom-jest-matchers
+type DomTestingLibraryType = {
+ toBeInTheDOM(): void,
+ toHaveTextContent(content: string): void,
+ toHaveAttribute(name: string, expectedValue?: string): void,
+};
+
+// Jest JQuery Matchers: https://github.com/unindented/custom-jquery-matchers
+type JestJQueryMatchersType = {
+ toExist(): void,
+ toHaveLength(len: number): void,
+ toHaveId(id: string): void,
+ toHaveClass(className: string): void,
+ toHaveTag(tag: string): void,
+ toHaveAttr(key: string, val?: any): void,
+ toHaveProp(key: string, val?: any): void,
+ toHaveText(text: string | RegExp): void,
+ toHaveData(key: string, val?: any): void,
+ toHaveValue(val: any): void,
+ toHaveCss(css: {[key: string]: any}): void,
+ toBeChecked(): void,
+ toBeDisabled(): void,
+ toBeEmpty(): void,
+ toBeHidden(): void,
+ toBeSelected(): void,
+ toBeVisible(): void,
+ toBeFocused(): void,
+ toBeInDom(): void,
+ toBeMatchedBy(sel: string): void,
+ toHaveDescendant(sel: string): void,
+ toHaveDescendantWithText(sel: string, text: string | RegExp): void,
+};
+
+// Jest Extended Matchers: https://github.com/jest-community/jest-extended
+type JestExtendedMatchersType = {
+ /**
+ * Note: Currently unimplemented
+ * Passing assertion
+ *
+ * @param {String} message
+ */
+ // pass(message: string): void;
+
+ /**
+ * Note: Currently unimplemented
+ * Failing assertion
+ *
+ * @param {String} message
+ */
+ // fail(message: string): void;
+
+ /**
+ * Use .toBeEmpty when checking if a String '', Array [] or Object {} is empty.
+ */
+ toBeEmpty(): void,
+
+ /**
+ * Use .toBeOneOf when checking if a value is a member of a given Array.
+ * @param {Array.<*>} members
+ */
+ toBeOneOf(members: any[]): void,
+
+ /**
+ * Use `.toBeNil` when checking a value is `null` or `undefined`.
+ */
+ toBeNil(): void,
+
+ /**
+ * Use `.toSatisfy` when you want to use a custom matcher by supplying a predicate function that returns a `Boolean`.
+ * @param {Function} predicate
+ */
+ toSatisfy(predicate: (n: any) => boolean): void,
+
+ /**
+ * Use `.toBeArray` when checking if a value is an `Array`.
+ */
+ toBeArray(): void,
+
+ /**
+ * Use `.toBeArrayOfSize` when checking if a value is an `Array` of size x.
+ * @param {Number} x
+ */
+ toBeArrayOfSize(x: number): void,
+
+ /**
+ * Use `.toIncludeAllMembers` when checking if an `Array` contains all of the same members of a given set.
+ * @param {Array.<*>} members
+ */
+ toIncludeAllMembers(members: any[]): void,
+
+ /**
+ * Use `.toIncludeAnyMembers` when checking if an `Array` contains any of the members of a given set.
+ * @param {Array.<*>} members
+ */
+ toIncludeAnyMembers(members: any[]): void,
+
+ /**
+ * Use `.toSatisfyAll` when you want to use a custom matcher by supplying a predicate function that returns a `Boolean` for all values in an array.
+ * @param {Function} predicate
+ */
+ toSatisfyAll(predicate: (n: any) => boolean): void,
+
+ /**
+ * Use `.toBeBoolean` when checking if a value is a `Boolean`.
+ */
+ toBeBoolean(): void,
+
+ /**
+ * Use `.toBeTrue` when checking a value is equal (===) to `true`.
+ */
+ toBeTrue(): void,
+
+ /**
+ * Use `.toBeFalse` when checking a value is equal (===) to `false`.
+ */
+ toBeFalse(): void,
+
+ /**
+ * Use .toBeDate when checking if a value is a Date.
+ */
+ toBeDate(): void,
+
+ /**
+ * Use `.toBeFunction` when checking if a value is a `Function`.
+ */
+ toBeFunction(): void,
+
+ /**
+ * Use `.toHaveBeenCalledBefore` when checking if a `Mock` was called before another `Mock`.
+ *
+ * Note: Required Jest version >22
+ * Note: Your mock functions will have to be asynchronous to cause the timestamps inside of Jest to occur in a differentJS event loop, otherwise the mock timestamps will all be the same
+ *
+ * @param {Mock} mock
+ */
+ toHaveBeenCalledBefore(mock: JestMockFn<any, any>): void,
+
+ /**
+ * Use `.toBeNumber` when checking if a value is a `Number`.
+ */
+ toBeNumber(): void,
+
+ /**
+ * Use `.toBeNaN` when checking a value is `NaN`.
+ */
+ toBeNaN(): void,
+
+ /**
+ * Use `.toBeFinite` when checking if a value is a `Number`, not `NaN` or `Infinity`.
+ */
+ toBeFinite(): void,
+
+ /**
+ * Use `.toBePositive` when checking if a value is a positive `Number`.
+ */
+ toBePositive(): void,
+
+ /**
+ * Use `.toBeNegative` when checking if a value is a negative `Number`.
+ */
+ toBeNegative(): void,
+
+ /**
+ * Use `.toBeEven` when checking if a value is an even `Number`.
+ */
+ toBeEven(): void,
+
+ /**
+ * Use `.toBeOdd` when checking if a value is an odd `Number`.
+ */
+ toBeOdd(): void,
+
+ /**
+ * Use `.toBeWithin` when checking if a number is in between the given bounds of: start (inclusive) and end (exclusive).
+ *
+ * @param {Number} start
+ * @param {Number} end
+ */
+ toBeWithin(start: number, end: number): void,
+
+ /**
+ * Use `.toBeObject` when checking if a value is an `Object`.
+ */
+ toBeObject(): void,
+
+ /**
+ * Use `.toContainKey` when checking if an object contains the provided key.
+ *
+ * @param {String} key
+ */
+ toContainKey(key: string): void,
+
+ /**
+ * Use `.toContainKeys` when checking if an object has all of the provided keys.
+ *
+ * @param {Array.<String>} keys
+ */
+ toContainKeys(keys: string[]): void,
+
+ /**
+ * Use `.toContainAllKeys` when checking if an object only contains all of the provided keys.
+ *
+ * @param {Array.<String>} keys
+ */
+ toContainAllKeys(keys: string[]): void,
+
+ /**
+ * Use `.toContainAnyKeys` when checking if an object contains at least one of the provided keys.
+ *
+ * @param {Array.<String>} keys
+ */
+ toContainAnyKeys(keys: string[]): void,
+
+ /**
+ * Use `.toContainValue` when checking if an object contains the provided value.
+ *
+ * @param {*} value
+ */
+ toContainValue(value: any): void,
+
+ /**
+ * Use `.toContainValues` when checking if an object contains all of the provided values.
+ *
+ * @param {Array.<*>} values
+ */
+ toContainValues(values: any[]): void,
+
+ /**
+ * Use `.toContainAllValues` when checking if an object only contains all of the provided values.
+ *
+ * @param {Array.<*>} values
+ */
+ toContainAllValues(values: any[]): void,
+
+ /**
+ * Use `.toContainAnyValues` when checking if an object contains at least one of the provided values.
+ *
+ * @param {Array.<*>} values
+ */
+ toContainAnyValues(values: any[]): void,
+
+ /**
+ * Use `.toContainEntry` when checking if an object contains the provided entry.
+ *
+ * @param {Array.<String, String>} entry
+ */
+ toContainEntry(entry: [string, string]): void,
+
+ /**
+ * Use `.toContainEntries` when checking if an object contains all of the provided entries.
+ *
+ * @param {Array.<Array.<String, String>>} entries
+ */
+ toContainEntries(entries: [string, string][]): void,
+
+ /**
+ * Use `.toContainAllEntries` when checking if an object only contains all of the provided entries.
+ *
+ * @param {Array.<Array.<String, String>>} entries
+ */
+ toContainAllEntries(entries: [string, string][]): void,
+
+ /**
+ * Use `.toContainAnyEntries` when checking if an object contains at least one of the provided entries.
+ *
+ * @param {Array.<Array.<String, String>>} entries
+ */
+ toContainAnyEntries(entries: [string, string][]): void,
+
+ /**
+ * Use `.toBeExtensible` when checking if an object is extensible.
+ */
+ toBeExtensible(): void,
+
+ /**
+ * Use `.toBeFrozen` when checking if an object is frozen.
+ */
+ toBeFrozen(): void,
+
+ /**
+ * Use `.toBeSealed` when checking if an object is sealed.
+ */
+ toBeSealed(): void,
+
+ /**
+ * Use `.toBeString` when checking if a value is a `String`.
+ */
+ toBeString(): void,
+
+ /**
+ * Use `.toEqualCaseInsensitive` when checking if a string is equal (===) to another ignoring the casing of both strings.
+ *
+ * @param {String} string
+ */
+ toEqualCaseInsensitive(string: string): void,
+
+ /**
+ * Use `.toStartWith` when checking if a `String` starts with a given `String` prefix.
+ *
+ * @param {String} prefix
+ */
+ toStartWith(prefix: string): void,
+
+ /**
+ * Use `.toEndWith` when checking if a `String` ends with a given `String` suffix.
+ *
+ * @param {String} suffix
+ */
+ toEndWith(suffix: string): void,
+
+ /**
+ * Use `.toInclude` when checking if a `String` includes the given `String` substring.
+ *
+ * @param {String} substring
+ */
+ toInclude(substring: string): void,
+
+ /**
+ * Use `.toIncludeRepeated` when checking if a `String` includes the given `String` substring the correct number of times.
+ *
+ * @param {String} substring
+ * @param {Number} times
+ */
+ toIncludeRepeated(substring: string, times: number): void,
+
+ /**
+ * Use `.toIncludeMultiple` when checking if a `String` includes all of the given substrings.
+ *
+ * @param {Array.<String>} substring
+ */
+ toIncludeMultiple(substring: string[]): void,
+};
+
+interface JestExpectType {
+ not: JestExpectType &
+ EnzymeMatchersType &
+ DomTestingLibraryType &
+ JestJQueryMatchersType &
+ JestStyledComponentsMatchersType &
+ JestExtendedMatchersType;
/**
* If you have a mock function, you can use .lastCalledWith to test what
* arguments it was last called with.
*/
- lastCalledWith(...args: Array<any>): void,
+ lastCalledWith(...args: Array<any>): void;
/**
* toBe just checks that a value is what you expect. It uses === to check
* strict equality.
*/
- toBe(value: any): void,
- /**
- * Use .toHaveBeenCalled to ensure that a mock function got called.
- */
- toBeCalled(): void,
+ toBe(value: any): void;
/**
* Use .toBeCalledWith to ensure that a mock function was called with
* specific arguments.
*/
- toBeCalledWith(...args: Array<any>): void,
+ toBeCalledWith(...args: Array<any>): void;
/**
* Using exact equality with floating point numbers is a bad idea. Rounding
* means that intuitive things fail.
*/
- toBeCloseTo(num: number, delta: any): void,
+ toBeCloseTo(num: number, delta: any): void;
/**
* Use .toBeDefined to check that a variable is not undefined.
*/
- toBeDefined(): void,
+ toBeDefined(): void;
/**
* Use .toBeFalsy when you don't care what a value is, you just want to
* ensure a value is false in a boolean context.
*/
- toBeFalsy(): void,
+ toBeFalsy(): void;
/**
* To compare floating point numbers, you can use toBeGreaterThan.
*/
- toBeGreaterThan(number: number): void,
+ toBeGreaterThan(number: number): void;
/**
* To compare floating point numbers, you can use toBeGreaterThanOrEqual.
*/
- toBeGreaterThanOrEqual(number: number): void,
+ toBeGreaterThanOrEqual(number: number): void;
/**
* To compare floating point numbers, you can use toBeLessThan.
*/
- toBeLessThan(number: number): void,
+ toBeLessThan(number: number): void;
/**
* To compare floating point numbers, you can use toBeLessThanOrEqual.
*/
- toBeLessThanOrEqual(number: number): void,
+ toBeLessThanOrEqual(number: number): void;
/**
* Use .toBeInstanceOf(Class) to check that an object is an instance of a
* class.
*/
- toBeInstanceOf(cls: Class<*>): void,
+ toBeInstanceOf(cls: Class<*>): void;
/**
* .toBeNull() is the same as .toBe(null) but the error messages are a bit
* nicer.
*/
- toBeNull(): void,
+ toBeNull(): void;
/**
* Use .toBeTruthy when you don't care what a value is, you just want to
* ensure a value is true in a boolean context.
*/
- toBeTruthy(): void,
+ toBeTruthy(): void;
/**
* Use .toBeUndefined to check that a variable is undefined.
*/
- toBeUndefined(): void,
+ toBeUndefined(): void;
/**
* Use .toContain when you want to check that an item is in a list. For
* testing the items in the list, this uses ===, a strict equality check.
*/
- toContain(item: any): void,
+ toContain(item: any): void;
/**
* Use .toContainEqual when you want to check that an item is in a list. For
* testing the items in the list, this matcher recursively checks the
* equality of all fields, rather than checking for object identity.
*/
- toContainEqual(item: any): void,
+ toContainEqual(item: any): void;
/**
* Use .toEqual when you want to check that two objects have the same value.
* This matcher recursively checks the equality of all fields, rather than
* checking for object identity.
*/
- toEqual(value: any): void,
+ toEqual(value: any): void;
/**
* Use .toHaveBeenCalled to ensure that a mock function got called.
*/
- toHaveBeenCalled(): void,
+ toHaveBeenCalled(): void;
+ toBeCalled(): void;
/**
* Use .toHaveBeenCalledTimes to ensure that a mock function got called exact
* number of times.
*/
- toHaveBeenCalledTimes(number: number): void,
+ toHaveBeenCalledTimes(number: number): void;
+ toBeCalledTimes(number: number): void;
+ /**
+ *
+ */
+ toHaveBeenNthCalledWith(nthCall: number, ...args: Array<any>): void;
+ nthCalledWith(nthCall: number, ...args: Array<any>): void;
+ /**
+ *
+ */
+ toHaveReturned(): void;
+ toReturn(): void;
+ /**
+ *
+ */
+ toHaveReturnedTimes(number: number): void;
+ toReturnTimes(number: number): void;
+ /**
+ *
+ */
+ toHaveReturnedWith(value: any): void;
+ toReturnWith(value: any): void;
+ /**
+ *
+ */
+ toHaveLastReturnedWith(value: any): void;
+ lastReturnedWith(value: any): void;
+ /**
+ *
+ */
+ toHaveNthReturnedWith(nthCall: number, value: any): void;
+ nthReturnedWith(nthCall: number, value: any): void;
/**
* Use .toHaveBeenCalledWith to ensure that a mock function was called with
* specific arguments.
*/
- toHaveBeenCalledWith(...args: Array<any>): void,
+ toHaveBeenCalledWith(...args: Array<any>): void;
+ toBeCalledWith(...args: Array<any>): void;
/**
* Use .toHaveBeenLastCalledWith to ensure that a mock function was last called
* with specific arguments.
*/
- toHaveBeenLastCalledWith(...args: Array<any>): void,
+ toHaveBeenLastCalledWith(...args: Array<any>): void;
+ lastCalledWith(...args: Array<any>): void;
/**
* Check that an object has a .length property and it is set to a certain
* numeric value.
*/
- toHaveLength(number: number): void,
+ toHaveLength(number: number): void;
/**
*
*/
- toHaveProperty(propPath: string, value?: any): void,
+ toHaveProperty(propPath: string, value?: any): void;
/**
* Use .toMatch to check that a string matches a regular expression or string.
*/
- toMatch(regexpOrString: RegExp | string): void,
+ toMatch(regexpOrString: RegExp | string): void;
/**
* Use .toMatchObject to check that a javascript object matches a subset of the properties of an object.
*/
- toMatchObject(object: Object): void,
+ toMatchObject(object: Object | Array<Object>): void;
+ /**
+ * Use .toStrictEqual to check that a javascript object matches a subset of the properties of an object.
+ */
+ toStrictEqual(value: any): void;
+ /**
+ * This ensures that an Object matches the most recent snapshot.
+ */
+ toMatchSnapshot(
+ propertyMatchers?: {[key: string]: JestAsymmetricEqualityType},
+ name?: string,
+ ): void;
/**
- * This ensures that a React component matches the most recent snapshot.
+ * This ensures that an Object matches the most recent snapshot.
*/
- toMatchSnapshot(name?: string): void,
+ toMatchSnapshot(name: string): void;
+
+ toMatchInlineSnapshot(snapshot?: string): void;
+ toMatchInlineSnapshot(
+ propertyMatchers?: {[key: string]: JestAsymmetricEqualityType},
+ snapshot?: string,
+ ): void;
/**
* Use .toThrow to test that a function throws when it is called.
* If you want to test that a specific error gets thrown, you can provide an
@@ -320,14 +732,15 @@
*
* Alias: .toThrowError
*/
- toThrow(message?: string | Error | RegExp): void,
- toThrowError(message?: string | Error | RegExp): void,
+ toThrow(message?: string | Error | Class<Error> | RegExp): void;
+ toThrowError(message?: string | Error | Class<Error> | RegExp): void;
/**
* Use .toThrowErrorMatchingSnapshot to test that a function throws a error
* matching the most recent snapshot when it is called.
*/
- toThrowErrorMatchingSnapshot(): void,
-};
+ toThrowErrorMatchingSnapshot(): void;
+ toThrowErrorMatchingInlineSnapshot(snapshot?: string): void;
+}
type JestObjectType = {
/**
@@ -408,6 +821,16 @@
options?: Object,
): JestObjectType,
/**
+ * Returns the actual module instead of a mock, bypassing all checks on
+ * whether the module should receive a mock implementation or not.
+ */
+ requireActual(moduleName: string): any,
+ /**
+ * Returns a mock module instead of the actual module, bypassing all checks
+ * on whether the module should be required normally or not.
+ */
+ requireMock(moduleName: string): any,
+ /**
* Resets the module registry - the cache of all required modules. This is
* useful to isolate modules where local state might conflict between tests.
*/
@@ -470,19 +893,16 @@
* Creates a mock function similar to jest.fn but also tracks calls to
* object[methodName].
*/
- spyOn(object: Object, methodName: string): JestMockFn<any, any>,
+ spyOn(
+ object: Object,
+ methodName: string,
+ accessType?: 'get' | 'set',
+ ): JestMockFn<any, any>,
/**
* Set the default timeout interval for tests and before/after hooks in milliseconds.
* Note: The default timeout interval is 5 seconds if this method is not called.
*/
setTimeout(timeout: number): JestObjectType,
-
- // These methods are added separately and not a part of flow-typed OSS
- // version of this file. They were added in jest@21.0.0.alpha-2 which is not
- // yet publicly released yet.
- // TODO T21262347 Add them to OSS version of flow-typed
- requireActual(module: string): any,
- requireMock(module: string): any,
};
type JestSpyType = {
@@ -515,17 +935,29 @@
/**
* Creates a block that groups together several related tests in one "test suite"
*/
- (name: string, fn: () => void): void,
+ (name: JestTestName, fn: () => void): void,
/**
* Only run this describe block
*/
- only(name: string, fn: () => void): void,
+ only(name: JestTestName, fn: () => void): void,
/**
* Skip running this describe block
*/
- skip(name: string, fn: () => void): void,
+ skip(name: JestTestName, fn: () => void): void,
+
+ /**
+ * each runs this test against array of argument arrays per each run
+ *
+ * @param {table} table of Test
+ */
+ each(
+ table: Array<Array<mixed> | mixed>,
+ ): (
+ name: JestTestName,
+ fn?: (...args: Array<any>) => ?Promise<mixed>,
+ ) => void,
};
/** An individual test unit */
@@ -533,54 +965,83 @@
/**
* An individual test unit
*
- * @param {string} Name of Test
+ * @param {JestTestName} Name of Test
* @param {Function} Test
* @param {number} Timeout for the test, in milliseconds.
*/
(
- name: string,
+ name: JestTestName,
fn?: (done: () => void) => ?Promise<mixed>,
timeout?: number,
): void,
/**
+ * each runs this test against array of argument arrays per each run
+ *
+ * @param {table} table of Test
+ */
+ each(
+ table: Array<Array<mixed> | mixed>,
+ ): (
+ name: JestTestName,
+ fn?: (...args: Array<any>) => ?Promise<mixed>,
+ ) => void,
+ /**
* Only run this test
*
- * @param {string} Name of Test
+ * @param {JestTestName} Name of Test
* @param {Function} Test
* @param {number} Timeout for the test, in milliseconds.
*/
only(
- name: string,
+ name: JestTestName,
fn?: (done: () => void) => ?Promise<mixed>,
timeout?: number,
- ): void,
+ ): {
+ each(
+ table: Array<Array<mixed> | mixed>,
+ ): (
+ name: JestTestName,
+ fn?: (...args: Array<any>) => ?Promise<mixed>,
+ ) => void,
+ },
/**
* Skip running this test
*
- * @param {string} Name of Test
+ * @param {JestTestName} Name of Test
* @param {Function} Test
* @param {number} Timeout for the test, in milliseconds.
*/
skip(
- name: string,
+ name: JestTestName,
fn?: (done: () => void) => ?Promise<mixed>,
timeout?: number,
): void,
/**
* Run the test concurrently
*
- * @param {string} Name of Test
+ * @param {JestTestName} Name of Test
* @param {Function} Test
* @param {number} Timeout for the test, in milliseconds.
*/
concurrent(
- name: string,
+ name: JestTestName,
fn?: (done: () => void) => ?Promise<mixed>,
timeout?: number,
): void,
+ /**
+ * each runs this test against array of argument arrays per each run
+ *
+ * @param {table} table of Test
+ */
+ each(
+ table: Array<Array<mixed> | mixed>,
+ ): (
+ name: JestTestName,
+ fn?: (...args: Array<any>) => ?Promise<mixed>,
+ ) => void,
};
declare function fit(
- name: string,
+ name: JestTestName,
fn: (done: () => void) => ?Promise<mixed>,
timeout?: number,
): void;
@@ -595,27 +1056,86 @@
/** A disabled individual test */
declare var xtest: typeof it;
+type JestPrettyFormatColors = {
+ comment: {close: string, open: string},
+ content: {close: string, open: string},
+ prop: {close: string, open: string},
+ tag: {close: string, open: string},
+ value: {close: string, open: string},
+};
+
+type JestPrettyFormatIndent = string => string;
+type JestPrettyFormatRefs = Array<any>;
+type JestPrettyFormatPrint = any => string;
+type JestPrettyFormatStringOrNull = string | null;
+
+type JestPrettyFormatOptions = {|
+ callToJSON: boolean,
+ edgeSpacing: string,
+ escapeRegex: boolean,
+ highlight: boolean,
+ indent: number,
+ maxDepth: number,
+ min: boolean,
+ plugins: JestPrettyFormatPlugins,
+ printFunctionName: boolean,
+ spacing: string,
+ theme: {|
+ comment: string,
+ content: string,
+ prop: string,
+ tag: string,
+ value: string,
+ |},
+|};
+
+type JestPrettyFormatPlugin = {
+ print: (
+ val: any,
+ serialize: JestPrettyFormatPrint,
+ indent: JestPrettyFormatIndent,
+ opts: JestPrettyFormatOptions,
+ colors: JestPrettyFormatColors,
+ ) => string,
+ test: any => boolean,
+};
+
+type JestPrettyFormatPlugins = Array<JestPrettyFormatPlugin>;
+
/** The expect function is used every time you want to test a value */
declare var expect: {
/** The object that you want to make assertions against */
- (value: any): JestExpectType & JestPromiseType & EnzymeMatchersType,
+ (
+ value: any,
+ ): JestExpectType &
+ JestPromiseType &
+ EnzymeMatchersType &
+ DomTestingLibraryType &
+ JestJQueryMatchersType &
+ JestStyledComponentsMatchersType &
+ JestExtendedMatchersType,
+
/** Add additional Jasmine matchers to Jest's roster */
extend(matchers: {[name: string]: JestMatcher}): void,
/** Add a module that formats application-specific data structures. */
- addSnapshotSerializer(serializer: (input: Object) => string): void,
+ addSnapshotSerializer(pluginModule: JestPrettyFormatPlugin): void,
assertions(expectedAssertions: number): void,
hasAssertions(): void,
any(value: mixed): JestAsymmetricEqualityType,
- anything(): void,
- arrayContaining(value: Array<mixed>): void,
- objectContaining(value: Object): void,
+ anything(): any,
+ arrayContaining(value: Array<mixed>): Array<mixed>,
+ objectContaining(value: Object): Object,
/** Matches any received string that contains the exact expected string. */
- stringContaining(value: string): void,
- stringMatching(value: string | RegExp): void,
+ stringContaining(value: string): string,
+ stringMatching(value: string | RegExp): string,
+ not: {
+ arrayContaining: (value: $ReadOnlyArray<mixed>) => Array<mixed>,
+ objectContaining: (value: {}) => Object,
+ stringContaining: (value: string) => string,
+ stringMatching: (value: string | RegExp) => string,
+ },
};
-declare function fail(message?: string): void;
-
// TODO handle return type
// http://jasmine.github.io/2.4/introduction.html#section-Spies
declare function spyOn(value: mixed, method: string): Object;
@@ -624,20 +1144,20 @@
declare var jest: JestObjectType;
/**
- * The global Jamine object, this is generally not exposed as the public API,
+ * The global Jasmine object, this is generally not exposed as the public API,
* using features inside here could break in later versions of Jest.
*/
declare var jasmine: {
DEFAULT_TIMEOUT_INTERVAL: number,
any(value: mixed): JestAsymmetricEqualityType,
- anything(): void,
- arrayContaining(value: Array<mixed>): void,
+ anything(): any,
+ arrayContaining(value: Array<mixed>): Array<mixed>,
clock(): JestClockType,
createSpy(name: string): JestSpyType,
createSpyObj(
baseName: string,
methodNames: Array<string>,
): {[methodName: string]: JestSpyType},
- objectContaining(value: Object): void,
- stringMatching(value: string): void,
+ objectContaining(value: Object): Object,
+ stringMatching(value: string): string,
};

flow/Map.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

flow/Position.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

flow/Promise.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

flow/prop-types.js

@@ -1,45 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @flow strict
- * @nolint
- * @format
- */
-
-// TODO (bvaughn) Remove this file once flowtype/flow-typed/pull/773 is merged
-
-type $npm$propTypes$ReactPropsCheckType = (
- props: any,
- propName: string,
- componentName: string,
- href?: string,
-) => ?Error;
-
-declare module 'prop-types' {
- declare var array: React$PropType$Primitive<Array<any>>;
- declare var bool: React$PropType$Primitive<boolean>;
- declare var func: React$PropType$Primitive<Function>;
- declare var number: React$PropType$Primitive<number>;
- declare var object: React$PropType$Primitive<Object>;
- declare var string: React$PropType$Primitive<string>;
- declare var any: React$PropType$Primitive<any>;
- declare var arrayOf: React$PropType$ArrayOf;
- declare var element: React$PropType$Primitive<any>; /* TODO */
- declare var instanceOf: React$PropType$InstanceOf;
- declare var node: React$PropType$Primitive<any>; /* TODO */
- declare var objectOf: React$PropType$ObjectOf;
- declare var oneOf: React$PropType$OneOf;
- declare var oneOfType: React$PropType$OneOfType;
- declare var shape: React$PropType$Shape;
-
- declare function checkPropTypes<V>(
- propTypes: $Subtype<{[_: $Keys<V>]: $npm$propTypes$ReactPropsCheckType}>,
- values: V,
- location: string,
- componentName: string,
- getStack: ?() => ?string,
- ): void;
-}

flow/Set.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

flow/Stringish.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

.flowconfig

@@ -3,7 +3,7 @@
.*/*[.]android.js
; Ignore templates for 'react-native init'
-.*/local-cli/templates/.*
+<PROJECT_ROOT>/template/.*
; Ignore the Dangerfile
<PROJECT_ROOT>/bots/dangerfile.js
@@ -22,21 +22,18 @@
; Ignore polyfills
.*/Libraries/polyfills/.*
-; Ignore metro
-.*/node_modules/metro/.*
-.*/node_modules/metro-config/.*
-
; These should not be required directly
-; require from fbjs/lib instead: require('fbjs/lib/invariant')
-.*/node_modules/invariant/.*
+; require from fbjs/lib instead: require('fbjs/lib/warning')
.*/node_modules/warning/.*
+[untyped]
+.*/node_modules/@react-native-community/cli/.*/.*
+
[include]
[libs]
Libraries/react-native/react-native-interface.js
flow/
-flow-github/
[options]
emoji=true
@@ -60,6 +57,7 @@
module.system.haste.paths.whitelist=<PROJECT_ROOT>/Libraries/.*
module.system.haste.paths.whitelist=<PROJECT_ROOT>/RNTester/.*
module.system.haste.paths.whitelist=<PROJECT_ROOT>/IntegrationTests/.*
+module.system.haste.paths.blacklist=<PROJECT_ROOT>/Libraries/react-native/react-native-implementation.js
module.system.haste.paths.blacklist=<PROJECT_ROOT>/Libraries/Animated/src/polyfills/.*
munge_underscores=true
@@ -71,25 +69,24 @@
suppress_type=$FlowFixMeProps
suppress_type=$FlowFixMeState
-suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*[react_native\\(_ios\\)?_oss|react_native\\(_ios\\)?_fb][a-z,_]*\\)?)\\)
-suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*[react_native\\(_ios\\)?_oss|react_native\\(_ios\\)?_fb][a-z,_]*\\)?)\\)?:? #[0-9]+
+suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)
+suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
[lints]
-all=warn
-unnecessary-optional-chain=off
-
-# There is an ESLint rule for this
-unclear-type=off
-
-sketchy-null=off
sketchy-null-number=warn
sketchy-null-mixed=warn
-
-# This is noisy for now. We *do* still want to warn on importing types
-# from untyped files, which is covered by untyped-type-import
-untyped-import=off
+sketchy-number=warn
+untyped-type-import=warn
+nonstrict-import=warn
+deprecated-type=warn
+unsafe-getters-setters=warn
+inexact-spread=warn
+unnecessary-invariant=warn
+deprecated-call-syntax=warn
+signature-verification-failure=warn
+deprecated-utility=error
[strict]
deprecated-type
@@ -101,4 +98,4 @@
untyped-type-import
[version]
-^0.78.0
+^0.92.0

flow-github/metro.js

@@ -1,65 +0,0 @@
-/**
- * Copyright (c) 2017-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @flow
- * @format
- */
-
-declare module 'metro' {
- declare module.exports: any;
-}
-
-declare module 'metro/src/HmrServer' {
- declare module.exports: any;
-}
-
-declare module 'metro/src/lib/attachWebsocketServer' {
- declare module.exports: any;
-}
-
-declare module 'metro/src/lib/bundle-modules/HMRClient' {
- declare module.exports: any;
-}
-
-declare module 'metro/src/lib/TerminalReporter' {
- declare module.exports: any;
-}
-
-declare module 'metro/src/Bundler' {
- declare module.exports: any;
-}
-
-declare module 'metro/src/DeltaBundler' {
- declare module.exports: any;
-}
-
-declare module 'metro/src/ModuleGraph/types.flow.js' {
- declare module.exports: any;
-}
-
-declare module 'metro/src/lib/getMaxWorkers' {
- declare module.exports: any;
-}
-
-declare module 'metro/src/lib/createModuleIdFactory' {
- declare module.exports: any;
-}
-
-declare module 'metro/src/shared/types.flow' {
- declare module.exports: any;
-}
-
-declare module 'metro/src/lib/reporting' {
- declare module.exports: any;
-}
-
-declare module 'metro/src/Server' {
- declare module.exports: any;
-}
-
-declare module 'metro/src/ModuleGraph/worker/collectDependencies' {
- declare module.exports: any;
-}

jest/assetFileTransformer.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2017-present, Facebook, Inc.
+ * 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.

jest/hasteImpl.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.
@@ -11,9 +11,35 @@
'use strict';
const path = require('path');
-const findPlugins = require('../local-cli/core/findPlugins');
-const plugins = findPlugins([path.resolve(__dirname, '../../../')]);
+const REACT_NATIVE_CI = process.cwd() === path.resolve(__dirname, '..');
+
+let pluginsPath;
+
+if (REACT_NATIVE_CI) {
+ pluginsPath = '..';
+} else {
+ pluginsPath = '../../../';
+}
+
+function getPlugins() {
+ try {
+ // @todo do not rely on private files
+ const findPlugins = require('@react-native-community/cli/build/core/findPlugins')
+ .default;
+
+ return findPlugins(path.resolve(__dirname, pluginsPath));
+ } catch (e) {
+ return {
+ haste: {
+ providesModuleNodeModules: [],
+ platforms: [],
+ },
+ };
+ }
+}
+
+const plugins = getPlugins();
// Detect out-of-tree platforms and add them to the whitelists
const pluginRoots /*: Array<

jest/mockComponent.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -10,7 +10,7 @@
'use strict';
module.exports = (moduleName, instanceMethods) => {
- const RealComponent = require.requireActual(moduleName);
+ const RealComponent = jest.requireActual(moduleName);
const React = require('react');
const SuperClass =

jest/MockNativeMethods.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

jest/preprocessor.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -23,18 +23,16 @@
const createCacheKeyFunction = require('fbjs-scripts/jest/createCacheKeyFunction');
const generate = require('@babel/generator').default;
-const nodeFiles = RegExp(
+const nodeFiles = new RegExp(
[
- '/local-cli/',
- '/metro(?:-[^/]*)?/', // metro, metro-core, metro-source-map, metro-etc
+ '/metro(?:-[^/]*)?/', // metro, metro-core, metro-source-map, metro-etc.
].join('|'),
);
const nodeOptions = babelRegisterOnly.config([nodeFiles]);
babelRegisterOnly([]);
-/* $FlowFixMe(site=react_native_oss) */
-const transformer = require('metro/src/reactNativeTransformer');
+const transformer = require('metro-react-native-babel-transformer');
module.exports = {
process(src /*: string */, file /*: string */) {
if (nodeFiles.test(file)) {
@@ -59,6 +57,7 @@
minify: false,
platform: '',
projectRoot: '',
+ publicPath: '/assets',
retainLines: true,
sourceType: 'unambiguous', // b7 required. detects module vs script mode
},
@@ -120,7 +119,7 @@
getCacheKey: createCacheKeyFunction([
__filename,
- require.resolve('metro/src/reactNativeTransformer'),
+ require.resolve('metro-react-native-babel-transformer'),
require.resolve('@babel/core/package.json'),
]),
};

jest/renderer.js

@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @emails oncall+react_native
+ * @flow
+ */
+
+'use strict';
+
+const React = require('React');
+
+const TestRenderer = require('react-test-renderer');
+const ShallowRenderer = require('react-test-renderer/shallow');
+
+const renderer = new ShallowRenderer();
+
+export const shallow = (Component: React.Element<any>) => {
+ const Wrapper = (): React.Element<any> => Component;
+
+ return renderer.render(<Wrapper />);
+};
+
+export const create = (Component: React.Element<any>) => {
+ return TestRenderer.create(Component);
+};

jest/setup.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,19 +9,17 @@
'use strict';
-const MockNativeMethods = require.requireActual('./MockNativeMethods');
-const mockComponent = require.requireActual('./mockComponent');
+const MockNativeMethods = jest.requireActual('./MockNativeMethods');
+const mockComponent = jest.requireActual('./mockComponent');
-require.requireActual('../Libraries/polyfills/babelHelpers.js');
-require.requireActual('../Libraries/polyfills/Object.es7.js');
-require.requireActual('../Libraries/polyfills/error-guard');
+jest.requireActual('../Libraries/polyfills/babelHelpers.js');
+jest.requireActual('../Libraries/polyfills/Object.es7.js');
+jest.requireActual('../Libraries/polyfills/error-guard');
global.__DEV__ = true;
-global.Promise = require.requireActual('promise');
-global.regeneratorRuntime = require.requireActual(
- 'regenerator-runtime/runtime',
-);
+global.Promise = jest.requireActual('promise');
+global.regeneratorRuntime = jest.requireActual('regenerator-runtime/runtime');
global.requestAnimationFrame = function(callback) {
return setTimeout(callback, 0);
@@ -42,12 +40,12 @@
.mock('TextInput', () => mockComponent('TextInput'))
.mock('Modal', () => mockComponent('Modal'))
.mock('View', () => mockComponent('View', MockNativeMethods))
- .mock('RefreshControl', () => require.requireMock('RefreshControlMock'))
- .mock('ScrollView', () => require.requireMock('ScrollViewMock'))
+ .mock('RefreshControl', () => jest.requireMock('RefreshControlMock'))
+ .mock('ScrollView', () => jest.requireMock('ScrollViewMock'))
.mock('ActivityIndicator', () => mockComponent('ActivityIndicator'))
- .mock('ListView', () => require.requireMock('ListViewMock'))
+ .mock('ListView', () => jest.requireMock('ListViewMock'))
.mock('ListViewDataSource', () => {
- const DataSource = require.requireActual('ListViewDataSource');
+ const DataSource = jest.requireActual('ListViewDataSource');
DataSource.prototype.toJSON = function() {
function ListViewDataSource(dataBlob) {
this.items = 0;
@@ -68,9 +66,7 @@
return DataSource;
})
.mock('AnimatedImplementation', () => {
- const AnimatedImplementation = require.requireActual(
- 'AnimatedImplementation',
- );
+ const AnimatedImplementation = jest.requireActual('AnimatedImplementation');
const oldCreate = AnimatedImplementation.createAnimatedComponent;
AnimatedImplementation.createAnimatedComponent = function(Component) {
const Wrapped = oldCreate(Component);
@@ -80,7 +76,7 @@
return AnimatedImplementation;
})
.mock('ReactNative', () => {
- const ReactNative = require.requireActual('ReactNative');
+ const ReactNative = jest.requireActual('ReactNative');
const NativeMethodsMixin =
ReactNative.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
.NativeMethodsMixin;
@@ -119,6 +115,12 @@
BuildInfo: {
appVersion: '0',
buildVersion: '0',
+ getConstants() {
+ return {
+ appVersion: '0',
+ buildVersion: '0',
+ };
+ },
},
Clipboard: {
setString: jest.fn(),
@@ -175,6 +177,7 @@
addEventListener: jest.fn(),
getInitialURL: jest.fn(() => Promise.resolve()),
removeEventListener: jest.fn(),
+ sendIntent: jest.fn(),
},
LocationObserver: {
getCurrentPosition: jest.fn(),
@@ -253,6 +256,7 @@
createView: jest.fn(),
dispatchViewManagerCommand: jest.fn(),
focus: jest.fn(),
+ getViewManagerConfig: jest.fn(),
setChildren: jest.fn(),
manageChildren: jest.fn(),
updateView: jest.fn(),

jest/__tests__/hasteImpl-test.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.
@@ -11,9 +11,23 @@
'use strict';
const path = require('path');
+const fs = require('fs');
const {getHasteName} = require('../hasteImpl');
+// RNPM currently does not support plugins when using Yarn Plug 'n Play
+const testIfNotPnP = fs.existsSync(
+ path.join(
+ __dirname,
+ '../..',
+ 'node_modules',
+ 'react-native-dummy',
+ 'package.json',
+ ),
+)
+ ? test
+ : test.skip;
+
function getPath(...parts) {
return path.join(__dirname, '..', '..', ...parts);
}
@@ -46,6 +60,24 @@
}
});
+testIfNotPnP(
+ 'returns the correct haste name for a file with an out-of-tree platform suffix',
+ () => {
+ for (const platform of ['dummy']) {
+ expect(
+ getHasteName(
+ getPath(
+ 'Libraries',
+ 'Components',
+ 'AccessibilityInfo',
+ `AccessibilityInfo.${platform}.js`,
+ ),
+ ),
+ ).toEqual('AccessibilityInfo');
+ }
+ },
+);
+
it('returns the correct haste name for a file with a flow suffix', () => {
expect(
getHasteName(

jest-preset.js

@@ -0,0 +1,36 @@
+/**
+ * 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
+ */
+
+'use strict';
+
+const dir = __dirname;
+
+module.exports = {
+ haste: {
+ defaultPlatform: 'ios',
+ platforms: ['android', 'ios', 'native'],
+ hasteImplModulePath: require.resolve('./jest/hasteImpl.js'),
+ providesModuleNodeModules: ['react-native'],
+ },
+ moduleNameMapper: {
+ '^React$': require.resolve('react'),
+ },
+ modulePathIgnorePatterns: [`${dir}/Libraries/react-native/`],
+ transform: {
+ '^.+\\.(js|ts|tsx)$': 'babel-jest',
+ '^.+\\.(bmp|gif|jpg|jpeg|mp4|png|psd|svg|webp)$': require.resolve(
+ './jest/assetFileTransformer.js',
+ ),
+ },
+ transformIgnorePatterns: [
+ 'node_modules/(?!(jest-)?react-native|react-clone-referenced-element|@react-native-community)',
+ ],
+ setupFiles: [require.resolve('./jest/setup.js')],
+ testEnvironment: 'node',
+};

jest-preset.json

@@ -1,27 +0,0 @@
-{
- "haste": {
- "defaultPlatform": "ios",
- "platforms": ["android", "ios", "native"],
- "hasteImplModulePath": "<rootDir>/node_modules/react-native/jest/hasteImpl.js",
- "providesModuleNodeModules": [
- "react-native"
- ]
- },
- "moduleNameMapper": {
- "^React$": "<rootDir>/node_modules/react"
- },
- "modulePathIgnorePatterns": [
- "<rootDir>/node_modules/react-native/Libraries/react-native/"
- ],
- "transform": {
- "^.+\\.js$": "babel-jest",
- "^.+\\.(bmp|gif|jpg|jpeg|mp4|png|psd|svg|webp)$": "<rootDir>/node_modules/react-native/jest/assetFileTransformer.js"
- },
- "transformIgnorePatterns": [
- "node_modules/(?!(jest-)?react-native|react-clone-referenced-element)"
- ],
- "setupFiles": [
- "<rootDir>/node_modules/react-native/jest/setup.js"
- ],
- "testEnvironment": "node"
-}

lib/deepDiffer.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.

lib/deepFreezeAndThrowOnMutationInDev.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.

lib/flattenStyle.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.

lib/InitializeJavaScriptAppEngine.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.

lib/RCTEventEmitter.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.

lib/TextInputState.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.

lib/UIManager.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.

lib/UIManagerStatTracker.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.

lib/View.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.

Libraries/ActionSheetIOS/ActionSheetIOS.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,7 +11,7 @@
const RCTActionSheetManager = require('NativeModules').ActionSheetManager;
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
const processColor = require('processColor');
/**
@@ -27,7 +27,7 @@
*
* - `options` (array of strings) - a list of button titles (required)
* - `cancelButtonIndex` (int) - index of cancel button in `options`
- * - `destructiveButtonIndex` (int) - index of destructive button in `options`
+ * - `destructiveButtonIndex` (int or array of ints) - index or indices of destructive buttons in `options`
* - `title` (string) - a title to show above the action sheet
* - `message` (string) - a message to show below the title
*

Libraries/ActionSheetIOS/RCTActionSheetManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ActionSheetIOS/RCTActionSheetManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -32,20 +32,21 @@
return dispatch_get_main_queue();
}
-/*
- * The `anchor` option takes a view to set as the anchor for the share
- * popup to point to, on iPads running iOS 8. If it is not passed, it
- * defaults to centering the share popup on screen without any arrows.
- */
-- (CGRect)sourceRectInView:(UIView *)sourceView
+- (void)presentViewController:(UIViewController *)alertController
+ onParentViewController:(UIViewController *)parentViewController
anchorViewTag:(NSNumber *)anchorViewTag
{
+ alertController.modalPresentationStyle = UIModalPresentationPopover;
+ UIView *sourceView = parentViewController.view;
+
if (anchorViewTag) {
- UIView *anchorView = [self.bridge.uiManager viewForReactTag:anchorViewTag];
- return [anchorView convertRect:anchorView.bounds toView:sourceView];
+ sourceView = [self.bridge.uiManager viewForReactTag:anchorViewTag];
} else {
- return (CGRect){sourceView.center, {1, 1}};
+ alertController.popoverPresentationController.permittedArrowDirections = 0;
}
+ alertController.popoverPresentationController.sourceView = sourceView;
+ alertController.popoverPresentationController.sourceRect = sourceView.bounds;
+ [parentViewController presentViewController:alertController animated:YES completion:nil];
}
RCT_EXPORT_METHOD(showActionSheetWithOptions:(NSDictionary *)options
@@ -63,8 +64,14 @@
NSString *title = [RCTConvert NSString:options[@"title"]];
NSString *message = [RCTConvert NSString:options[@"message"]];
NSArray<NSString *> *buttons = [RCTConvert NSStringArray:options[@"options"]];
- NSInteger destructiveButtonIndex = options[@"destructiveButtonIndex"] ? [RCTConvert NSInteger:options[@"destructiveButtonIndex"]] : -1;
NSInteger cancelButtonIndex = options[@"cancelButtonIndex"] ? [RCTConvert NSInteger:options[@"cancelButtonIndex"]] : -1;
+ NSArray<NSNumber *> *destructiveButtonIndices;
+ if ([options[@"destructiveButtonIndex"] isKindOfClass:[NSArray class]]) {
+ destructiveButtonIndices = [RCTConvert NSArray:options[@"destructiveButtonIndex"]];
+ } else {
+ NSNumber *destructiveButtonIndex = options[@"destructiveButtonIndex"] ? [RCTConvert NSNumber:options[@"destructiveButtonIndex"]] : @-1;
+ destructiveButtonIndices = @[destructiveButtonIndex];
+ }
UIViewController *controller = RCTPresentedViewController();
@@ -79,8 +86,6 @@
* defaults to centering the share popup on screen without any arrows.
*/
NSNumber *anchorViewTag = [RCTConvert NSNumber:options[@"anchor"]];
- UIView *sourceView = controller.view;
- CGRect sourceRect = [self sourceRectInView:sourceView anchorViewTag:anchorViewTag];
UIAlertController *alertController =
[UIAlertController alertControllerWithTitle:title
@@ -90,7 +95,7 @@
NSInteger index = 0;
for (NSString *option in buttons) {
UIAlertActionStyle style = UIAlertActionStyleDefault;
- if (index == destructiveButtonIndex) {
+ if ([destructiveButtonIndices containsObject:@(index)]) {
style = UIAlertActionStyleDestructive;
} else if (index == cancelButtonIndex) {
style = UIAlertActionStyleCancel;
@@ -106,15 +111,8 @@
index++;
}
- alertController.modalPresentationStyle = UIModalPresentationPopover;
- alertController.popoverPresentationController.sourceView = sourceView;
- alertController.popoverPresentationController.sourceRect = sourceRect;
- if (!anchorViewTag) {
- alertController.popoverPresentationController.permittedArrowDirections = 0;
- }
- [controller presentViewController:alertController animated:YES completion:nil];
-
alertController.view.tintColor = [RCTConvert UIColor:options[@"tintColor"]];
+ [self presentViewController:alertController onParentViewController:controller anchorViewTag:anchorViewTag];
}
RCT_EXPORT_METHOD(showShareActionSheetWithOptions:(NSDictionary *)options
@@ -173,17 +171,10 @@
}
};
- shareController.modalPresentationStyle = UIModalPresentationPopover;
NSNumber *anchorViewTag = [RCTConvert NSNumber:options[@"anchor"]];
- if (!anchorViewTag) {
- shareController.popoverPresentationController.permittedArrowDirections = 0;
- }
- shareController.popoverPresentationController.sourceView = controller.view;
- shareController.popoverPresentationController.sourceRect = [self sourceRectInView:controller.view anchorViewTag:anchorViewTag];
-
- [controller presentViewController:shareController animated:YES completion:nil];
-
shareController.view.tintColor = [RCTConvert UIColor:options[@"tintColor"]];
+
+ [self presentViewController:shareController onParentViewController:controller anchorViewTag:anchorViewTag];
}
@end

Libraries/Alert/AlertIOS.js

@@ -1,181 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow
- * @jsdoc
- */
-
-'use strict';
-
-const RCTAlertManager = require('NativeModules').AlertManager;
-
-/**
- * An Alert button type
- */
-export type AlertType = $Enum<{
- /**
- * Default alert with no inputs
- */
- default: string,
- /**
- * Plain text input alert
- */
- 'plain-text': string,
- /**
- * Secure text input alert
- */
- 'secure-text': string,
- /**
- * Login and password alert
- */
- 'login-password': string,
-}>;
-
-/**
- * An Alert button style
- */
-export type AlertButtonStyle = $Enum<{
- /**
- * Default button style
- */
- default: string,
- /**
- * Cancel button style
- */
- cancel: string,
- /**
- * Destructive button style
- */
- destructive: string,
-}>;
-
-/**
- * Array or buttons
- * @typedef {Array} ButtonsArray
- * @property {string=} text Button label
- * @property {Function=} onPress Callback function when button pressed
- * @property {AlertButtonStyle=} style Button style
- */
-export type ButtonsArray = Array<{
- /**
- * Button label
- */
- text?: string,
- /**
- * Callback function when button pressed
- */
- onPress?: ?Function,
- /**
- * Button style
- */
- style?: AlertButtonStyle,
-}>;
-
-/**
- * Use `AlertIOS` to display an alert dialog with a message or to create a prompt for user input on iOS. If you don't need to prompt for user input, we recommend using `Alert.alert() for cross-platform support.
- *
- * See http://facebook.github.io/react-native/docs/alertios.html
- */
-class AlertIOS {
- /**
- * Create and display a popup alert.
- *
- * See http://facebook.github.io/react-native/docs/alertios.html#alert
- */
- static alert(
- title: ?string,
- message?: ?string,
- callbackOrButtons?: ?((() => void) | ButtonsArray),
- type?: AlertType,
- ): void {
- if (typeof type !== 'undefined') {
- console.warn(
- 'AlertIOS.alert() with a 4th "type" parameter is deprecated and will be removed. Use AlertIOS.prompt() instead.',
- );
- this.prompt(title, message, callbackOrButtons, type);
- return;
- }
- this.prompt(title, message, callbackOrButtons, 'default');
- }
-
- /**
- * Create and display a prompt to enter some text.
- *
- * See http://facebook.github.io/react-native/docs/alertios.html#prompt
- */
- static prompt(
- title: ?string,
- message?: ?string,
- callbackOrButtons?: ?(((text: string) => void) | ButtonsArray),
- type?: ?AlertType = 'plain-text',
- defaultValue?: string,
- keyboardType?: string,
- ): void {
- if (typeof type === 'function') {
- console.warn(
- 'You passed a callback function as the "type" argument to AlertIOS.prompt(). React Native is ' +
- 'assuming you want to use the deprecated AlertIOS.prompt(title, defaultValue, buttons, callback) ' +
- 'signature. The current signature is AlertIOS.prompt(title, message, callbackOrButtons, type, defaultValue, ' +
- 'keyboardType) and the old syntax will be removed in a future version.',
- );
-
- const callback = type;
- RCTAlertManager.alertWithArgs(
- {
- title: title || '',
- type: 'plain-text',
- defaultValue: message,
- },
- (id, value) => {
- callback(value);
- },
- );
- return;
- }
-
- let callbacks = [];
- const buttons = [];
- let cancelButtonKey;
- let destructiveButtonKey;
- if (typeof callbackOrButtons === 'function') {
- callbacks = [callbackOrButtons];
- } else if (callbackOrButtons instanceof Array) {
- callbackOrButtons.forEach((btn, index) => {
- callbacks[index] = btn.onPress;
- if (btn.style === 'cancel') {
- cancelButtonKey = String(index);
- } else if (btn.style === 'destructive') {
- destructiveButtonKey = String(index);
- }
- if (btn.text || index < (callbackOrButtons || []).length - 1) {
- const btnDef = {};
- btnDef[index] = btn.text || '';
- buttons.push(btnDef);
- }
- });
- }
-
- RCTAlertManager.alertWithArgs(
- {
- title: title || '',
- message: message || undefined,
- buttons,
- type: type || undefined,
- defaultValue,
- cancelButtonKey,
- destructiveButtonKey,
- keyboardType,
- },
- (id, value) => {
- const cb = callbacks[id];
- cb && cb(value);
- },
- );
- }
-}
-
-module.exports = AlertIOS;

Libraries/Alert/Alert.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,12 +10,10 @@
'use strict';
-const AlertIOS = require('AlertIOS');
const NativeModules = require('NativeModules');
+const RCTAlertManager = NativeModules.AlertManager;
const Platform = require('Platform');
-import type {AlertType, AlertButtonStyle} from 'AlertIOS';
-
export type Buttons = Array<{
text?: string,
onPress?: ?Function,
@@ -27,36 +25,139 @@
onDismiss?: ?Function,
};
+type AlertType = $Enum<{
+ default: string,
+ 'plain-text': string,
+ 'secure-text': string,
+ 'login-password': string,
+}>;
+
+export type AlertButtonStyle = $Enum<{
+ default: string,
+ cancel: string,
+ destructive: string,
+}>;
+
/**
* Launches an alert dialog with the specified title and message.
*
* See http://facebook.github.io/react-native/docs/alert.html
*/
class Alert {
- /**
- * Launches an alert dialog with the specified title and message.
- *
- * See http://facebook.github.io/react-native/docs/alert.html#alert
- */
static alert(
title: ?string,
message?: ?string,
buttons?: Buttons,
options?: Options,
- type?: AlertType,
): void {
if (Platform.OS === 'ios') {
- if (typeof type !== 'undefined') {
+ AlertIOS.alert(title, message, buttons);
+ } else if (Platform.OS === 'android') {
+ AlertAndroid.alert(title, message, buttons, options);
+ }
+ }
+
+ static prompt(
+ title: ?string,
+ message?: ?string,
+ callbackOrButtons?: ?(((text: string) => void) | Buttons),
+ type?: ?AlertType = 'plain-text',
+ defaultValue?: string,
+ keyboardType?: string,
+ ): void {
+ if (Platform.OS === 'ios') {
+ AlertIOS.prompt(
+ title,
+ message,
+ callbackOrButtons,
+ type,
+ defaultValue,
+ keyboardType,
+ );
+ }
+ }
+}
+
+/**
+ * Wrapper around the iOS native module.
+ */
+class AlertIOS {
+ static alert(
+ title: ?string,
+ message?: ?string,
+ callbackOrButtons?: ?((() => void) | Buttons),
+ ): void {
+ this.prompt(title, message, callbackOrButtons, 'default');
+ }
+
+ static prompt(
+ title: ?string,
+ message?: ?string,
+ callbackOrButtons?: ?(((text: string) => void) | Buttons),
+ type?: ?AlertType = 'plain-text',
+ defaultValue?: string,
+ keyboardType?: string,
+ ): void {
+ if (typeof type === 'function') {
console.warn(
- 'Alert.alert() with a 5th "type" parameter is deprecated and will be removed. Use AlertIOS.prompt() instead.',
+ 'You passed a callback function as the "type" argument to Alert.prompt(). React Native is ' +
+ 'assuming you want to use the deprecated Alert.prompt(title, defaultValue, buttons, callback) ' +
+ 'signature. The current signature is Alert.prompt(title, message, callbackOrButtons, type, defaultValue, ' +
+ 'keyboardType) and the old syntax will be removed in a future version.',
+ );
+
+ const callback = type;
+ RCTAlertManager.alertWithArgs(
+ {
+ title: title || '',
+ type: 'plain-text',
+ defaultValue: message,
+ },
+ (id, value) => {
+ callback(value);
+ },
);
- AlertIOS.alert(title, message, buttons, type);
return;
}
- AlertIOS.alert(title, message, buttons);
- } else if (Platform.OS === 'android') {
- AlertAndroid.alert(title, message, buttons, options);
+
+ let callbacks = [];
+ const buttons = [];
+ let cancelButtonKey;
+ let destructiveButtonKey;
+ if (typeof callbackOrButtons === 'function') {
+ callbacks = [callbackOrButtons];
+ } else if (Array.isArray(callbackOrButtons)) {
+ callbackOrButtons.forEach((btn, index) => {
+ callbacks[index] = btn.onPress;
+ if (btn.style === 'cancel') {
+ cancelButtonKey = String(index);
+ } else if (btn.style === 'destructive') {
+ destructiveButtonKey = String(index);
+ }
+ if (btn.text || index < (callbackOrButtons || []).length - 1) {
+ const btnDef = {};
+ btnDef[index] = btn.text || '';
+ buttons.push(btnDef);
+ }
+ });
}
+
+ RCTAlertManager.alertWithArgs(
+ {
+ title: title || '',
+ message: message || undefined,
+ buttons,
+ type: type || undefined,
+ defaultValue,
+ cancelButtonKey,
+ destructiveButtonKey,
+ keyboardType,
+ },
+ (id, value) => {
+ const cb = callbacks[id];
+ cb && cb(value);
+ },
+ );
}
}

Libraries/Alert/RCTAlertManager.android.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

Libraries/Alert/RCTAlertManager.ios.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Animated/examples/style.css

@@ -1,3 +1,10 @@
+/**
+ * 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.
+ */
+
html, h1, h2 {
font-family: 'Roboto', sans-serif;
font-weight: 300;

Libraries/Animated/release/.gitignore

@@ -0,0 +1,3 @@
+/lib/
+/dist/
+/node_modules/

Libraries/Animated/release/gulpfile.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

Libraries/Animated/src/AnimatedEvent.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -13,7 +13,7 @@
const NativeAnimatedHelper = require('./NativeAnimatedHelper');
const ReactNative = require('ReactNative');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
const {shouldUseNativeDriver} = require('./NativeAnimatedHelper');
export type Mapping = {[key: string]: Mapping} | AnimatedValue;
@@ -158,7 +158,7 @@
};
}
- _callListeners(...args) {
+ _callListeners(...args: any) {
this._listeners.forEach(listener => listener(...args));
}

Libraries/Animated/src/AnimatedImplementation.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -514,6 +514,8 @@
* easy to build and maintain. `Animated` focuses on declarative relationships
* between inputs and outputs, with configurable transforms in between, and
* simple `start`/`stop` methods to control time-based animation execution.
+ * If additional transforms are added, be sure to include them in
+ * AnimatedMock.js as well.
*
* See http://facebook.github.io/react-native/docs/animated.html
*/
@@ -685,5 +687,10 @@
forkEvent,
unforkEvent,
+ /**
+ * Expose Event class, so it can be used as a type for type checkers.
+ */
+ Event: AnimatedEvent,
+
__PropsOnlyForTests: AnimatedProps,
};

Libraries/Animated/src/Animated.js

@@ -1,29 +1,39 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
*
- * @flow strict-local
+ * @flow
* @format
*/
'use strict';
-const AnimatedImplementation = require('AnimatedImplementation');
-const FlatList = require('FlatList');
-const Image = require('Image');
-const ScrollView = require('ScrollView');
-const SectionList = require('SectionList');
-const Text = require('Text');
-const View = require('View');
+import Platform from 'Platform';
+
+const AnimatedImplementation = Platform.isTesting
+ ? require('AnimatedMock')
+ : require('AnimatedImplementation');
module.exports = {
+ get FlatList() {
+ return require('AnimatedFlatList');
+ },
+ get Image() {
+ return require('AnimatedImage');
+ },
+ get ScrollView() {
+ return require('AnimatedScrollView');
+ },
+ get SectionList() {
+ return require('AnimatedSectionList');
+ },
+ get Text() {
+ return require('AnimatedText');
+ },
+ get View() {
+ return require('AnimatedView');
+ },
...AnimatedImplementation,
- View: AnimatedImplementation.createAnimatedComponent(View),
- Text: AnimatedImplementation.createAnimatedComponent(Text),
- Image: AnimatedImplementation.createAnimatedComponent(Image),
- ScrollView: AnimatedImplementation.createAnimatedComponent(ScrollView),
- FlatList: AnimatedImplementation.createAnimatedComponent(FlatList),
- SectionList: AnimatedImplementation.createAnimatedComponent(SectionList),
};

Libraries/Animated/src/AnimatedMock.js

@@ -0,0 +1,138 @@
+/**
+ * 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.
+ *
+ * @flow
+ * @format
+ */
+'use strict';
+
+const {AnimatedEvent, attachNativeEvent} = require('./AnimatedEvent');
+const AnimatedImplementation = require('AnimatedImplementation');
+const AnimatedInterpolation = require('./nodes/AnimatedInterpolation');
+const AnimatedNode = require('./nodes/AnimatedNode');
+const AnimatedProps = require('./nodes/AnimatedProps');
+const AnimatedValue = require('./nodes/AnimatedValue');
+const AnimatedValueXY = require('./nodes/AnimatedValueXY');
+
+const createAnimatedComponent = require('./createAnimatedComponent');
+
+import type {EndCallback} from './animations/Animation';
+import type {TimingAnimationConfig} from './animations/TimingAnimation';
+import type {DecayAnimationConfig} from './animations/DecayAnimation';
+import type {SpringAnimationConfig} from './animations/SpringAnimation';
+import type {Mapping, EventConfig} from './AnimatedEvent';
+
+/**
+ * Animations are a source of flakiness in snapshot testing. This mock replaces
+ * animation functions from AnimatedImplementation with empty animations for
+ * predictability in tests.
+ */
+type CompositeAnimation = {
+ start: (callback?: ?EndCallback) => void,
+ stop: () => void,
+ reset: () => void,
+ _startNativeLoop: (iterations?: number) => void,
+ _isUsingNativeDriver: () => boolean,
+};
+
+const emptyAnimation = {
+ start: () => {},
+ stop: () => {},
+ reset: () => {},
+ _startNativeLoop: () => {},
+ _isUsingNativeDriver: () => {
+ return false;
+ },
+};
+
+const spring = function(
+ value: AnimatedValue | AnimatedValueXY,
+ config: SpringAnimationConfig,
+): CompositeAnimation {
+ return emptyAnimation;
+};
+
+const timing = function(
+ value: AnimatedValue | AnimatedValueXY,
+ config: TimingAnimationConfig,
+): CompositeAnimation {
+ return emptyAnimation;
+};
+
+const decay = function(
+ value: AnimatedValue | AnimatedValueXY,
+ config: DecayAnimationConfig,
+): CompositeAnimation {
+ return emptyAnimation;
+};
+
+const sequence = function(
+ animations: Array<CompositeAnimation>,
+): CompositeAnimation {
+ return emptyAnimation;
+};
+
+type ParallelConfig = {
+ stopTogether?: boolean,
+};
+const parallel = function(
+ animations: Array<CompositeAnimation>,
+ config?: ?ParallelConfig,
+): CompositeAnimation {
+ return emptyAnimation;
+};
+
+const delay = function(time: number): CompositeAnimation {
+ return emptyAnimation;
+};
+
+const stagger = function(
+ time: number,
+ animations: Array<CompositeAnimation>,
+): CompositeAnimation {
+ return emptyAnimation;
+};
+
+type LoopAnimationConfig = {iterations: number};
+
+const loop = function(
+ animation: CompositeAnimation,
+ {iterations = -1}: LoopAnimationConfig = {},
+): CompositeAnimation {
+ return emptyAnimation;
+};
+
+const event = function(argMapping: Array<?Mapping>, config?: EventConfig): any {
+ return null;
+};
+
+module.exports = {
+ Value: AnimatedValue,
+ ValueXY: AnimatedValueXY,
+ Interpolation: AnimatedInterpolation,
+ Node: AnimatedNode,
+ decay,
+ timing,
+ spring,
+ add: AnimatedImplementation.add,
+ subtract: AnimatedImplementation.subtract,
+ divide: AnimatedImplementation.divide,
+ multiply: AnimatedImplementation.multiply,
+ modulo: AnimatedImplementation.modulo,
+ diffClamp: AnimatedImplementation.diffClamp,
+ delay,
+ sequence,
+ parallel,
+ stagger,
+ loop,
+ event,
+ createAnimatedComponent,
+ attachNativeEvent,
+ forkEvent: AnimatedImplementation.forkEvent,
+ unforkEvent: AnimatedImplementation.unforkEvent,
+ Event: AnimatedEvent,
+ __PropsOnlyForTests: AnimatedProps,
+};

Libraries/Animated/src/AnimatedWeb.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Animated/src/animations/Animation.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Animated/src/animations/DecayAnimation.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Animated/src/animations/SpringAnimation.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -14,7 +14,7 @@
const Animation = require('./Animation');
const SpringConfig = require('../SpringConfig');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
const {shouldUseNativeDriver} = require('../NativeAnimatedHelper');
import type {AnimationConfig, EndCallback} from './Animation';

Libraries/Animated/src/animations/TimingAnimation.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Animated/src/bezier.js

@@ -1,8 +1,13 @@
/**
+ * 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.
+ *
* BezierEasing - use bezier curve for transition easing function
* https://github.com/gre/bezier-easing
*
- * @flow
+ * @flow strict
* @format
* @copyright 2014-2015 Gaëtan Renaudeau. MIT License.
*/
@@ -40,10 +45,12 @@
return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1);
}
-function binarySubdivide(aX, aA, aB, mX1, mX2) {
+function binarySubdivide(aX, _aA, _aB, mX1, mX2) {
let currentX,
currentT,
- i = 0;
+ i = 0,
+ aA = _aA,
+ aB = _aB;
do {
currentT = aA + (aB - aA) / 2.0;
currentX = calcBezier(currentT, mX1, mX2) - aX;
@@ -59,7 +66,8 @@
return currentT;
}
-function newtonRaphsonIterate(aX, aGuessT, mX1, mX2) {
+function newtonRaphsonIterate(aX, _aGuessT, mX1, mX2) {
+ let aGuessT = _aGuessT;
for (let i = 0; i < NEWTON_ITERATIONS; ++i) {
const currentSlope = getSlope(aGuessT, mX1, mX2);
if (currentSlope === 0.0) {
@@ -77,7 +85,7 @@
mX2: number,
mY2: number,
) {
- if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) {
+ if (!(mX1 >= 0 && mX1 <= 1 && mX2 >= 0 && mX2 <= 1)) {
throw new Error('bezier x values must be in [0, 1] range');
}

Libraries/Animated/src/components/AnimatedFlatList.js

@@ -0,0 +1,17 @@
+/**
+ * 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.
+ *
+ * @flow strict-local
+ * @format
+ */
+
+'use strict';
+
+const FlatList = require('FlatList');
+
+const createAnimatedComponent = require('createAnimatedComponent');
+
+module.exports = createAnimatedComponent(FlatList);

Libraries/Animated/src/components/AnimatedImage.js

@@ -0,0 +1,17 @@
+/**
+ * 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.
+ *
+ * @flow strict-local
+ * @format
+ */
+
+'use strict';
+
+const Image = require('Image');
+
+const createAnimatedComponent = require('createAnimatedComponent');
+
+module.exports = createAnimatedComponent(Image);

Libraries/Animated/src/components/AnimatedScrollView.js

@@ -0,0 +1,17 @@
+/**
+ * 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.
+ *
+ * @flow strict-local
+ * @format
+ */
+
+'use strict';
+
+const ScrollView = require('ScrollView');
+
+const createAnimatedComponent = require('createAnimatedComponent');
+
+module.exports = createAnimatedComponent(ScrollView);

Libraries/Animated/src/components/AnimatedSectionList.js

@@ -0,0 +1,17 @@
+/**
+ * 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.
+ *
+ * @flow strict-local
+ * @format
+ */
+
+'use strict';
+
+const SectionList = require('SectionList');
+
+const createAnimatedComponent = require('createAnimatedComponent');
+
+module.exports = createAnimatedComponent(SectionList);

Libraries/Animated/src/components/AnimatedText.js

@@ -0,0 +1,17 @@
+/**
+ * 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.
+ *
+ * @flow strict-local
+ * @format
+ */
+
+'use strict';
+
+const Text = require('Text');
+
+const createAnimatedComponent = require('createAnimatedComponent');
+
+module.exports = createAnimatedComponent(Text);

Libraries/Animated/src/components/AnimatedView.js

@@ -0,0 +1,17 @@
+/**
+ * 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.
+ *
+ * @flow strict-local
+ * @format
+ */
+
+'use strict';
+
+const View = require('View');
+
+const createAnimatedComponent = require('createAnimatedComponent');
+
+module.exports = createAnimatedComponent(View);

Libraries/Animated/src/createAnimatedComponent.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -12,9 +12,9 @@
const {AnimatedEvent} = require('./AnimatedEvent');
const AnimatedProps = require('./nodes/AnimatedProps');
const React = require('React');
-const ViewStylePropTypes = require('ViewStylePropTypes');
+const DeprecatedViewStylePropTypes = require('DeprecatedViewStylePropTypes');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
function createAnimatedComponent(Component: any): any {
invariant(
@@ -30,13 +30,11 @@
_prevComponent: any;
_propsAnimated: AnimatedProps;
_eventDetachers: Array<Function> = [];
- _setComponentRef: Function;
static __skipSetNativeProps_FOR_TESTS_ONLY = false;
constructor(props: Object) {
super(props);
- this._setComponentRef = this._setComponentRef.bind(this);
}
componentWillUnmount() {
@@ -164,10 +162,10 @@
);
}
- _setComponentRef(c) {
+ _setComponentRef = c => {
this._prevComponent = this._component;
this._component = c;
- }
+ };
// A third party library can use getNode()
// to get the node reference of the decorated component
@@ -184,7 +182,7 @@
return;
}
- for (const key in ViewStylePropTypes) {
+ for (const key in DeprecatedViewStylePropTypes) {
if (!propTypes[key] && props[key] !== undefined) {
console.warn(
'You are setting the style `{ ' +

Libraries/Animated/src/Easing.js

@@ -1,11 +1,11 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
- * @flow
+ * @flow strict
*/
'use strict';
@@ -175,10 +175,7 @@
*
* - http://tiny.cc/back_default (s = 1.70158, default)
*/
- static back(s: number): (t: number) => number {
- if (s === undefined) {
- s = 1.70158;
- }
+ static back(s: number = 1.70158): (t: number) => number {
return t => t * t * ((s + 1) * t - s);
}
@@ -193,17 +190,17 @@
}
if (t < 2 / 2.75) {
- t -= 1.5 / 2.75;
- return 7.5625 * t * t + 0.75;
+ const t2 = t - 1.5 / 2.75;
+ return 7.5625 * t2 * t2 + 0.75;
}
if (t < 2.5 / 2.75) {
- t -= 2.25 / 2.75;
- return 7.5625 * t * t + 0.9375;
+ const t2 = t - 2.25 / 2.75;
+ return 7.5625 * t2 * t2 + 0.9375;
}
- t -= 2.625 / 2.75;
- return 7.5625 * t * t + 0.984375;
+ const t2 = t - 2.625 / 2.75;
+ return 7.5625 * t2 * t2 + 0.984375;
}
/**

Libraries/Animated/src/NativeAnimatedHelper.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -12,7 +12,7 @@
const NativeAnimatedModule = require('NativeModules').NativeAnimatedModule;
const NativeEventEmitter = require('NativeEventEmitter');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
import type {AnimationConfig} from './animations/Animation';
import type {EventConfig} from './AnimatedEvent';
@@ -153,6 +153,7 @@
borderTopLeftRadius: true,
borderTopRightRadius: true,
borderTopStartRadius: true,
+ elevation: true,
/* ios styles */
shadowOpacity: true,
shadowRadius: true,
@@ -259,6 +260,22 @@
return config.useNativeDriver || false;
}
+function transformDataType(value: any): number {
+ // Change the string type to number type so we can reuse the same logic in
+ // iOS and Android platform
+ if (typeof value !== 'string') {
+ return value;
+ }
+ if (/deg$/.test(value)) {
+ const degrees = parseFloat(value) || 0;
+ const radians = (degrees * Math.PI) / 180.0;
+ return radians;
+ } else {
+ // Assume radians
+ return parseFloat(value) || 0;
+ }
+}
+
module.exports = {
API,
addWhitelistedStyleProp,
@@ -271,6 +288,7 @@
generateNewAnimationId,
assertNativeAnimatedModule,
shouldUseNativeDriver,
+ transformDataType,
get nativeEventEmitter() {
if (!nativeEventEmitter) {
nativeEventEmitter = new NativeEventEmitter(NativeAnimatedModule);

Libraries/Animated/src/nodes/AnimatedAddition.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Animated/src/nodes/AnimatedDiffClamp.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Animated/src/nodes/AnimatedDivision.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Animated/src/nodes/AnimatedInterpolation.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -14,7 +14,7 @@
const AnimatedWithChildren = require('./AnimatedWithChildren');
const NativeAnimatedHelper = require('../NativeAnimatedHelper');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
const normalizeColor = require('normalizeColor');
type ExtrapolateType = 'extend' | 'identity' | 'clamp';
@@ -347,24 +347,7 @@
}
__transformDataType(range: Array<any>) {
- // Change the string array type to number array
- // So we can reuse the same logic in iOS and Android platform
- /* $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. */
- return range.map(function(value) {
- if (typeof value !== 'string') {
- return value;
- }
- if (/deg$/.test(value)) {
- const degrees = parseFloat(value) || 0;
- const radians = (degrees * Math.PI) / 180.0;
- return radians;
- } else {
- // Assume radians
- return parseFloat(value) || 0;
- }
- });
+ return range.map(NativeAnimatedHelper.transformDataType);
}
__getNativeConfig(): any {

Libraries/Animated/src/nodes/AnimatedModulo.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Animated/src/nodes/AnimatedMultiplication.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Animated/src/nodes/AnimatedNode.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,7 +11,7 @@
const NativeAnimatedHelper = require('../NativeAnimatedHelper');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
// Note(vjeux): this would be better as an interface but flow doesn't
// support them yet

Libraries/Animated/src/nodes/AnimatedProps.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -15,7 +15,7 @@
const NativeAnimatedHelper = require('../NativeAnimatedHelper');
const ReactNative = require('ReactNative');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
class AnimatedProps extends AnimatedNode {
_props: Object;

Libraries/Animated/src/nodes/AnimatedStyle.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Animated/src/nodes/AnimatedSubtraction.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Animated/src/nodes/AnimatedTracking.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Animated/src/nodes/AnimatedTransform.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -103,7 +103,7 @@
transConfigs.push({
type: 'static',
property: key,
- value,
+ value: NativeAnimatedHelper.transformDataType(value),
});
}
}

Libraries/Animated/src/nodes/AnimatedValue.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,7 +10,6 @@
'use strict';
const AnimatedInterpolation = require('./AnimatedInterpolation');
-const AnimatedNode = require('./AnimatedNode');
const AnimatedWithChildren = require('./AnimatedWithChildren');
const InteractionManager = require('InteractionManager');
const NativeAnimatedHelper = require('../NativeAnimatedHelper');

Libraries/Animated/src/nodes/AnimatedValueXY.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -12,7 +12,7 @@
const AnimatedValue = require('./AnimatedValue');
const AnimatedWithChildren = require('./AnimatedWithChildren');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
type ValueXYListenerCallback = (value: {x: number, y: number}) => void;

Libraries/Animated/src/nodes/AnimatedWithChildren.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Animated/src/polyfills/flattenStyle.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Animated/src/polyfills/InteractionManager.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Animated/src/polyfills/Set.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Animated/src/SpringConfig.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/AppState/AppState.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -16,7 +16,7 @@
const RCTAppState = NativeModules.AppState;
const logError = require('logError');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
/**
* `AppState` can tell you if the app is in the foreground or background,

Libraries/ART/ARTCGFloatArray.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,7 +7,7 @@
// A little helper to make sure we have the right memory allocation ready for use.
// We assume that we will only this in one place so no reference counting is necessary.
-// Needs to be freed when dealloced.
+// Needs to be freed when deallocated.
// This is fragile since this relies on these values not getting reused. Consider
// wrapping these in an Obj-C class or some ARC hackery to get refcounting.

Libraries/ART/ARTContainer.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/ARTGroup.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/ARTGroup.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/ARTNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/ARTNode.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/ARTRenderable.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/ARTRenderable.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/ARTSerializablePath.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/ARTShape.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/ARTShape.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/ARTSurfaceView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/ARTSurfaceView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/ARTTextFrame.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,7 +9,7 @@
// A little helper to make sure we have a set of lines including width ready for use.
// We assume that we will only this in one place so no reference counting is necessary.
-// Needs to be freed when dealloced.
+// Needs to be freed when deallocated.
// This is fragile since this relies on these values not getting reused. Consider
// wrapping these in an Obj-C class or some ARC hackery to get refcounting.

Libraries/ART/ARTText.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/ARTText.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/Brushes/ARTBrush.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/Brushes/ARTBrush.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/Brushes/ARTLinearGradient.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/Brushes/ARTLinearGradient.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/Brushes/ARTPattern.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/Brushes/ARTPattern.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/Brushes/ARTRadialGradient.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/Brushes/ARTRadialGradient.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/Brushes/ARTSolidColor.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/Brushes/ARTSolidColor.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/RCTConvert+ART.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -15,7 +15,7 @@
@interface RCTConvert (ART)
-+ (CGPathRef)CGPath:(id)json;
++ (CGPathRef)CGPath:(id)json CF_RETURNS_NOT_RETAINED;
+ (CTTextAlignment)CTTextAlignment:(id)json;
+ (ARTTextFrame)ARTTextFrame:(id)json;
+ (ARTCGFloatArray)ARTCGFloatArray:(id)json;
@@ -23,7 +23,7 @@
+ (CGPoint)CGPoint:(id)json offset:(NSUInteger)offset;
+ (CGRect)CGRect:(id)json offset:(NSUInteger)offset;
-+ (CGColorRef)CGColor:(id)json offset:(NSUInteger)offset;
-+ (CGGradientRef)CGGradient:(id)json offset:(NSUInteger)offset;
++ (CGColorRef)CGColor:(id)json offset:(NSUInteger)offset CF_RETURNS_NOT_RETAINED;
++ (CGGradientRef)CGGradient:(id)json offset:(NSUInteger)offset CF_RETURNS_NOT_RETAINED;
@end

Libraries/ART/RCTConvert+ART.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/ReactNativeART.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -19,7 +19,7 @@
const createReactNativeComponentClass = require('createReactNativeComponentClass');
const merge = require('merge');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
// Diff Helpers
@@ -399,7 +399,19 @@
// Note: ART has a notion of width and height on Shape but AFAIK it's a noop in
// ReactART.
-class Shape extends React.Component {
+export type ShapeProps = {|
+ fill?: mixed,
+ stroke?: mixed,
+ strokeCap?: mixed,
+ strokeDash?: mixed,
+ strokeJoin?: mixed,
+ strokeWidth?: mixed,
+ x?: number,
+ y?: number,
+ opacity?: mixed,
+|};
+
+class Shape extends React.Component<ShapeProps> {
render() {
const props = this.props;
const path = props.d || childrenAsString(props.children);

Libraries/ART/ViewManagers/ARTGroupManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/ViewManagers/ARTGroupManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/ViewManagers/ARTNodeManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/ViewManagers/ARTNodeManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/ViewManagers/ARTRenderableManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/ViewManagers/ARTRenderableManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/ViewManagers/ARTShapeManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/ViewManagers/ARTShapeManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/ViewManagers/ARTSurfaceViewManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/ViewManagers/ARTSurfaceViewManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/ViewManagers/ARTTextManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ART/ViewManagers/ARTTextManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/BatchedBridge/BatchedBridge.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/BatchedBridge/MessageQueue.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -14,7 +14,7 @@
const Systrace = require('Systrace');
const deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
const stringifySafe = require('stringifySafe');
export type SpyData = {
@@ -213,11 +213,13 @@
t === 'undefined' ||
t === 'null' ||
t === 'boolean' ||
- t === 'number' ||
t === 'string'
) {
return true;
}
+ if (t === 'number') {
+ return isFinite(val);
+ }
if (t === 'function' || t !== 'object') {
return false;
}
@@ -232,10 +234,25 @@
return true;
};
+ // Replacement allows normally non-JSON-convertible values to be
+ // seen. There is ambiguity with string values, but in context,
+ // it should at least be a strong hint.
+ const replacer = (key, val) => {
+ const t = typeof val;
+ if (t === 'function') {
+ return '<<Function ' + val.name + '>>';
+ } else if (t === 'number' && !isFinite(val)) {
+ return '<<' + val.toString() + '>>';
+ } else {
+ return val;
+ }
+ };
+
+ // Note that JSON.stringify
invariant(
isValidArgument(params),
'%s is not usable as a native method argument',
- params,
+ JSON.stringify(params, replacer),
);
// The params object should not be mutated after being queued

Libraries/BatchedBridge/__mocks__/MessageQueueTestConfig.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

Libraries/BatchedBridge/__mocks__/MessageQueueTestModule.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

Libraries/BatchedBridge/NativeModules.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -12,7 +12,7 @@
const BatchedBridge = require('BatchedBridge');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
import type {ExtendedError} from 'parseErrorStack';
@@ -60,8 +60,17 @@
const methodType = isPromise ? 'promise' : isSync ? 'sync' : 'async';
module[methodName] = genMethod(moduleID, methodID, methodType);
});
+
Object.assign(module, constants);
+ if (module.getConstants == null) {
+ module.getConstants = () => constants;
+ } else {
+ console.warn(
+ `Unable to define method 'getConstants()' on NativeModule '${moduleName}'. NativeModule '${moduleName}' already has a constant or method called 'getConstants'. Please remove it.`,
+ );
+ }
+
if (__DEV__) {
BatchedBridge.createDebugLookup(moduleID, moduleName, methods);
}

Libraries/Blob/Blob.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

Libraries/Blob/BlobManager.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

Libraries/Blob/BlobRegistry.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

Libraries/Blob/BlobTypes.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

Libraries/Blob/File.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -11,7 +11,7 @@
const Blob = require('Blob');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
import type {BlobOptions} from 'BlobTypes';

Libraries/Blob/FileReader.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Blob/__mocks__/BlobModule.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Blob/__mocks__/FileReaderModule.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Blob/RCTBlobManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Blob/RCTBlobManager.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -49,6 +49,11 @@
- (NSDictionary<NSString *, id> *)constantsToExport
{
+ return [self getConstants];
+}
+
+- (NSDictionary<NSString *, id> *)getConstants
+{
return @{
@"BLOB_URI_SCHEME": kBlobURIScheme,
@"BLOB_URI_HOST": [NSNull null],

Libraries/Blob/RCTFileReaderModule.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Blob/RCTFileReaderModule.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Blob/URL.js

@@ -1,11 +1,10 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
- * @flow strict-local
*/
'use strict';
@@ -47,11 +46,71 @@
* </resources>
* ```
*/
-class URL {
- constructor() {
- throw new Error('Creating URL objects is not supported yet.');
+
+// Small subset from whatwg-url: https://github.com/jsdom/whatwg-url/tree/master/lib
+// The reference code bloat comes from Unicode issues with URLs, so those won't work here.
+export class URLSearchParams {
+ _searchParams = [];
+
+ constructor(params: any) {
+ if (typeof params === 'object') {
+ Object.keys(params).forEach(key => this.append(key, params[key]));
+ }
+ }
+
+ append(key: string, value: string) {
+ this._searchParams.push([key, value]);
+ }
+
+ delete(name) {
+ throw new Error('not implemented');
+ }
+
+ get(name) {
+ throw new Error('not implemented');
+ }
+
+ getAll(name) {
+ throw new Error('not implemented');
+ }
+
+ has(name) {
+ throw new Error('not implemented');
+ }
+
+ set(name, value) {
+ throw new Error('not implemented');
+ }
+
+ sort() {
+ throw new Error('not implemented');
}
+ [Symbol.iterator]() {
+ return this._searchParams[Symbol.iterator]();
+ }
+
+ toString() {
+ if (this._searchParams.length === 0) {
+ return '';
+ }
+ const last = this._searchParams.length - 1;
+ return this._searchParams.reduce((acc, curr, index) => {
+ return acc + curr.join('=') + (index === last ? '' : '&');
+ }, '');
+ }
+}
+
+function validateBaseUrl(url: string) {
+ // from this MIT-licensed gist: https://gist.github.com/dperini/729294
+ return /^(?:(?:(?:https?|ftp):)?\/\/)(?:(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(
+ url,
+ );
+}
+
+export class URL {
+ _searchParamsInstance = null;
+
static createObjectURL(blob: Blob) {
if (BLOB_URL_PREFIX === null) {
throw new Error('Cannot create URL for blob!');
@@ -64,6 +123,93 @@
static revokeObjectURL(url: string) {
// Do nothing.
}
-}
-module.exports = URL;
+ constructor(url: string, base: string) {
+ let baseUrl = null;
+ if (base) {
+ if (typeof base === 'string') {
+ baseUrl = base;
+ if (!validateBaseUrl(baseUrl)) {
+ throw new TypeError(`Invalid base URL: ${baseUrl}`);
+ }
+ } else if (typeof base === 'object') {
+ baseUrl = base.toString();
+ }
+ if (baseUrl.endsWith('/') && url.startsWith('/')) {
+ baseUrl = baseUrl.slice(0, baseUrl.length - 1);
+ }
+ if (baseUrl.endsWith(url)) {
+ url = '';
+ }
+ this._url = `${baseUrl}${url}`;
+ } else {
+ this._url = url;
+ if (!this._url.endsWith('/')) {
+ this._url += '/';
+ }
+ }
+ }
+
+ get hash() {
+ throw new Error('not implemented');
+ }
+
+ get host() {
+ throw new Error('not implemented');
+ }
+
+ get hostname() {
+ throw new Error('not implemented');
+ }
+
+ get href(): string {
+ return this.toString();
+ }
+
+ get origin() {
+ throw new Error('not implemented');
+ }
+
+ get password() {
+ throw new Error('not implemented');
+ }
+
+ get pathname() {
+ throw new Error('not implemented');
+ }
+
+ get port() {
+ throw new Error('not implemented');
+ }
+
+ get protocol() {
+ throw new Error('not implemented');
+ }
+
+ get search() {
+ throw new Error('not implemented');
+ }
+
+ get searchParams(): URLSearchParams {
+ if (this._searchParamsInstance == null) {
+ this._searchParamsInstance = new URLSearchParams();
+ }
+ return this._searchParamsInstance;
+ }
+
+ toJSON(): string {
+ return this.toString();
+ }
+
+ toString(): string {
+ if (this._searchParamsInstance === null) {
+ return this._url;
+ }
+ const separator = this._url.indexOf('?') > -1 ? '&' : '?';
+ return this._url + separator + this._searchParamsInstance.toString();
+ }
+
+ get username() {
+ throw new Error('not implemented');
+ }
+}

Libraries/BugReporting/BugReporting.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -11,7 +11,6 @@
'use strict';
const RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
-const Map = require('Map');
const infoLog = require('infoLog');
import type EmitterSubscription from 'EmitterSubscription';

Libraries/BugReporting/dumpReactTree.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

Libraries/BugReporting/getReactData.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -142,8 +142,14 @@
function setIn(obj: Object, path: Array<string | number>, value: any) {
const last = path.pop();
+ /* $FlowFixMe(>=0.88.0 site=react_native_fb) This comment suppresses an error
+ * found when Flow v0.88 was deployed. To see the error, delete this comment
+ * and run Flow. */
const parent = path.reduce((obj_, attr) => (obj_ ? obj_[attr] : null), obj);
if (parent) {
+ /* $FlowFixMe(>=0.88.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.88 was deployed. To see the error, delete this
+ * comment and run Flow. */
parent[last] = value;
}
}

Libraries/CameraRoll/CameraRoll.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -13,8 +13,8 @@
const {checkPropTypes} = PropTypes;
const RCTCameraRollManager = require('NativeModules').CameraRollManager;
-const createStrictShapeTypeChecker = require('createStrictShapeTypeChecker');
-const invariant = require('fbjs/lib/invariant');
+const deprecatedCreateStrictShapeTypeChecker = require('deprecatedCreateStrictShapeTypeChecker');
+const invariant = require('invariant');
const GROUP_TYPES_OPTIONS = {
Album: 'Album',
@@ -32,10 +32,12 @@
Photos: 'Photos',
};
-type GetPhotosParams = {
+export type GroupTypes = $Keys<typeof GROUP_TYPES_OPTIONS>;
+
+export type GetPhotosParams = {
first: number,
after?: string,
- groupTypes?: $Keys<typeof GROUP_TYPES_OPTIONS>,
+ groupTypes?: GroupTypes,
groupName?: string,
assetType?: $Keys<typeof ASSET_TYPE_OPTIONS>,
mimeTypes?: Array<string>,
@@ -44,7 +46,7 @@
/**
* Shape of the param arg for the `getPhotos` function.
*/
-const getPhotosParamChecker = createStrictShapeTypeChecker({
+const getPhotosParamChecker = deprecatedCreateStrictShapeTypeChecker({
/**
* The number of photos wanted in reverse order of the photo application
* (i.e. most recent first for SavedPhotos).
@@ -79,12 +81,12 @@
mimeTypes: PropTypes.arrayOf(PropTypes.string),
});
-type GetPhotosReturn = Promise<{
- edges: Array<{
+export type PhotoIdentifier = {
node: {
type: string,
group_name: string,
image: {
+ filename: string,
uri: string,
height: number,
width: number,
@@ -100,27 +102,30 @@
speed?: number,
},
},
- }>,
+};
+
+export type PhotoIdentifiersPage = {
+ edges: Array<PhotoIdentifier>,
page_info: {
has_next_page: boolean,
start_cursor?: string,
end_cursor?: string,
},
-}>;
+};
/**
* Shape of the return value of the `getPhotos` function.
*/
-const getPhotosReturnChecker = createStrictShapeTypeChecker({
+const getPhotosReturnChecker = deprecatedCreateStrictShapeTypeChecker({
edges: PropTypes.arrayOf(
/* $FlowFixMe(>=0.66.0 site=react_native_fb) This comment suppresses an
* error found when Flow v0.66 was deployed. To see the error delete this
* comment and run Flow. */
- createStrictShapeTypeChecker({
- node: createStrictShapeTypeChecker({
+ deprecatedCreateStrictShapeTypeChecker({
+ node: deprecatedCreateStrictShapeTypeChecker({
type: PropTypes.string.isRequired,
group_name: PropTypes.string.isRequired,
- image: createStrictShapeTypeChecker({
+ image: deprecatedCreateStrictShapeTypeChecker({
uri: PropTypes.string.isRequired,
height: PropTypes.number.isRequired,
width: PropTypes.number.isRequired,
@@ -128,7 +133,7 @@
playableDuration: PropTypes.number.isRequired,
}).isRequired,
timestamp: PropTypes.number.isRequired,
- location: createStrictShapeTypeChecker({
+ location: deprecatedCreateStrictShapeTypeChecker({
latitude: PropTypes.number,
longitude: PropTypes.number,
altitude: PropTypes.number,
@@ -138,7 +143,7 @@
}).isRequired,
}),
).isRequired,
- page_info: createStrictShapeTypeChecker({
+ page_info: deprecatedCreateStrictShapeTypeChecker({
has_next_page: PropTypes.bool.isRequired,
start_cursor: PropTypes.string,
end_cursor: PropTypes.string,
@@ -151,8 +156,8 @@
* See https://facebook.github.io/react-native/docs/cameraroll.html
*/
class CameraRoll {
- static GroupTypesOptions: Object = GROUP_TYPES_OPTIONS;
- static AssetTypeOptions: Object = ASSET_TYPE_OPTIONS;
+ static GroupTypesOptions = GROUP_TYPES_OPTIONS;
+ static AssetTypeOptions = ASSET_TYPE_OPTIONS;
/**
* `CameraRoll.saveImageWithTag()` is deprecated. Use `CameraRoll.saveToCameraRoll()` instead.
@@ -204,7 +209,7 @@
*
* See https://facebook.github.io/react-native/docs/cameraroll.html#getphotos
*/
- static getPhotos(params: GetPhotosParams): GetPhotosReturn {
+ static getPhotos(params: GetPhotosParams): Promise<PhotoIdentifiersPage> {
if (__DEV__) {
checkPropTypes(
{params: getPhotosParamChecker},

Libraries/CameraRoll/ImagePickerIOS.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/CameraRoll/__mocks__/CameraRoll.js

@@ -0,0 +1,14 @@
+/**
+ * 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.
+ *
+ * @flow
+ * @format
+ */
+'use strict';
+
+const CameraRoll = {};
+
+export default CameraRoll;

Libraries/CameraRoll/RCTAssetsLibraryRequestHandler.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -8,17 +8,8 @@
#import <React/RCTBridge.h>
#import <React/RCTURLRequestHandler.h>
-@class ALAssetsLibrary;
+@class PHPhotoLibrary;
@interface RCTAssetsLibraryRequestHandler : NSObject <RCTURLRequestHandler>
@end
-
-@interface RCTBridge (RCTAssetsLibraryImageLoader)
-
-/**
- * The shared asset library instance.
- */
-@property (nonatomic, readonly) ALAssetsLibrary *assetsLibrary;
-
-@end

Libraries/CameraRoll/RCTAssetsLibraryRequestHandler.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,41 +11,26 @@
#import <dlfcn.h>
#import <objc/runtime.h>
-#import <AssetsLibrary/AssetsLibrary.h>
+#import <Photos/Photos.h>
#import <MobileCoreServices/MobileCoreServices.h>
#import <React/RCTBridge.h>
#import <React/RCTUtils.h>
@implementation RCTAssetsLibraryRequestHandler
-{
- ALAssetsLibrary *_assetsLibrary;
-}
RCT_EXPORT_MODULE()
-@synthesize bridge = _bridge;
-static Class _ALAssetsLibrary = nil;
-static void ensureAssetsLibLoaded(void)
-{
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- void * handle = dlopen("/System/Library/Frameworks/AssetsLibrary.framework/AssetsLibrary", RTLD_LAZY);
-#pragma unused(handle)
- _ALAssetsLibrary = objc_getClass("ALAssetsLibrary");
- });
-}
-- (ALAssetsLibrary *)assetsLibrary
-{
- ensureAssetsLibLoaded();
- return _assetsLibrary ?: (_assetsLibrary = [_ALAssetsLibrary new]);
-}
-
#pragma mark - RCTURLRequestHandler
- (BOOL)canHandleRequest:(NSURLRequest *)request
{
- return [request.URL.scheme caseInsensitiveCompare:@"assets-library"] == NSOrderedSame;
+ if (![PHAsset class]) {
+ return NO;
+ }
+
+ return [request.URL.scheme caseInsensitiveCompare:@"assets-library"] == NSOrderedSame
+ || [request.URL.scheme caseInsensitiveCompare:@"ph"] == NSOrderedSame;
}
- (id)sendRequest:(NSURLRequest *)request
@@ -56,55 +41,72 @@
atomic_store(&cancelled, YES);
};
- [[self assetsLibrary] assetForURL:request.URL resultBlock:^(ALAsset *asset) {
- if (atomic_load(&cancelled)) {
- return;
+ if (!request.URL) {
+ NSString *const msg = [NSString stringWithFormat:@"Cannot send request without URL"];
+ [delegate URLRequest:cancellationBlock didCompleteWithError:RCTErrorWithMessage(msg)];
+ return cancellationBlock;
}
- if (asset) {
-
- ALAssetRepresentation *representation = [asset defaultRepresentation];
- NSInteger length = (NSInteger)representation.size;
- CFStringRef MIMEType = UTTypeCopyPreferredTagWithClass((__bridge CFStringRef _Nonnull)(representation.UTI), kUTTagClassMIMEType);
-
- NSURLResponse *response =
- [[NSURLResponse alloc] initWithURL:request.URL
- MIMEType:(__bridge NSString *)(MIMEType)
- expectedContentLength:length
- textEncodingName:nil];
-
- [delegate URLRequest:cancellationBlock didReceiveResponse:response];
-
- NSError *error = nil;
- uint8_t *buffer = (uint8_t *)malloc((size_t)length);
- if ([representation getBytes:buffer
- fromOffset:0
- length:length
- error:&error]) {
-
- NSData *data = [[NSData alloc] initWithBytesNoCopy:buffer
- length:length
- freeWhenDone:YES];
-
- [delegate URLRequest:cancellationBlock didReceiveData:data];
- [delegate URLRequest:cancellationBlock didCompleteWithError:nil];
+ PHFetchResult<PHAsset *> *fetchResult;
+ if ([request.URL.scheme caseInsensitiveCompare:@"ph"] == NSOrderedSame) {
+ // Fetch assets using PHAsset localIdentifier (recommended)
+ NSString *const localIdentifier = [request.URL.absoluteString substringFromIndex:@"ph://".length];
+ fetchResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[localIdentifier] options:nil];
+ } else if ([request.URL.scheme caseInsensitiveCompare:@"assets-library"] == NSOrderedSame) {
+ // This is the older, deprecated way of fetching assets from assets-library
+ // using the "assets-library://" protocol
+ fetchResult = [PHAsset fetchAssetsWithALAssetURLs:@[request.URL] options:nil];
} else {
- free(buffer);
- [delegate URLRequest:cancellationBlock didCompleteWithError:error];
+ NSString *const msg = [NSString stringWithFormat:@"Cannot send request with unknown protocol: %@", request.URL];
+ [delegate URLRequest:cancellationBlock didCompleteWithError:RCTErrorWithMessage(msg)];
+ return cancellationBlock;
}
- } else {
+ if (![fetchResult firstObject]) {
NSString *errorMessage = [NSString stringWithFormat:@"Failed to load asset"
" at URL %@ with no error message.", request.URL];
NSError *error = RCTErrorWithMessage(errorMessage);
[delegate URLRequest:cancellationBlock didCompleteWithError:error];
+ return cancellationBlock;
}
- } failureBlock:^(NSError *loadError) {
+
if (atomic_load(&cancelled)) {
+ return cancellationBlock;
+ }
+
+ PHAsset *const _Nonnull asset = [fetchResult firstObject];
+
+ // By default, allow downloading images from iCloud
+ PHImageRequestOptions *const requestOptions = [PHImageRequestOptions new];
+ requestOptions.networkAccessAllowed = YES;
+
+ [[PHImageManager defaultManager] requestImageDataForAsset:asset
+ options:requestOptions
+ resultHandler:^(NSData * _Nullable imageData,
+ NSString * _Nullable dataUTI,
+ UIImageOrientation orientation,
+ NSDictionary * _Nullable info) {
+ NSError *const error = [info objectForKey:PHImageErrorKey];
+ if (error) {
+ [delegate URLRequest:cancellationBlock didCompleteWithError:error];
return;
}
- [delegate URLRequest:cancellationBlock didCompleteWithError:loadError];
+
+ NSInteger const length = [imageData length];
+ CFStringRef const dataUTIStringRef = (__bridge CFStringRef _Nonnull)(dataUTI);
+ CFStringRef const mimeType = UTTypeCopyPreferredTagWithClass(dataUTIStringRef, kUTTagClassMIMEType);
+
+ NSURLResponse *const response = [[NSURLResponse alloc] initWithURL:request.URL
+ MIMEType:(__bridge NSString *)(mimeType)
+ expectedContentLength:length
+ textEncodingName:nil];
+ CFRelease(mimeType);
+
+ [delegate URLRequest:cancellationBlock didReceiveResponse:response];
+
+ [delegate URLRequest:cancellationBlock didReceiveData:imageData];
+ [delegate URLRequest:cancellationBlock didCompleteWithError:nil];
}];
return cancellationBlock;
@@ -116,12 +118,3 @@
}
@end
-
-@implementation RCTBridge (RCTAssetsLibraryImageLoader)
-
-- (ALAssetsLibrary *)assetsLibrary
-{
- return [[self moduleForClass:[RCTAssetsLibraryRequestHandler class]] assetsLibrary];
-}
-
-@end

Libraries/CameraRoll/RCTCameraRollManager.h

@@ -1,19 +1,18 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
*/
-#import <AssetsLibrary/AssetsLibrary.h>
+#import <Photos/Photos.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTConvert.h>
-@interface RCTConvert (ALAssetGroup)
+@interface RCTConvert (PHFetchOptions)
-+ (ALAssetsGroupType)ALAssetsGroupType:(id)json;
-+ (ALAssetsFilter *)ALAssetsFilter:(id)json;
++ (PHFetchOptions *)PHFetchOptionsFromMediaType:(NSString *)mediaType;
@end

Libraries/CameraRoll/RCTCameraRollManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -13,6 +13,7 @@
#import <Photos/Photos.h>
#import <dlfcn.h>
#import <objc/runtime.h>
+#import <MobileCoreServices/UTType.h>
#import <React/RCTBridge.h>
#import <React/RCTConvert.h>
@@ -22,85 +23,46 @@
#import "RCTAssetsLibraryRequestHandler.h"
-@implementation RCTConvert (ALAssetGroup)
+@implementation RCTConvert (PHAssetCollectionSubtype)
-RCT_ENUM_CONVERTER(ALAssetsGroupType, (@{
+RCT_ENUM_CONVERTER(PHAssetCollectionSubtype, (@{
+ @"album": @(PHAssetCollectionSubtypeAny),
+ @"all": @(PHAssetCollectionSubtypeAny),
+ @"event": @(PHAssetCollectionSubtypeAlbumSyncedEvent),
+ @"faces": @(PHAssetCollectionSubtypeAlbumSyncedFaces),
+ @"library": @(PHAssetCollectionSubtypeSmartAlbumUserLibrary),
+ @"photo-stream": @(PHAssetCollectionSubtypeAlbumMyPhotoStream), // incorrect, but legacy
+ @"photostream": @(PHAssetCollectionSubtypeAlbumMyPhotoStream),
+ @"saved-photos": @(PHAssetCollectionSubtypeAny), // incorrect, but legacy
+ @"savedphotos": @(PHAssetCollectionSubtypeAny), // This was ALAssetsGroupSavedPhotos, seems to have no direct correspondence in PHAssetCollectionSubtype
+}), PHAssetCollectionSubtypeAny, integerValue)
- // New values
- @"album": @(ALAssetsGroupAlbum),
- @"all": @(ALAssetsGroupAll),
- @"event": @(ALAssetsGroupEvent),
- @"faces": @(ALAssetsGroupFaces),
- @"library": @(ALAssetsGroupLibrary),
- @"photo-stream": @(ALAssetsGroupPhotoStream),
- @"saved-photos": @(ALAssetsGroupSavedPhotos),
-
- // Legacy values
- @"Album": @(ALAssetsGroupAlbum),
- @"All": @(ALAssetsGroupAll),
- @"Event": @(ALAssetsGroupEvent),
- @"Faces": @(ALAssetsGroupFaces),
- @"Library": @(ALAssetsGroupLibrary),
- @"PhotoStream": @(ALAssetsGroupPhotoStream),
- @"SavedPhotos": @(ALAssetsGroupSavedPhotos),
-
-}), ALAssetsGroupSavedPhotos, integerValue)
-
-static Class _ALAssetsFilter = nil;
-static NSString *_ALAssetsGroupPropertyName = nil;
-static NSString *_ALAssetPropertyAssetURL = nil;
-static NSString *_ALAssetPropertyLocation = nil;
-static NSString *_ALAssetPropertyDate = nil;
-static NSString *_ALAssetPropertyType = nil;
-static NSString *_ALAssetPropertyDuration = nil;
-static NSString *_ALAssetTypeVideo = nil;
-static NSString *lookupNSString(void * handle, const char * name)
-{
- void ** sym = dlsym(handle, name);
- return (__bridge NSString *)(sym ? *sym : nil);
-}
-static void ensureAssetsLibLoaded(void)
-{
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- void * handle = dlopen("/System/Library/Frameworks/AssetsLibrary.framework/AssetsLibrary", RTLD_LAZY);
- RCTAssert(handle != NULL, @"Unable to load AssetsLibrary.framework.");
- _ALAssetsFilter = objc_getClass("ALAssetsFilter");
- _ALAssetsGroupPropertyName = lookupNSString(handle, "ALAssetsGroupPropertyName");
- _ALAssetPropertyAssetURL = lookupNSString(handle, "ALAssetPropertyAssetURL");
- _ALAssetPropertyLocation = lookupNSString(handle, "ALAssetPropertyLocation");
- _ALAssetPropertyDate = lookupNSString(handle, "ALAssetPropertyDate");
- _ALAssetPropertyType = lookupNSString(handle, "ALAssetPropertyType");
- _ALAssetPropertyDuration = lookupNSString(handle, "ALAssetPropertyDuration");
- _ALAssetTypeVideo = lookupNSString(handle, "ALAssetTypeVideo");
- });
-}
-+ (ALAssetsFilter *)ALAssetsFilter:(id)json
+@end
+
+@implementation RCTConvert (PHFetchOptions)
+
++ (PHFetchOptions *)PHFetchOptionsFromMediaType:(NSString *)mediaType
{
- static NSDictionary<NSString *, ALAssetsFilter *> *options;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- ensureAssetsLibLoaded();
- options = @{
- // New values
- @"photos": [_ALAssetsFilter allPhotos],
- @"videos": [_ALAssetsFilter allVideos],
- @"all": [_ALAssetsFilter allAssets],
-
- // Legacy values
- @"Photos": [_ALAssetsFilter allPhotos],
- @"Videos": [_ALAssetsFilter allVideos],
- @"All": [_ALAssetsFilter allAssets],
- };
- });
+ // This is not exhaustive in terms of supported media type predicates; more can be added in the future
+ NSString *const lowercase = [mediaType lowercaseString];
- ALAssetsFilter *filter = options[json ?: @"photos"];
- if (!filter) {
+ if ([lowercase isEqualToString:@"photos"]) {
+ PHFetchOptions *const options = [PHFetchOptions new];
+ options.predicate = [NSPredicate predicateWithFormat:@"mediaType = %d", PHAssetMediaTypeImage];
+ return options;
+ } else if ([lowercase isEqualToString:@"videos"]) {
+ PHFetchOptions *const options = [PHFetchOptions new];
+ options.predicate = [NSPredicate predicateWithFormat:@"mediaType = %d", PHAssetMediaTypeVideo];
+ return options;
+ } else {
+ if (![lowercase isEqualToString:@"all"]) {
RCTLogError(@"Invalid filter option: '%@'. Expected one of 'photos',"
- "'videos' or 'all'.", json);
+ "'videos' or 'all'.", mediaType);
+ }
+ // This case includes the "all" mediatype
+ return nil;
}
- return filter ?: [_ALAssetsFilter allPhotos];
}
@end
@@ -111,45 +73,87 @@
@synthesize bridge = _bridge;
-static NSString *const kErrorUnableToLoad = @"E_UNABLE_TO_LOAD";
static NSString *const kErrorUnableToSave = @"E_UNABLE_TO_SAVE";
+static NSString *const kErrorUnableToLoad = @"E_UNABLE_TO_LOAD";
+
+static NSString *const kErrorAuthRestricted = @"E_PHOTO_LIBRARY_AUTH_RESTRICTED";
+static NSString *const kErrorAuthDenied = @"E_PHOTO_LIBRARY_AUTH_DENIED";
+
+typedef void (^PhotosAuthorizedBlock)(void);
+
+static void requestPhotoLibraryAccess(RCTPromiseRejectBlock reject, PhotosAuthorizedBlock authorizedBlock) {
+ PHAuthorizationStatus authStatus = [PHPhotoLibrary authorizationStatus];
+ if (authStatus == PHAuthorizationStatusRestricted) {
+ reject(kErrorAuthRestricted, @"Access to photo library is restricted", nil);
+ } else if (authStatus == PHAuthorizationStatusAuthorized) {
+ authorizedBlock();
+ } else if (authStatus == PHAuthorizationStatusNotDetermined) {
+ [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
+ requestPhotoLibraryAccess(reject, authorizedBlock);
+ }];
+ } else {
+ reject(kErrorAuthDenied, @"Access to photo library was denied", nil);
+ }
+}
RCT_EXPORT_METHOD(saveToCameraRoll:(NSURLRequest *)request
type:(NSString *)type
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject)
{
+ __block PHObjectPlaceholder *placeholder;
+
+ // We load images and videos differently.
+ // Images have many custom loaders which can load images from ALAssetsLibrary URLs, PHPhotoLibrary
+ // URLs, `data:` URIs, etc. Video URLs are passed directly through for now; it may be nice to support
+ // more ways of loading videos in the future.
+ __block NSURL *inputURI = nil;
+ __block UIImage *inputImage = nil;
+
+ void (^saveBlock)(void) = ^void() {
+ // performChanges and the completionHandler are called on
+ // arbitrary threads, not the main thread - this is safe
+ // for now since all JS is queued and executed on a single thread.
+ // We should reevaluate this if that assumption changes.
+ [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
+ PHAssetChangeRequest *changeRequest;
+
+ // Defaults to "photo". `type` is an optional param.
if ([type isEqualToString:@"video"]) {
- // It's unclear if writeVideoAtPathToSavedPhotosAlbum is thread-safe
- dispatch_async(dispatch_get_main_queue(), ^{
- [self->_bridge.assetsLibrary writeVideoAtPathToSavedPhotosAlbum:request.URL completionBlock:^(NSURL *assetURL, NSError *saveError) {
- if (saveError) {
- reject(kErrorUnableToSave, nil, saveError);
+ changeRequest = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:inputURI];
} else {
- resolve(assetURL.absoluteString);
+ changeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:inputImage];
}
- }];
- });
+
+ placeholder = [changeRequest placeholderForCreatedAsset];
+ } completionHandler:^(BOOL success, NSError * _Nullable error) {
+ if (success) {
+ NSString *uri = [NSString stringWithFormat:@"ph://%@", [placeholder localIdentifier]];
+ resolve(uri);
} else {
- [_bridge.imageLoader loadImageWithURLRequest:request
- callback:^(NSError *loadError, UIImage *loadedImage) {
- if (loadError) {
- reject(kErrorUnableToLoad, nil, loadError);
- return;
+ reject(kErrorUnableToSave, nil, error);
}
- // It's unclear if writeImageToSavedPhotosAlbum is thread-safe
- dispatch_async(dispatch_get_main_queue(), ^{
- [self->_bridge.assetsLibrary writeImageToSavedPhotosAlbum:loadedImage.CGImage metadata:nil completionBlock:^(NSURL *assetURL, NSError *saveError) {
- if (saveError) {
- RCTLogWarn(@"Error saving cropped image: %@", saveError);
- reject(kErrorUnableToSave, nil, saveError);
+ }];
+ };
+
+ void (^loadBlock)(void) = ^void() {
+ if ([type isEqualToString:@"video"]) {
+ inputURI = request.URL;
+ saveBlock();
} else {
- resolve(assetURL.absoluteString);
+ [self.bridge.imageLoader loadImageWithURLRequest:request callback:^(NSError *error, UIImage *image) {
+ if (error) {
+ reject(kErrorUnableToLoad, nil, error);
+ return;
}
- }];
- });
+
+ inputImage = image;
+ saveBlock();
}];
}
+ };
+
+ requestPhotoLibraryAccess(reject, loadBlock);
}
static void RCTResolvePromise(RCTPromiseResolveBlock resolve,
@@ -181,89 +185,133 @@
{
checkPhotoLibraryConfig();
- ensureAssetsLibLoaded();
- NSUInteger first = [RCTConvert NSInteger:params[@"first"]];
- NSString *afterCursor = [RCTConvert NSString:params[@"after"]];
- NSString *groupName = [RCTConvert NSString:params[@"groupName"]];
- ALAssetsFilter *assetType = [RCTConvert ALAssetsFilter:params[@"assetType"]];
- ALAssetsGroupType groupTypes = [RCTConvert ALAssetsGroupType:params[@"groupTypes"]];
+ NSUInteger const first = [RCTConvert NSInteger:params[@"first"]];
+ NSString *const afterCursor = [RCTConvert NSString:params[@"after"]];
+ NSString *const groupName = [RCTConvert NSString:params[@"groupName"]];
+ NSString *const groupTypes = [[RCTConvert NSString:params[@"groupTypes"]] lowercaseString];
+ NSString *const mediaType = [RCTConvert NSString:params[@"assetType"]];
+ NSArray<NSString *> *const mimeTypes = [RCTConvert NSStringArray:params[@"mimeTypes"]];
+
+ // If groupTypes is "all", we want to fetch the SmartAlbum "all photos". Otherwise, all
+ // other groupTypes values require the "album" collection type.
+ PHAssetCollectionType const collectionType = ([groupTypes isEqualToString:@"all"]
+ ? PHAssetCollectionTypeSmartAlbum
+ : PHAssetCollectionTypeAlbum);
+ PHAssetCollectionSubtype const collectionSubtype = [RCTConvert PHAssetCollectionSubtype:groupTypes];
+
+ // Predicate for fetching assets within a collection
+ PHFetchOptions *const assetFetchOptions = [RCTConvert PHFetchOptionsFromMediaType:mediaType];
+ assetFetchOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]];
BOOL __block foundAfter = NO;
BOOL __block hasNextPage = NO;
BOOL __block resolvedPromise = NO;
NSMutableArray<NSDictionary<NSString *, id> *> *assets = [NSMutableArray new];
- [_bridge.assetsLibrary enumerateGroupsWithTypes:groupTypes usingBlock:^(ALAssetsGroup *group, BOOL *stopGroups) {
- if (group && (groupName == nil || [groupName isEqualToString:[group valueForProperty:_ALAssetsGroupPropertyName]])) {
+ // Filter collection name ("group")
+ PHFetchOptions *const collectionFetchOptions = [PHFetchOptions new];
+ collectionFetchOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"endDate" ascending:NO]];
+ if (groupName != nil) {
+ collectionFetchOptions.predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:@"localizedTitle == '%@'", groupName]];
+ }
+
+ requestPhotoLibraryAccess(reject, ^{
+ PHFetchResult<PHAssetCollection *> *const assetCollectionFetchResult = [PHAssetCollection fetchAssetCollectionsWithType:collectionType subtype:collectionSubtype options:collectionFetchOptions];
+ [assetCollectionFetchResult enumerateObjectsUsingBlock:^(PHAssetCollection * _Nonnull assetCollection, NSUInteger collectionIdx, BOOL * _Nonnull stopCollections) {
+ // Enumerate assets within the collection
+ PHFetchResult<PHAsset *> *const assetsFetchResult = [PHAsset fetchAssetsInAssetCollection:assetCollection options:assetFetchOptions];
- [group setAssetsFilter:assetType];
- [group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stopAssets) {
- if (result) {
- NSString *uri = ((NSURL *)[result valueForProperty:_ALAssetPropertyAssetURL]).absoluteString;
+ [assetsFetchResult enumerateObjectsUsingBlock:^(PHAsset * _Nonnull asset, NSUInteger assetIdx, BOOL * _Nonnull stopAssets) {
+ NSString *const uri = [NSString stringWithFormat:@"ph://%@", [asset localIdentifier]];
if (afterCursor && !foundAfter) {
if ([afterCursor isEqualToString:uri]) {
foundAfter = YES;
}
- return; // Skip until we get to the first one
+ return; // skip until we get to the first one
+ }
+
+ // Get underlying resources of an asset - this includes files as well as details about edited PHAssets
+ if ([mimeTypes count] > 0) {
+ NSArray<PHAssetResource *> *const assetResources = [PHAssetResource assetResourcesForAsset:asset];
+ if (![assetResources firstObject]) {
+ return;
+ }
+
+ PHAssetResource *const _Nonnull resource = [assetResources firstObject];
+ CFStringRef const uti = (__bridge CFStringRef _Nonnull)(resource.uniformTypeIdentifier);
+ NSString *const mimeType = (NSString *)CFBridgingRelease(UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType));
+
+ BOOL __block mimeTypeFound = NO;
+ [mimeTypes enumerateObjectsUsingBlock:^(NSString * _Nonnull mimeTypeFilter, NSUInteger idx, BOOL * _Nonnull stop) {
+ if ([mimeType isEqualToString:mimeTypeFilter]) {
+ mimeTypeFound = YES;
+ *stop = YES;
+ }
+ }];
+
+ if (!mimeTypeFound) {
+ return;
+ }
}
+
+ // If we've accumulated enough results to resolve a single promise
if (first == assets.count) {
*stopAssets = YES;
- *stopGroups = YES;
+ *stopCollections = YES;
hasNextPage = YES;
RCTAssert(resolvedPromise == NO, @"Resolved the promise before we finished processing the results.");
RCTResolvePromise(resolve, assets, hasNextPage);
resolvedPromise = YES;
return;
}
- CGSize dimensions = [result defaultRepresentation].dimensions;
- CLLocation *loc = [result valueForProperty:_ALAssetPropertyLocation];
- NSDate *date = [result valueForProperty:_ALAssetPropertyDate];
- NSString *filename = [result defaultRepresentation].filename;
- int64_t duration = 0;
- if ([[result valueForProperty:_ALAssetPropertyType] isEqualToString:_ALAssetTypeVideo]) {
- duration = [[result valueForProperty:_ALAssetPropertyDuration] intValue];
- }
+ NSString *const assetMediaTypeLabel = (asset.mediaType == PHAssetMediaTypeVideo
+ ? @"video"
+ : (asset.mediaType == PHAssetMediaTypeImage
+ ? @"image"
+ : (asset.mediaType == PHAssetMediaTypeAudio
+ ? @"audio"
+ : @"unknown")));
+ CLLocation *const loc = asset.location;
+
+ // A note on isStored: in the previous code that used ALAssets, isStored
+ // was always set to YES, probably because iCloud-synced images were never returned (?).
+ // To get the "isStored" information and filename, we would need to actually request the
+ // image data from the image manager. Those operations could get really expensive and
+ // would definitely utilize the disk too much.
+ // Thus, this field is actually not reliable.
+ // Note that Android also does not return the `isStored` field at all.
[assets addObject:@{
@"node": @{
- @"type": [result valueForProperty:_ALAssetPropertyType],
- @"group_name": [group valueForProperty:_ALAssetsGroupPropertyName],
+ @"type": assetMediaTypeLabel, // TODO: switch to mimeType?
+ @"group_name": [assetCollection localizedTitle],
@"image": @{
@"uri": uri,
- @"filename" : filename ?: [NSNull null],
- @"height": @(dimensions.height),
- @"width": @(dimensions.width),
- @"isStored": @YES,
- @"playableDuration": @(duration),
+ @"height": @([asset pixelHeight]),
+ @"width": @([asset pixelWidth]),
+ @"isStored": @YES, // this field doesn't seem to exist on android
+ @"playableDuration": @([asset duration]) // fractional seconds
},
- @"timestamp": @(date.timeIntervalSince1970),
- @"location": loc ? @{
+ @"timestamp": @(asset.creationDate.timeIntervalSince1970),
+ @"location": (loc ? @{
@"latitude": @(loc.coordinate.latitude),
@"longitude": @(loc.coordinate.longitude),
@"altitude": @(loc.altitude),
@"heading": @(loc.course),
- @"speed": @(loc.speed),
- } : @{},
+ @"speed": @(loc.speed), // speed in m/s
+ } : @{})
}
}];
- }
}];
- }
+ }];
- if (!group) {
- // Sometimes the enumeration continues even if we set stop above, so we guard against resolving the promise
- // multiple times here.
+ // If we get this far and haven't resolved the promise yet, we reached the end of the list of photos
if (!resolvedPromise) {
+ hasNextPage = NO;
RCTResolvePromise(resolve, assets, hasNextPage);
resolvedPromise = YES;
}
- }
- } failureBlock:^(NSError *error) {
- if (error.code != ALAssetsLibraryAccessUserDeniedError) {
- RCTLogError(@"Failure while iterating through asset groups %@", error);
- }
- reject(kErrorUnableToLoad, nil, error);
- }];
+ });
}
RCT_EXPORT_METHOD(deletePhotos:(NSArray<NSString *>*)assets

Libraries/CameraRoll/RCTImagePickerManager.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

Libraries/CameraRoll/RCTImagePickerManager.m

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -16,6 +16,16 @@
#import <React/RCTRootView.h>
#import <React/RCTUtils.h>
+@interface RCTImagePickerController : UIImagePickerController
+
+@property (nonatomic, assign) BOOL unmirrorFrontFacingCamera;
+
+@end
+
+@implementation RCTImagePickerController
+
+@end
+
@interface RCTImagePickerManager () <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
@end
@@ -31,6 +41,22 @@
@synthesize bridge = _bridge;
+- (id)init
+{
+ if (self = [super init]) {
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(cameraChanged:)
+ name:@"AVCaptureDeviceDidStartRunningNotification"
+ object:nil];
+ }
+ return self;
+}
+
+- (void)dealloc
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:@"AVCaptureDeviceDidStartRunningNotification" object:nil];
+}
+
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
@@ -56,9 +82,10 @@
return;
}
- UIImagePickerController *imagePicker = [UIImagePickerController new];
+ RCTImagePickerController *imagePicker = [RCTImagePickerController new];
imagePicker.delegate = self;
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
+ imagePicker.unmirrorFrontFacingCamera = [RCTConvert BOOL:config[@"unmirrorFrontFacingCamera"]];
if ([RCTConvert BOOL:config[@"videoMode"]]) {
imagePicker.cameraCaptureMode = UIImagePickerControllerCameraCaptureModeVideo;
@@ -175,4 +202,17 @@
}
}
+- (void)cameraChanged:(NSNotification *)notification
+{
+ for (UIImagePickerController *picker in _pickers) {
+ if ([picker isKindOfClass:[RCTImagePickerController class]]
+ && ((RCTImagePickerController *)picker).unmirrorFrontFacingCamera
+ && picker.cameraDevice == UIImagePickerControllerCameraDeviceFront) {
+ picker.cameraViewTransform = CGAffineTransformScale(CGAffineTransformIdentity, -1, 1);
+ } else {
+ picker.cameraViewTransform = CGAffineTransformIdentity;
+ }
+ }
+}
+
@end

Libraries/CameraRoll/RCTPhotoLibraryImageLoader.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/CameraRoll/RCTPhotoLibraryImageLoader.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -39,7 +39,7 @@
// Using PhotoKit for iOS 8+
// The 'ph://' prefix is used by FBMediaKit to differentiate between
// assets-library. It is prepended to the local ID so that it is in the
- // form of an, NSURL which is what assets-library uses.
+ // form of an NSURL which is what assets-library uses.
NSString *assetID = @"";
PHFetchResult *results;
if (!imageURL) {

Libraries/Color/normalizeColor.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/AccessibilityInfo/AccessibilityInfo.ios.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/ActivityIndicator/ActivityIndicator.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -15,7 +15,7 @@
const StyleSheet = require('StyleSheet');
const View = require('View');
-const requireNativeComponent = require('requireNativeComponent');
+const RCTActivityIndicatorViewNativeComponent = require('RCTActivityIndicatorViewNativeComponent');
import type {NativeComponent} from 'ReactNative';
import type {ViewProps} from 'ViewPropTypes';
@@ -23,7 +23,7 @@
const RCTActivityIndicator =
Platform.OS === 'android'
? require('ProgressBarAndroid')
- : requireNativeComponent('RCTActivityIndicatorView');
+ : RCTActivityIndicatorViewNativeComponent;
const GRAY = '#999999';
@@ -69,10 +69,7 @@
*
* See http://facebook.github.io/react-native/docs/activityindicator.html
*/
-const ActivityIndicator = (
- props: Props,
- forwardedRef?: ?React.Ref<'RCTActivityIndicatorView'>,
-) => {
+const ActivityIndicator = (props: Props, forwardedRef?: any) => {
const {onLayout, style, ...restProps} = props;
let sizeStyle;
@@ -110,10 +107,12 @@
);
};
-// $FlowFixMe - TODO T29156721 `React.forwardRef` is not defined in Flow, yet.
const ActivityIndicatorWithRef = React.forwardRef(ActivityIndicator);
ActivityIndicatorWithRef.displayName = 'ActivityIndicator';
+/* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an error
+ * found when Flow v0.89 was deployed. To see the error, delete this comment
+ * and run Flow. */
ActivityIndicatorWithRef.defaultProps = {
animating: true,
color: Platform.OS === 'ios' ? GRAY : null,
@@ -136,4 +135,7 @@
},
});
+/* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an error
+ * found when Flow v0.89 was deployed. To see the error, delete this comment
+ * and run Flow. */
module.exports = (ActivityIndicatorWithRef: Class<NativeComponent<Props>>);

Libraries/Components/ActivityIndicator/RCTActivityIndicatorViewNativeComponent.js

@@ -0,0 +1,60 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow
+ */
+
+'use strict';
+
+const requireNativeComponent = require('requireNativeComponent');
+
+import type {ViewProps} from 'ViewPropTypes';
+import type {ViewStyleProp} from 'StyleSheet';
+import type {NativeComponent} from 'ReactNative';
+
+type NativeProps = $ReadOnly<{|
+ ...ViewProps,
+
+ /**
+ * Whether the indicator should hide when not animating (true by default).
+ *
+ * See http://facebook.github.io/react-native/docs/activityindicator.html#hideswhenstopped
+ */
+ hidesWhenStopped?: ?boolean,
+
+ /**
+ * Whether to show the indicator (true, the default) or hide it (false).
+ *
+ * See http://facebook.github.io/react-native/docs/activityindicator.html#animating
+ */
+ animating?: ?boolean,
+
+ /**
+ * The foreground color of the spinner (default is gray).
+ *
+ * See http://facebook.github.io/react-native/docs/activityindicator.html#color
+ */
+ color?: ?string,
+
+ /**
+ * Size of the indicator (default is 'small').
+ * Passing a number to the size prop is only supported on Android.
+ *
+ * See http://facebook.github.io/react-native/docs/activityindicator.html#size
+ */
+ size?: ?(number | 'small' | 'large'),
+
+ style?: ?ViewStyleProp,
+ styleAttr?: ?string,
+ indeterminate?: ?boolean,
+|}>;
+
+type ActivityIndicatorNativeType = Class<NativeComponent<NativeProps>>;
+
+module.exports = ((requireNativeComponent(
+ 'RCTActivityIndicatorView',
+): any): ActivityIndicatorNativeType);

Libraries/Components/AppleTV/TVEventHandler.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/AppleTV/TVViewPropTypes.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,76 +9,100 @@
*/
'use strict';
-const PropTypes = require('prop-types');
+
+export type TVParallaxPropertiesType = $ReadOnly<{|
+ /**
+ * If true, parallax effects are enabled. Defaults to true.
+ */
+ enabled?: boolean,
+
+ /**
+ * Defaults to 2.0.
+ */
+ shiftDistanceX?: number,
+
+ /**
+ * Defaults to 2.0.
+ */
+ shiftDistanceY?: number,
+
+ /**
+ * Defaults to 0.05.
+ */
+ tiltAngle?: number,
+
+ /**
+ * Defaults to 1.0
+ */
+ magnification?: number,
+
+ /**
+ * Defaults to 1.0
+ */
+ pressMagnification?: number,
+
+ /**
+ * Defaults to 0.3
+ */
+ pressDuration?: number,
+
+ /**
+ * Defaults to 0.3
+ */
+ pressDelay?: number,
+|}>;
/**
* Additional View properties for Apple TV
*/
-const TVViewPropTypes = {
+export type TVViewProps = $ReadOnly<{|
/**
- * When set to true, this view will be focusable
- * and navigable using the TV remote.
+ * *(Apple TV only)* When set to true, this view will be focusable
+ * and navigable using the Apple TV remote.
+ *
+ * @platform ios
*/
- isTVSelectable: PropTypes.bool,
+ isTVSelectable?: boolean,
/**
- * May be set to true to force the TV focus engine to move focus to this view.
+ * *(Apple TV only)* May be set to true to force the Apple TV focus engine to move focus to this view.
+ *
+ * @platform ios
*/
- hasTVPreferredFocus: PropTypes.bool,
+ hasTVPreferredFocus?: boolean,
/**
* *(Apple TV only)* Object with properties to control Apple TV parallax effects.
*
- * enabled: If true, parallax effects are enabled. Defaults to true.
- * shiftDistanceX: Defaults to 2.0.
- * shiftDistanceY: Defaults to 2.0.
- * tiltAngle: Defaults to 0.05.
- * magnification: Defaults to 1.0.
- * pressMagnification: Defaults to 1.0.
- * pressDuration: Defaults to 0.3.
- * pressDelay: Defaults to 0.0.
- *
* @platform ios
*/
- tvParallaxProperties: PropTypes.object,
+ tvParallaxProperties?: TVParallaxPropertiesType,
/**
* *(Apple TV only)* May be used to change the appearance of the Apple TV parallax effect when this view goes in or out of focus. Defaults to 2.0.
*
* @platform ios
*/
- tvParallaxShiftDistanceX: PropTypes.number,
+ tvParallaxShiftDistanceX?: number,
/**
* *(Apple TV only)* May be used to change the appearance of the Apple TV parallax effect when this view goes in or out of focus. Defaults to 2.0.
*
* @platform ios
*/
- tvParallaxShiftDistanceY: PropTypes.number,
+ tvParallaxShiftDistanceY?: number,
/**
* *(Apple TV only)* May be used to change the appearance of the Apple TV parallax effect when this view goes in or out of focus. Defaults to 0.05.
*
* @platform ios
*/
- tvParallaxTiltAngle: PropTypes.number,
+ tvParallaxTiltAngle?: number,
/**
* *(Apple TV only)* May be used to change the appearance of the Apple TV parallax effect when this view goes in or out of focus. Defaults to 1.0.
*
* @platform ios
*/
- tvParallaxMagnification: PropTypes.number,
-};
-
-export type TVViewProps = $ReadOnly<{|
- isTVSelectable?: boolean,
- hasTVPreferredFocus?: boolean,
- tvParallaxProperties?: Object,
- tvParallaxShiftDistanceX?: number,
- tvParallaxShiftDistanceY?: number,
- tvParallaxTiltAngle?: number,
tvParallaxMagnification?: number,
|}>;
-
-module.exports = TVViewPropTypes;

Libraries/Components/Button.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,17 +10,54 @@
'use strict';
-const ColorPropType = require('ColorPropType');
const Platform = require('Platform');
const React = require('React');
-const PropTypes = require('prop-types');
const StyleSheet = require('StyleSheet');
const Text = require('Text');
const TouchableNativeFeedback = require('TouchableNativeFeedback');
const TouchableOpacity = require('TouchableOpacity');
const View = require('View');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
+
+import type {PressEvent} from 'CoreEventTypes';
+
+type ButtonProps = $ReadOnly<{|
+ /**
+ * Text to display inside the button
+ */
+ title: string,
+
+ /**
+ * Handler to be called when the user taps the button
+ */
+ onPress: (event?: PressEvent) => mixed,
+
+ /**
+ * Color of the text (iOS), or background color of the button (Android)
+ */
+ color?: ?string,
+
+ /**
+ * TV preferred focus (see documentation for the View component).
+ */
+ hasTVPreferredFocus?: ?boolean,
+
+ /**
+ * Text to display for blindness accessibility features
+ */
+ accessibilityLabel?: ?string,
+
+ /**
+ * If true, disable all interactions for this component.
+ */
+ disabled?: ?boolean,
+
+ /**
+ * Used to locate this view in end-to-end tests.
+ */
+ testID?: ?string,
+|}>;
/**
* A basic button component that should render nicely on any platform. Supports
@@ -50,46 +87,7 @@
*
*/
-class Button extends React.Component<{
- title: string,
- onPress: () => any,
- color?: ?string,
- hasTVPreferredFocus?: ?boolean,
- accessibilityLabel?: ?string,
- disabled?: ?boolean,
- testID?: ?string,
-}> {
- static propTypes = {
- /**
- * Text to display inside the button
- */
- title: PropTypes.string.isRequired,
- /**
- * Text to display for blindness accessibility features
- */
- accessibilityLabel: PropTypes.string,
- /**
- * Color of the text (iOS), or background color of the button (Android)
- */
- color: ColorPropType,
- /**
- * If true, disable all interactions for this component.
- */
- disabled: PropTypes.bool,
- /**
- * TV preferred focus (see documentation for the View component).
- */
- hasTVPreferredFocus: PropTypes.bool,
- /**
- * Handler to be called when the user taps the button
- */
- onPress: PropTypes.func.isRequired,
- /**
- * Used to locate this view in end-to-end tests.
- */
- testID: PropTypes.string,
- };
-
+class Button extends React.Component<ButtonProps> {
render() {
const {
accessibilityLabel,
@@ -152,21 +150,21 @@
borderRadius: 2,
},
}),
- text: Platform.select({
+ text: {
+ textAlign: 'center',
+ padding: 8,
+ ...Platform.select({
ios: {
// iOS blue from https://developer.apple.com/ios/human-interface-guidelines/visual-design/color/
color: '#007AFF',
- textAlign: 'center',
- padding: 8,
fontSize: 18,
},
android: {
color: 'white',
- textAlign: 'center',
- padding: 8,
fontWeight: '500',
},
}),
+ },
buttonDisabled: Platform.select({
ios: {},
android: {

Libraries/Components/CheckBox/AndroidCheckBoxNativeComponent.js

@@ -0,0 +1,51 @@
+/**
+ * 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.
+ *
+ * @flow
+ * @format
+ */
+'use strict';
+
+const requireNativeComponent = require('requireNativeComponent');
+
+import type {ViewProps} from 'ViewPropTypes';
+import type {SyntheticEvent} from 'CoreEventTypes';
+import type {NativeComponent} from 'ReactNative';
+
+type CheckBoxEvent = SyntheticEvent<
+ $ReadOnly<{|
+ target: number,
+ value: boolean,
+ |}>,
+>;
+
+type NativeProps = $ReadOnly<{|
+ ...ViewProps,
+
+ /**
+ * Used in case the props change removes the component.
+ */
+ onChange?: ?(event: CheckBoxEvent) => mixed,
+
+ /**
+ * Invoked with the new value when the value changes.
+ */
+ onValueChange?: ?(value: boolean) => mixed,
+
+ /**
+ * Used to locate this view in end-to-end tests.
+ */
+ testID?: ?string,
+
+ on?: ?boolean,
+ enabled?: boolean,
+|}>;
+
+type CheckBoxNativeType = Class<NativeComponent<NativeProps>>;
+
+module.exports = ((requireNativeComponent(
+ 'AndroidCheckBox',
+): any): CheckBoxNativeType);

Libraries/Components/CheckBox/CheckBox.android.js

@@ -1,29 +1,80 @@
/**
- * Copyright (c) 2017-present, Facebook, Inc.
+ * 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.
*
- * @flow
+ * @flow strict-local
* @format
*/
'use strict';
-const NativeMethodsMixin = require('NativeMethodsMixin');
-const PropTypes = require('prop-types');
const React = require('React');
const StyleSheet = require('StyleSheet');
-const ViewPropTypes = require('ViewPropTypes');
-const createReactClass = require('create-react-class');
-const requireNativeComponent = require('requireNativeComponent');
+const AndroidCheckBoxNativeComponent = require('AndroidCheckBoxNativeComponent');
+const nullthrows = require('nullthrows');
+const setAndForwardRef = require('setAndForwardRef');
+
+import type {ViewProps} from 'ViewPropTypes';
+import type {SyntheticEvent} from 'CoreEventTypes';
+import type {NativeComponent} from 'ReactNative';
+
+type CheckBoxEvent = SyntheticEvent<
+ $ReadOnly<{|
+ target: number,
+ value: boolean,
+ |}>,
+>;
-const RCTCheckBox = requireNativeComponent('AndroidCheckBox');
+type CommonProps = $ReadOnly<{|
+ ...ViewProps,
-type DefaultProps = {
- value: boolean,
- disabled: boolean,
-};
+ /**
+ * Used in case the props change removes the component.
+ */
+ onChange?: ?(event: CheckBoxEvent) => mixed,
+
+ /**
+ * Invoked with the new value when the value changes.
+ */
+ onValueChange?: ?(value: boolean) => mixed,
+
+ /**
+ * Used to locate this view in end-to-end tests.
+ */
+ testID?: ?string,
+|}>;
+
+type NativeProps = $ReadOnly<{|
+ ...CommonProps,
+
+ on?: ?boolean,
+ enabled?: boolean,
+|}>;
+
+type CheckBoxNativeType = Class<NativeComponent<NativeProps>>;
+
+type Props = $ReadOnly<{|
+ ...CommonProps,
+
+ /**
+ * The value of the checkbox. If true the checkbox will be turned on.
+ * Default value is false.
+ */
+ value?: ?boolean,
+
+ /**
+ * If true the user won't be able to toggle the checkbox.
+ * Default value is false.
+ */
+ disabled?: ?boolean,
+
+ /**
+ * Used to get the ref for the native checkbox
+ */
+ forwardedRef?: ?React.Ref<CheckBoxNativeType>,
+|}>;
/**
* Renders a boolean input (Android only).
@@ -80,85 +131,66 @@
* @keyword checkbox
* @keyword toggle
*/
-let CheckBox = createReactClass({
- displayName: 'CheckBox',
- propTypes: {
- ...ViewPropTypes,
- /**
- * The value of the checkbox. If true the checkbox will be turned on.
- * Default value is false.
- */
- value: PropTypes.bool,
- /**
- * If true the user won't be able to toggle the checkbox.
- * Default value is false.
- */
- disabled: PropTypes.bool,
- /**
- * Used in case the props change removes the component.
- */
- onChange: PropTypes.func,
- /**
- * Invoked with the new value when the value changes.
- */
- onValueChange: PropTypes.func,
- /**
- * Used to locate this view in end-to-end tests.
- */
- testID: PropTypes.string,
- },
-
- getDefaultProps: function(): DefaultProps {
- return {
- value: false,
- disabled: false,
- };
+class CheckBox extends React.Component<Props> {
+ _nativeRef: ?React.ElementRef<CheckBoxNativeType> = null;
+ _setNativeRef = setAndForwardRef({
+ getForwardedRef: () => this.props.forwardedRef,
+ setLocalRef: ref => {
+ this._nativeRef = ref;
},
+ });
- mixins: [NativeMethodsMixin],
-
- _rctCheckBox: {},
- _onChange: function(event: Object) {
- this._rctCheckBox.setNativeProps({value: this.props.value});
+ _onChange = (event: CheckBoxEvent) => {
+ const value = this.props.value ?? false;
+ nullthrows(this._nativeRef).setNativeProps({value: value});
// Change the props after the native props are set in case the props
// change removes the component
this.props.onChange && this.props.onChange(event);
this.props.onValueChange &&
this.props.onValueChange(event.nativeEvent.value);
- },
+ };
- render: function() {
- let props = {...this.props};
- props.onStartShouldSetResponder = () => true;
- props.onResponderTerminationRequest = () => false;
- /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
- * when making Flow check .android.js files. */
- props.enabled = !this.props.disabled;
- /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
- * when making Flow check .android.js files. */
- props.on = this.props.value;
- props.style = [styles.rctCheckBox, this.props.style];
+ render() {
+ const {disabled: _, value: __, style, forwardedRef, ...props} = this.props;
+ const disabled = this.props.disabled ?? false;
+ const value = this.props.value ?? false;
+
+ const nativeProps = {
+ ...props,
+ onStartShouldSetResponder: () => true,
+ onResponderTerminationRequest: () => false,
+ enabled: !disabled,
+ on: value,
+ style: [styles.rctCheckBox, style],
+ };
return (
- <RCTCheckBox
- {...props}
- ref={ref => {
- /* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This
- * comment suppresses an error when upgrading Flow's support for
- * React. To see the error delete this comment and run Flow. */
- this._rctCheckBox = ref;
- }}
+ <AndroidCheckBoxNativeComponent
+ {...nativeProps}
+ ref={this._setNativeRef}
onChange={this._onChange}
/>
);
- },
-});
+ }
+}
-let styles = StyleSheet.create({
+const styles = StyleSheet.create({
rctCheckBox: {
height: 32,
width: 32,
},
});
-module.exports = CheckBox;
+/**
+ * Can't use CheckBoxNativeType because it has different props
+ */
+type CheckBoxType = Class<NativeComponent<Props>>;
+
+const CheckBoxWithRef = React.forwardRef(function CheckBoxWithRef(props, ref) {
+ return <CheckBox {...props} forwardedRef={ref} />;
+});
+
+/* $FlowFixMe(>=0.89.0 site=react_native_android_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
+module.exports = (CheckBoxWithRef: CheckBoxType);

Libraries/Components/CheckBox/CheckBox.ios.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2017-present, Facebook, Inc.
+ * 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.

Libraries/Components/Clipboard/Clipboard.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/DatePicker/DatePickerIOS.android.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/DatePicker/DatePickerIOS.ios.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -8,23 +8,27 @@
* This is a controlled component version of RCTDatePickerIOS
*
* @format
- * @flow
+ * @flow strict-local
*/
'use strict';
const React = require('React');
-const invariant = require('fbjs/lib/invariant');
const StyleSheet = require('StyleSheet');
const View = require('View');
-const requireNativeComponent = require('requireNativeComponent');
+const invariant = require('invariant');
import type {ViewProps} from 'ViewPropTypes';
+import type {SyntheticEvent} from 'CoreEventTypes';
-const RCTDatePickerIOS = requireNativeComponent('RCTDatePicker');
+const RCTDatePickerNativeComponent = require('RCTDatePickerNativeComponent');
-type Event = Object;
+type Event = SyntheticEvent<
+ $ReadOnly<{|
+ timestamp: number,
+ |}>,
+>;
type Props = $ReadOnly<{|
...ViewProps,
@@ -113,8 +117,7 @@
mode: 'datetime',
};
- // $FlowFixMe How to type a native component to be able to call setNativeProps
- _picker: ?React.ElementRef<typeof RCTDatePickerIOS> = null;
+ _picker: ?React.ElementRef<typeof RCTDatePickerNativeComponent> = null;
componentDidUpdate() {
if (this.props.date) {
@@ -142,7 +145,8 @@
);
return (
<View style={props.style}>
- <RCTDatePickerIOS
+ <RCTDatePickerNativeComponent
+ testID={props.testID}
ref={picker => {
this._picker = picker;
}}
@@ -154,7 +158,11 @@
? props.initialDate.getTime()
: undefined
}
- locale={props.locale ? props.locale : undefined}
+ locale={
+ props.locale != null && props.locale !== ''
+ ? props.locale
+ : undefined
+ }
maximumDate={
props.maximumDate ? props.maximumDate.getTime() : undefined
}

Libraries/Components/DatePicker/RCTDatePickerNativeComponent.js

@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow
+ */
+
+'use strict';
+
+const requireNativeComponent = require('requireNativeComponent');
+
+import type {SyntheticEvent} from 'CoreEventTypes';
+import type {ViewProps} from 'ViewPropTypes';
+import type {NativeComponent} from 'ReactNative';
+
+type Event = SyntheticEvent<
+ $ReadOnly<{|
+ timestamp: number,
+ |}>,
+>;
+
+type NativeProps = $ReadOnly<{|
+ ...ViewProps,
+ date?: ?number,
+ initialDate?: ?Date,
+ locale?: ?string,
+ maximumDate?: ?number,
+ minimumDate?: ?number,
+ minuteInterval?: ?(1 | 2 | 3 | 4 | 5 | 6 | 10 | 12 | 15 | 20 | 30),
+ mode?: ?('date' | 'time' | 'datetime'),
+ onChange?: ?(event: Event) => void,
+ timeZoneOffsetInMinutes?: ?number,
+|}>;
+type RCTDatePickerNativeType = Class<NativeComponent<NativeProps>>;
+
+module.exports = ((requireNativeComponent(
+ 'RCTDatePicker',
+): any): RCTDatePickerNativeType);

Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js

@@ -1,21 +1,22 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
- * @flow
+ * @flow strict-local
*/
'use strict';
const DatePickerModule = require('NativeModules').DatePickerAndroid;
+import type {Options, DatePickerOpenAction} from 'DatePickerAndroidTypes';
/**
* Convert a Date to a timestamp.
*/
-function _toMillis(options: Object, key: string) {
+function _toMillis(options: Options, key: string) {
const dateVal = options[key];
// Is it a Date object?
if (typeof dateVal === 'object' && typeof dateVal.getMonth === 'function') {
@@ -65,12 +66,12 @@
* Note the native date picker dialog has some UI glitches on Android 4 and lower
* when using the `minDate` and `maxDate` options.
*/
- static async open(options: Object): Promise<Object> {
+ static async open(options: ?Options): Promise<DatePickerOpenAction> {
const optionsMs = options;
- if (optionsMs) {
- _toMillis(options, 'date');
- _toMillis(options, 'minDate');
- _toMillis(options, 'maxDate');
+ if (optionsMs != null) {
+ _toMillis(optionsMs, 'date');
+ _toMillis(optionsMs, 'minDate');
+ _toMillis(optionsMs, 'maxDate');
}
return DatePickerModule.open(options);
}
@@ -78,15 +79,11 @@
/**
* A date has been selected.
*/
- static get dateSetAction() {
- return 'dateSetAction';
- }
+ static +dateSetAction: 'dateSetAction' = 'dateSetAction';
/**
* The dialog has been dismissed.
*/
- static get dismissedAction() {
- return 'dismissedAction';
- }
+ static +dismissedAction: 'dismissedAction' = 'dismissedAction';
}
module.exports = DatePickerAndroid;

Libraries/Components/DatePickerAndroid/DatePickerAndroid.ios.js

@@ -1,21 +1,30 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
- * @flow
+ * @flow strict-local
*/
'use strict';
-const DatePickerAndroid = {
- async open(options: Object): Promise<Object> {
- return Promise.reject({
- message: 'DatePickerAndroid is not supported on this platform.',
- });
- },
-};
+import type {Options, DatePickerOpenAction} from 'DatePickerAndroidTypes';
+
+class DatePickerAndroid {
+ static async open(options: ?Options): Promise<DatePickerOpenAction> {
+ throw new Error('DatePickerAndroid is not supported on this platform.');
+ }
+
+ /**
+ * A date has been selected.
+ */
+ static +dateSetAction: 'dateSetAction' = 'dateSetAction';
+ /**
+ * The dialog has been dismissed.
+ */
+ static +dismissedAction: 'dismissedAction' = 'dismissedAction';
+}
module.exports = DatePickerAndroid;

Libraries/Components/DatePickerAndroid/DatePickerAndroidTypes.js

@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow strict-local
+ */
+
+export type Options = $ReadOnly<{|
+ date?: ?(Date | number),
+ minDate?: ?(Date | number),
+ maxDate?: ?(Date | number),
+ mode?: ?('calender' | 'spinner' | 'default'),
+|}>;
+
+export type DatePickerOpenAction =
+ | {|
+ action: 'dateSetAction',
+ year: number,
+ month: number,
+ day: number,
+ |}
+ | {|
+ action: 'dismissedAction',
+ year: void,
+ month: void,
+ day: void,
+ |};

Libraries/Components/DrawerAndroid/AndroidDrawerLayoutNativeComponent.js

@@ -0,0 +1,121 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow
+ */
+
+'use strict';
+
+const requireNativeComponent = require('requireNativeComponent');
+
+import type {NativeComponent} from 'ReactNative';
+import type {SyntheticEvent} from 'CoreEventTypes';
+import type {ViewStyleProp} from 'StyleSheet';
+import type React from 'React';
+
+type ColorValue = null | string;
+
+type DrawerStates = 'Idle' | 'Dragging' | 'Settling';
+
+type DrawerStateEvent = SyntheticEvent<
+ $ReadOnly<{|
+ drawerState: number,
+ |}>,
+>;
+
+type DrawerSlideEvent = SyntheticEvent<
+ $ReadOnly<{|
+ offset: number,
+ |}>,
+>;
+
+type NativeProps = $ReadOnly<{|
+ /**
+ * Determines whether the keyboard gets dismissed in response to a drag.
+ * - 'none' (the default), drags do not dismiss the keyboard.
+ * - 'on-drag', the keyboard is dismissed when a drag begins.
+ */
+ keyboardDismissMode?: ?('none' | 'on-drag'),
+
+ /**
+ * Specifies the background color of the drawer. The default value is white.
+ * If you want to set the opacity of the drawer, use rgba. Example:
+ *
+ * ```
+ * return (
+ * <DrawerLayoutAndroid drawerBackgroundColor="rgba(0,0,0,0.5)">
+ * </DrawerLayoutAndroid>
+ * );
+ * ```
+ */
+ drawerBackgroundColor: ColorValue,
+
+ /**
+ * Specifies the side of the screen from which the drawer will slide in.
+ */
+ drawerPosition: ?number,
+
+ /**
+ * Specifies the width of the drawer, more precisely the width of the view that be pulled in
+ * from the edge of the window.
+ */
+ drawerWidth?: ?number,
+
+ /**
+ * Specifies the lock mode of the drawer. The drawer can be locked in 3 states:
+ * - unlocked (default), meaning that the drawer will respond (open/close) to touch gestures.
+ * - locked-closed, meaning that the drawer will stay closed and not respond to gestures.
+ * - locked-open, meaning that the drawer will stay opened and not respond to gestures.
+ * The drawer may still be opened and closed programmatically (`openDrawer`/`closeDrawer`).
+ */
+ drawerLockMode?: ?('unlocked' | 'locked-closed' | 'locked-open'),
+
+ /**
+ * Function called whenever there is an interaction with the navigation view.
+ */
+ onDrawerSlide?: ?(event: DrawerSlideEvent) => mixed,
+
+ /**
+ * Function called when the drawer state has changed. The drawer can be in 3 states:
+ * - Idle, meaning there is no interaction with the navigation view happening at the time
+ * - Dragging, meaning there is currently an interaction with the navigation view
+ * - Settling, meaning that there was an interaction with the navigation view, and the
+ * navigation view is now finishing its closing or opening animation
+ */
+ onDrawerStateChanged?: ?(state: DrawerStateEvent) => mixed,
+
+ /**
+ * Function called whenever the navigation view has been opened.
+ */
+ onDrawerOpen?: ?() => mixed,
+
+ /**
+ * Function called whenever the navigation view has been closed.
+ */
+ onDrawerClose?: ?() => mixed,
+
+ /**
+ * The navigation view that will be rendered to the side of the screen and can be pulled in.
+ */
+ renderNavigationView: () => React.Element<any>,
+
+ /**
+ * Make the drawer take the entire screen and draw the background of the
+ * status bar to allow it to open over the status bar. It will only have an
+ * effect on API 21+.
+ */
+ statusBarBackgroundColor?: ?ColorValue,
+
+ children?: React.Node,
+ style?: ?ViewStyleProp,
+|}>;
+
+type AndroidDrawerLayoutNativeType = Class<NativeComponent<NativeProps>>;
+
+module.exports = ((requireNativeComponent(
+ 'AndroidDrawerLayout',
+): any): AndroidDrawerLayoutNativeType);

Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js

@@ -1,85 +1,63 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
*
+ * @flow
* @format
*/
'use strict';
-const ColorPropType = require('ColorPropType');
-const NativeMethodsMixin = require('NativeMethodsMixin');
const Platform = require('Platform');
const React = require('React');
-const PropTypes = require('prop-types');
const ReactNative = require('ReactNative');
const StatusBar = require('StatusBar');
const StyleSheet = require('StyleSheet');
const UIManager = require('UIManager');
const View = require('View');
-const ViewPropTypes = require('ViewPropTypes');
+const nullthrows = require('nullthrows');
-const DrawerConsts = UIManager.AndroidDrawerLayout.Constants;
+const DrawerConsts = UIManager.getViewManagerConfig('AndroidDrawerLayout')
+ .Constants;
-const createReactClass = require('create-react-class');
const dismissKeyboard = require('dismissKeyboard');
-const requireNativeComponent = require('requireNativeComponent');
-
-const RK_DRAWER_REF = 'drawerlayout';
-const INNERVIEW_REF = 'innerView';
+const AndroidDrawerLayoutNativeComponent = require('AndroidDrawerLayoutNativeComponent');
const DRAWER_STATES = ['Idle', 'Dragging', 'Settling'];
-/**
- * React component that wraps the platform `DrawerLayout` (Android only). The
- * Drawer (typically used for navigation) is rendered with `renderNavigationView`
- * and direct children are the main view (where your content goes). The navigation
- * view is initially not visible on the screen, but can be pulled in from the
- * side of the window specified by the `drawerPosition` prop and its width can
- * be set by the `drawerWidth` prop.
- *
- * Example:
- *
- * ```
- * render: function() {
- * var navigationView = (
- * <View style={{flex: 1, backgroundColor: '#fff'}}>
- * <Text style={{margin: 10, fontSize: 15, textAlign: 'left'}}>I'm in the Drawer!</Text>
- * </View>
- * );
- * return (
- * <DrawerLayoutAndroid
- * drawerWidth={300}
- * drawerPosition={DrawerLayoutAndroid.positions.Left}
- * renderNavigationView={() => navigationView}>
- * <View style={{flex: 1, alignItems: 'center'}}>
- * <Text style={{margin: 10, fontSize: 15, textAlign: 'right'}}>Hello</Text>
- * <Text style={{margin: 10, fontSize: 15, textAlign: 'right'}}>World!</Text>
- * </View>
- * </DrawerLayoutAndroid>
- * );
- * },
- * ```
- */
-const DrawerLayoutAndroid = createReactClass({
- displayName: 'DrawerLayoutAndroid',
- statics: {
- positions: DrawerConsts.DrawerPosition,
- },
+import type {ViewStyleProp} from 'StyleSheet';
+import type {ColorValue} from 'StyleSheetTypes';
+import type {SyntheticEvent} from 'CoreEventTypes';
+import type {
+ MeasureOnSuccessCallback,
+ MeasureInWindowOnSuccessCallback,
+ MeasureLayoutOnSuccessCallback,
+} from 'ReactNativeTypes';
+
+type DrawerStates = 'Idle' | 'Dragging' | 'Settling';
+
+type DrawerStateEvent = SyntheticEvent<
+ $ReadOnly<{|
+ drawerState: number,
+ |}>,
+>;
+
+type DrawerSlideEvent = SyntheticEvent<
+ $ReadOnly<{|
+ offset: number,
+ |}>,
+>;
- propTypes: {
- ...ViewPropTypes,
+type Props = $ReadOnly<{|
/**
* Determines whether the keyboard gets dismissed in response to a drag.
* - 'none' (the default), drags do not dismiss the keyboard.
* - 'on-drag', the keyboard is dismissed when a drag begins.
*/
- keyboardDismissMode: PropTypes.oneOf([
- 'none', // default
- 'on-drag',
- ]),
+ keyboardDismissMode?: ?('none' | 'on-drag'),
+
/**
* Specifies the background color of the drawer. The default value is white.
* If you want to set the opacity of the drawer, use rgba. Example:
@@ -91,19 +69,19 @@
* );
* ```
*/
- drawerBackgroundColor: ColorPropType,
+ drawerBackgroundColor: ColorValue,
+
/**
* Specifies the side of the screen from which the drawer will slide in.
*/
- drawerPosition: PropTypes.oneOf([
- DrawerConsts.DrawerPosition.Left,
- DrawerConsts.DrawerPosition.Right,
- ]),
+ drawerPosition: ?number,
+
/**
* Specifies the width of the drawer, more precisely the width of the view that be pulled in
* from the edge of the window.
*/
- drawerWidth: PropTypes.number,
+ drawerWidth?: ?number,
+
/**
* Specifies the lock mode of the drawer. The drawer can be locked in 3 states:
* - unlocked (default), meaning that the drawer will respond (open/close) to touch gestures.
@@ -111,61 +89,95 @@
* - locked-open, meaning that the drawer will stay opened and not respond to gestures.
* The drawer may still be opened and closed programmatically (`openDrawer`/`closeDrawer`).
*/
- drawerLockMode: PropTypes.oneOf([
- 'unlocked',
- 'locked-closed',
- 'locked-open',
- ]),
+ drawerLockMode?: ?('unlocked' | 'locked-closed' | 'locked-open'),
+
/**
* Function called whenever there is an interaction with the navigation view.
*/
- onDrawerSlide: PropTypes.func,
+ onDrawerSlide?: ?(event: DrawerSlideEvent) => mixed,
+
/**
* Function called when the drawer state has changed. The drawer can be in 3 states:
- * - idle, meaning there is no interaction with the navigation view happening at the time
- * - dragging, meaning there is currently an interaction with the navigation view
- * - settling, meaning that there was an interaction with the navigation view, and the
+ * - Idle, meaning there is no interaction with the navigation view happening at the time
+ * - Dragging, meaning there is currently an interaction with the navigation view
+ * - Settling, meaning that there was an interaction with the navigation view, and the
* navigation view is now finishing its closing or opening animation
*/
- onDrawerStateChanged: PropTypes.func,
+ onDrawerStateChanged?: ?(state: DrawerStates) => mixed,
+
/**
* Function called whenever the navigation view has been opened.
*/
- onDrawerOpen: PropTypes.func,
+ onDrawerOpen?: ?() => mixed,
+
/**
* Function called whenever the navigation view has been closed.
*/
- onDrawerClose: PropTypes.func,
+ onDrawerClose?: ?() => mixed,
+
/**
* The navigation view that will be rendered to the side of the screen and can be pulled in.
*/
- renderNavigationView: PropTypes.func.isRequired,
+ renderNavigationView: () => React.Element<any>,
/**
* Make the drawer take the entire screen and draw the background of the
* status bar to allow it to open over the status bar. It will only have an
* effect on API 21+.
*/
- statusBarBackgroundColor: ColorPropType,
- },
+ statusBarBackgroundColor?: ?ColorValue,
- mixins: [NativeMethodsMixin],
+ children?: React.Node,
+ style?: ?ViewStyleProp,
+|}>;
+
+type State = {|
+ statusBarBackgroundColor: ColorValue,
+|};
- getDefaultProps: function(): Object {
- return {
+/**
+ * React component that wraps the platform `DrawerLayout` (Android only). The
+ * Drawer (typically used for navigation) is rendered with `renderNavigationView`
+ * and direct children are the main view (where your content goes). The navigation
+ * view is initially not visible on the screen, but can be pulled in from the
+ * side of the window specified by the `drawerPosition` prop and its width can
+ * be set by the `drawerWidth` prop.
+ *
+ * Example:
+ *
+ * ```
+ * render: function() {
+ * var navigationView = (
+ * <View style={{flex: 1, backgroundColor: '#fff'}}>
+ * <Text style={{margin: 10, fontSize: 15, textAlign: 'left'}}>I'm in the Drawer!</Text>
+ * </View>
+ * );
+ * return (
+ * <DrawerLayoutAndroid
+ * drawerWidth={300}
+ * drawerPosition={DrawerLayoutAndroid.positions.Left}
+ * renderNavigationView={() => navigationView}>
+ * <View style={{flex: 1, alignItems: 'center'}}>
+ * <Text style={{margin: 10, fontSize: 15, textAlign: 'right'}}>Hello</Text>
+ * <Text style={{margin: 10, fontSize: 15, textAlign: 'right'}}>World!</Text>
+ * </View>
+ * </DrawerLayoutAndroid>
+ * );
+ * },
+ * ```
+ */
+class DrawerLayoutAndroid extends React.Component<Props, State> {
+ static positions = DrawerConsts.DrawerPosition;
+ static defaultProps = {
drawerBackgroundColor: 'white',
};
- },
- getInitialState: function() {
- return {statusBarBackgroundColor: undefined};
- },
+ _nativeRef = React.createRef<Class<ReactNative.NativeComponent<Props>>>();
- getInnerViewNode: function() {
- return this.refs[INNERVIEW_REF].getInnerViewNode();
- },
+ state = {statusBarBackgroundColor: null};
- render: function() {
+ render() {
+ const {onDrawerStateChanged, ...props} = this.props;
const drawStatusBar =
Platform.Version >= 21 && this.props.statusBarBackgroundColor;
const drawerViewWrapper = (
@@ -183,7 +195,7 @@
</View>
);
const childrenWrapper = (
- <View ref={INNERVIEW_REF} style={styles.mainSubview} collapsable={false}>
+ <View style={styles.mainSubview} collapsable={false}>
{drawStatusBar && (
<StatusBar
translucent
@@ -202,9 +214,12 @@
</View>
);
return (
- <AndroidDrawerLayout
- {...this.props}
- ref={RK_DRAWER_REF}
+ <AndroidDrawerLayoutNativeComponent
+ {...props}
+ /* $FlowFixMe(>=0.87.0 site=react_native_android_fb) This comment
+ * suppresses an error found when Flow v0.87 was deployed. To see the
+ * error, delete this comment and run Flow. */
+ ref={this._nativeRef}
drawerWidth={this.props.drawerWidth}
drawerPosition={this.props.drawerPosition}
drawerLockMode={this.props.drawerLockMode}
@@ -215,60 +230,62 @@
onDrawerStateChanged={this._onDrawerStateChanged}>
{childrenWrapper}
{drawerViewWrapper}
- </AndroidDrawerLayout>
+ </AndroidDrawerLayoutNativeComponent>
);
- },
+ }
- _onDrawerSlide: function(event) {
+ _onDrawerSlide = (event: DrawerSlideEvent) => {
if (this.props.onDrawerSlide) {
this.props.onDrawerSlide(event);
}
if (this.props.keyboardDismissMode === 'on-drag') {
dismissKeyboard();
}
- },
+ };
- _onDrawerOpen: function() {
+ _onDrawerOpen = () => {
if (this.props.onDrawerOpen) {
this.props.onDrawerOpen();
}
- },
+ };
- _onDrawerClose: function() {
+ _onDrawerClose = () => {
if (this.props.onDrawerClose) {
this.props.onDrawerClose();
}
- },
+ };
- _onDrawerStateChanged: function(event) {
+ _onDrawerStateChanged = (event: DrawerStateEvent) => {
if (this.props.onDrawerStateChanged) {
this.props.onDrawerStateChanged(
DRAWER_STATES[event.nativeEvent.drawerState],
);
}
- },
+ };
/**
* Opens the drawer.
*/
- openDrawer: function() {
+ openDrawer() {
UIManager.dispatchViewManagerCommand(
this._getDrawerLayoutHandle(),
- UIManager.AndroidDrawerLayout.Commands.openDrawer,
+ UIManager.getViewManagerConfig('AndroidDrawerLayout').Commands.openDrawer,
null,
);
- },
+ }
/**
* Closes the drawer.
*/
- closeDrawer: function() {
+ closeDrawer() {
UIManager.dispatchViewManagerCommand(
this._getDrawerLayoutHandle(),
- UIManager.AndroidDrawerLayout.Commands.closeDrawer,
+ UIManager.getViewManagerConfig('AndroidDrawerLayout').Commands
+ .closeDrawer,
null,
);
- },
+ }
+
/**
* Closing and opening example
* Note: To access the drawer you have to give it a ref. Refs do not work on stateless components
@@ -285,10 +302,63 @@
* )
* }
*/
- _getDrawerLayoutHandle: function() {
- return ReactNative.findNodeHandle(this.refs[RK_DRAWER_REF]);
- },
-});
+ _getDrawerLayoutHandle() {
+ return ReactNative.findNodeHandle(this._nativeRef.current);
+ }
+
+ /**
+ * Native methods
+ */
+ blur() {
+ /* $FlowFixMe(>=0.87.0 site=react_native_android_fb) This comment
+ * suppresses an error found when Flow v0.87 was deployed. To see the
+ * error, delete this comment and run Flow. */
+ nullthrows(this._nativeRef.current).blur();
+ }
+
+ focus() {
+ /* $FlowFixMe(>=0.87.0 site=react_native_android_fb) This comment
+ * suppresses an error found when Flow v0.87 was deployed. To see the
+ * error, delete this comment and run Flow. */
+ nullthrows(this._nativeRef.current).focus();
+ }
+
+ measure(callback: MeasureOnSuccessCallback) {
+ /* $FlowFixMe(>=0.87.0 site=react_native_android_fb) This comment
+ * suppresses an error found when Flow v0.87 was deployed. To see the
+ * error, delete this comment and run Flow. */
+ nullthrows(this._nativeRef.current).measure(callback);
+ }
+
+ measureInWindow(callback: MeasureInWindowOnSuccessCallback) {
+ /* $FlowFixMe(>=0.87.0 site=react_native_android_fb) This comment
+ * suppresses an error found when Flow v0.87 was deployed. To see the
+ * error, delete this comment and run Flow. */
+ nullthrows(this._nativeRef.current).measureInWindow(callback);
+ }
+
+ measureLayout(
+ relativeToNativeNode: number,
+ onSuccess: MeasureLayoutOnSuccessCallback,
+ onFail?: () => void,
+ ) {
+ /* $FlowFixMe(>=0.87.0 site=react_native_android_fb) This comment
+ * suppresses an error found when Flow v0.87 was deployed. To see the
+ * error, delete this comment and run Flow. */
+ nullthrows(this._nativeRef.current).measureLayout(
+ relativeToNativeNode,
+ onSuccess,
+ onFail,
+ );
+ }
+
+ setNativeProps(nativeProps: Object) {
+ /* $FlowFixMe(>=0.87.0 site=react_native_android_fb) This comment
+ * suppresses an error found when Flow v0.87 was deployed. To see the
+ * error, delete this comment and run Flow. */
+ nullthrows(this._nativeRef.current).setNativeProps(nativeProps);
+ }
+}
const styles = StyleSheet.create({
base: {
@@ -320,7 +390,4 @@
},
});
-// The View that contains both the actual drawer and the main view
-const AndroidDrawerLayout = requireNativeComponent('AndroidDrawerLayout');
-
module.exports = DrawerLayoutAndroid;

Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.ios.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/Keyboard/KeyboardAvoidingView.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -52,8 +52,6 @@
bottom: number,
|};
-const viewRef = 'VIEW';
-
/**
* View that moves out of the way when the keyboard appears by automatically
* adjusting its height, position, or bottom padding.
@@ -66,10 +64,13 @@
_frame: ?ViewLayout = null;
_subscriptions: Array<EmitterSubscription> = [];
+ viewRef: {current: React.ElementRef<any> | null};
- state = {
- bottom: 0,
- };
+ constructor(props: Props) {
+ super(props);
+ this.state = {bottom: 0};
+ this.viewRef = React.createRef();
+ }
_relativeKeyboardHeight(keyboardFrame): number {
const frame = this._frame;
@@ -151,7 +152,7 @@
children,
contentContainerStyle,
enabled,
- keyboardVerticalOffset, // eslint-disable-line no-unused-vars
+ keyboardVerticalOffset,
style,
...props
} = this.props;
@@ -159,7 +160,7 @@
switch (behavior) {
case 'height':
let heightStyle;
- if (this._frame != null) {
+ if (this._frame != null && this.state.bottom > 0) {
// Note that we only apply a height change when there is keyboard present,
// i.e. this.state.bottom is greater than 0. If we remove that condition,
// this.frame.height will never go back to its original value.
@@ -171,7 +172,7 @@
}
return (
<View
- ref={viewRef}
+ ref={this.viewRef}
style={StyleSheet.compose(
style,
heightStyle,
@@ -185,7 +186,7 @@
case 'position':
return (
<View
- ref={viewRef}
+ ref={this.viewRef}
style={style}
onLayout={this._onLayout}
{...props}>
@@ -204,7 +205,7 @@
case 'padding':
return (
<View
- ref={viewRef}
+ ref={this.viewRef}
style={StyleSheet.compose(
style,
{paddingBottom: bottomHeight},
@@ -218,7 +219,7 @@
default:
return (
<View
- ref={viewRef}
+ ref={this.viewRef}
onLayout={this._onLayout}
style={style}
{...props}>

Libraries/Components/Keyboard/Keyboard.js

@@ -1,23 +1,23 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
- * @flow
+ * @flow strict-local
*/
'use strict';
const LayoutAnimation = require('LayoutAnimation');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
const NativeEventEmitter = require('NativeEventEmitter');
const KeyboardObserver = require('NativeModules').KeyboardObserver;
const dismissKeyboard = require('dismissKeyboard');
const KeyboardEventEmitter = new NativeEventEmitter(KeyboardObserver);
-type KeyboardEventName =
+export type KeyboardEventName =
| 'keyboardWillShow'
| 'keyboardDidShow'
| 'keyboardWillHide'
@@ -25,6 +25,13 @@
| 'keyboardWillChangeFrame'
| 'keyboardDidChangeFrame';
+export type KeyboardEventEasing =
+ | 'easeIn'
+ | 'easeInEaseOut'
+ | 'easeOut'
+ | 'linear'
+ | 'keyboard';
+
type ScreenRect = $ReadOnly<{|
screenX: number,
screenY: number,
@@ -33,10 +40,11 @@
|}>;
export type KeyboardEvent = $ReadOnly<{|
- duration?: number,
- easing?: string,
+ duration: number,
+ easing: KeyboardEventEasing,
endCoordinates: ScreenRect,
- startCoordinates?: ScreenRect,
+ startCoordinates: ScreenRect,
+ isEventFromThisApp: boolean,
|}>;
type KeyboardEventListener = (e: KeyboardEvent) => void;
@@ -121,7 +129,10 @@
* @param {string} eventName The `nativeEvent` is the string that identifies the event you're listening for.
* @param {function} callback function to be called when the event fires.
*/
- removeListener(eventName: KeyboardEventName, callback: Function) {
+ removeListener(
+ eventName: KeyboardEventName,
+ callback: KeyboardEventListener,
+ ) {
invariant(false, 'Dummy method used for documentation');
},
@@ -155,12 +166,12 @@
Keyboard.dismiss = dismissKeyboard;
Keyboard.scheduleLayoutAnimation = function(event: KeyboardEvent) {
const {duration, easing} = event;
- if (duration) {
+ if (duration != null && duration !== 0) {
LayoutAnimation.configureNext({
duration: duration,
update: {
duration: duration,
- type: (easing && LayoutAnimation.Types[easing]) || 'keyboard',
+ type: (easing != null && LayoutAnimation.Types[easing]) || 'keyboard',
},
});
}

Libraries/Components/MaskedView/MaskedViewIOS.android.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/MaskedView/MaskedViewIOS.ios.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -8,27 +8,23 @@
* @flow
*/
-const PropTypes = require('prop-types');
const React = require('React');
const StyleSheet = require('StyleSheet');
const View = require('View');
-const ViewPropTypes = require('ViewPropTypes');
-const requireNativeComponent = require('requireNativeComponent');
+const RCTMaskedViewNativeComponent = require('RCTMaskedViewNativeComponent');
import type {ViewProps} from 'ViewPropTypes';
-const RCTMaskedView = requireNativeComponent('RCTMaskedView');
-
-type Props = {
+type Props = $ReadOnly<{|
...ViewProps,
- children: any,
+ children: React.Node,
/**
* Should be a React element to be rendered and applied as the
* mask for the child element.
*/
maskElement: React.Element<any>,
-};
+|}>;
/**
* Renders the child view with a mask specified in the `maskElement` prop.
@@ -67,11 +63,6 @@
*
*/
class MaskedViewIOS extends React.Component<Props> {
- static propTypes = {
- ...ViewPropTypes,
- maskElement: PropTypes.element.isRequired,
- };
-
_hasWarnedInvalidRenderMask = false;
render() {
@@ -89,12 +80,12 @@
}
return (
- <RCTMaskedView {...otherViewProps}>
+ <RCTMaskedViewNativeComponent {...otherViewProps}>
<View pointerEvents="none" style={StyleSheet.absoluteFill}>
{maskElement}
</View>
{children}
- </RCTMaskedView>
+ </RCTMaskedViewNativeComponent>
);
}
}

Libraries/Components/MaskedView/RCTMaskedViewNativeComponent.js

@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow
+ */
+
+const requireNativeComponent = require('requireNativeComponent');
+
+import type {ViewProps} from 'ViewPropTypes';
+import type {NativeComponent} from 'ReactNative';
+
+type NativeProps = $ReadOnly<{|
+ ...ViewProps,
+|}>;
+
+type RCTMaskedViewNativeType = Class<NativeComponent<NativeProps>>;
+
+module.exports = ((requireNativeComponent(
+ 'RCTMaskedView',
+): any): RCTMaskedViewNativeType);

Libraries/Components/Navigation/NavigatorIOS.android.js

@@ -1,12 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-module.exports = require('UnimplementedView');

Libraries/Components/Navigation/NavigatorIOS.ios.js

@@ -1,932 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow
- */
-
-'use strict';
-
-const EventEmitter = require('EventEmitter');
-const Image = require('Image');
-const RCTNavigatorManager = require('NativeModules').NavigatorManager;
-const React = require('React');
-const PropTypes = require('prop-types');
-const ReactNative = require('ReactNative');
-const StaticContainer = require('StaticContainer.react');
-const StyleSheet = require('StyleSheet');
-const TVEventHandler = require('TVEventHandler');
-const View = require('View');
-const ViewPropTypes = require('ViewPropTypes');
-
-const createReactClass = require('create-react-class');
-const invariant = require('fbjs/lib/invariant');
-const requireNativeComponent = require('requireNativeComponent');
-
-/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
- * found when Flow v0.54 was deployed. To see the error delete this comment and
- * run Flow. */
-const keyMirror = require('fbjs/lib/keyMirror');
-
-const TRANSITIONER_REF = 'transitionerRef';
-
-let __uid = 0;
-function getuid() {
- return __uid++;
-}
-
-class NavigatorTransitionerIOS extends React.Component<$FlowFixMeProps> {
- requestSchedulingNavigation(cb) {
- RCTNavigatorManager.requestSchedulingJavaScriptNavigation(
- ReactNative.findNodeHandle(this),
- cb,
- );
- }
-
- render() {
- return <RCTNavigator {...this.props} />;
- }
-}
-
-const SystemIconLabels = {
- done: true,
- cancel: true,
- edit: true,
- save: true,
- add: true,
- compose: true,
- reply: true,
- action: true,
- organize: true,
- bookmarks: true,
- search: true,
- refresh: true,
- stop: true,
- camera: true,
- trash: true,
- play: true,
- pause: true,
- rewind: true,
- 'fast-forward': true,
- undo: true,
- redo: true,
- 'page-curl': true,
-};
-const SystemIcons = keyMirror(SystemIconLabels);
-
-type SystemButtonType = $Enum<typeof SystemIconLabels>;
-
-type Route = {
- component: Function,
- title: string,
- titleImage?: Object,
- passProps?: Object,
- backButtonTitle?: string,
- backButtonIcon?: Object,
- leftButtonTitle?: string,
- leftButtonIcon?: Object,
- leftButtonSystemIcon?: SystemButtonType,
- onLeftButtonPress?: Function,
- rightButtonTitle?: string,
- rightButtonIcon?: Object,
- rightButtonSystemIcon?: SystemButtonType,
- onRightButtonPress?: Function,
- wrapperStyle?: any,
-};
-
-type State = {
- idStack: Array<number>,
- routeStack: Array<Route>,
- requestedTopOfStack: number,
- observedTopOfStack: number,
- progress: number,
- fromIndex: number,
- toIndex: number,
- makingNavigatorRequest: boolean,
- updatingAllIndicesAtOrBeyond: ?number,
-};
-
-type Event = Object;
-
-/**
- * Think of `<NavigatorIOS>` as simply a component that renders an
- * `RCTNavigator`, and moves the `RCTNavigator`'s `requestedTopOfStack` pointer
- * forward and backward. The `RCTNavigator` interprets changes in
- * `requestedTopOfStack` to be pushes and pops of children that are rendered.
- * `<NavigatorIOS>` always ensures that whenever the `requestedTopOfStack`
- * pointer is moved, that we've also rendered enough children so that the
- * `RCTNavigator` can carry out the push/pop with those children.
- * `<NavigatorIOS>` also removes children that will no longer be needed
- * (after the pop of a child has been fully completed/animated out).
- */
-
-/**
- * `NavigatorIOS` is a wrapper around
- * [`UINavigationController`](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UINavigationController_Class/),
- * enabling you to implement a navigation stack. It works exactly the same as it
- * would on a native app using `UINavigationController`, providing the same
- * animations and behavior from UIKit.
- *
- * As the name implies, it is only available on iOS. Take a look at
- * [`React Navigation`](https://reactnavigation.org/) for a cross-platform
- * solution in JavaScript, or check out either of these components for native
- * solutions: [native-navigation](http://airbnb.io/native-navigation/),
- * [react-native-navigation](https://github.com/wix/react-native-navigation).
- *
- * To set up the navigator, provide the `initialRoute` prop with a route
- * object. A route object is used to describe each scene that your app
- * navigates to. `initialRoute` represents the first route in your navigator.
- *
- * ```
- * import PropTypes from 'prop-types';
- * import React, { Component } from 'react';
- * import { NavigatorIOS, Text } from 'react-native';
- *
- * export default class NavigatorIOSApp extends Component {
- * render() {
- * return (
- * <NavigatorIOS
- * initialRoute={{
- * component: MyScene,
- * title: 'My Initial Scene',
- * }}
- * style={{flex: 1}}
- * />
- * );
- * }
- * }
- *
- * class MyScene extends Component {
- * static propTypes = {
- * title: PropTypes.string.isRequired,
- * navigator: PropTypes.object.isRequired,
- * }
- *
- * _onForward = () => {
- * this.props.navigator.push({
- * title: 'Scene ' + nextIndex,
- * });
- * }
- *
- * render() {
- * return (
- * <View>
- * <Text>Current Scene: { this.props.title }</Text>
- * <TouchableHighlight onPress={this._onForward}>
- * <Text>Tap me to load the next scene</Text>
- * </TouchableHighlight>
- * </View>
- * )
- * }
- * }
- * ```
- *
- * In this code, the navigator renders the component specified in initialRoute,
- * which in this case is `MyScene`. This component will receive a `route` prop
- * and a `navigator` prop representing the navigator. The navigator's navigation
- * bar will render the title for the current scene, "My Initial Scene".
- *
- * You can optionally pass in a `passProps` property to your `initialRoute`.
- * `NavigatorIOS` passes this in as props to the rendered component:
- *
- * ```
- * initialRoute={{
- * component: MyScene,
- * title: 'My Initial Scene',
- * passProps: { myProp: 'foo' }
- * }}
- * ```
- *
- * You can then access the props passed in via `{this.props.myProp}`.
- *
- * #### Handling Navigation
- *
- * To trigger navigation functionality such as pushing or popping a view, you
- * have access to a `navigator` object. The object is passed in as a prop to any
- * component that is rendered by `NavigatorIOS`. You can then call the
- * relevant methods to perform the navigation action you need:
- *
- * ```
- * class MyView extends Component {
- * _handleBackPress() {
- * this.props.navigator.pop();
- * }
- *
- * _handleNextPress(nextRoute) {
- * this.props.navigator.push(nextRoute);
- * }
- *
- * render() {
- * const nextRoute = {
- * component: MyView,
- * title: 'Bar That',
- * passProps: { myProp: 'bar' }
- * };
- * return(
- * <TouchableHighlight onPress={() => this._handleNextPress(nextRoute)}>
- * <Text style={{marginTop: 200, alignSelf: 'center'}}>
- * See you on the other nav {this.props.myProp}!
- * </Text>
- * </TouchableHighlight>
- * );
- * }
- * }
- * ```
- *
- * You can also trigger navigator functionality from the `NavigatorIOS`
- * component:
- *
- * ```
- * class NavvyIOS extends Component {
- * _handleNavigationRequest() {
- * this.refs.nav.push({
- * component: MyView,
- * title: 'Genius',
- * passProps: { myProp: 'genius' },
- * });
- * }
- *
- * render() {
- * return (
- * <NavigatorIOS
- * ref='nav'
- * initialRoute={{
- * component: MyView,
- * title: 'Foo This',
- * passProps: { myProp: 'foo' },
- * rightButtonTitle: 'Add',
- * onRightButtonPress: () => this._handleNavigationRequest(),
- * }}
- * style={{flex: 1}}
- * />
- * );
- * }
- * }
- * ```
- *
- * The code above adds a `_handleNavigationRequest` private method that is
- * invoked from the `NavigatorIOS` component when the right navigation bar item
- * is pressed. To get access to the navigator functionality, a reference to it
- * is saved in the `ref` prop and later referenced to push a new scene into the
- * navigation stack.
- *
- * #### Navigation Bar Configuration
- *
- * Props passed to `NavigatorIOS` will set the default configuration
- * for the navigation bar. Props passed as properties to a route object will set
- * the configuration for that route's navigation bar, overriding any props
- * passed to the `NavigatorIOS` component.
- *
- * ```
- * _handleNavigationRequest() {
- * this.refs.nav.push({
- * //...
- * passProps: { myProp: 'genius' },
- * barTintColor: '#996699',
- * });
- * }
- *
- * render() {
- * return (
- * <NavigatorIOS
- * //...
- * style={{flex: 1}}
- * barTintColor='#ffffcc'
- * />
- * );
- * }
- * ```
- *
- * In the example above the navigation bar color is changed when the new route
- * is pushed.
- *
- */
-const NavigatorIOS = createReactClass({
- displayName: 'NavigatorIOS',
-
- propTypes: {
- /**
- * NavigatorIOS uses `route` objects to identify child views, their props,
- * and navigation bar configuration. Navigation operations such as push
- * operations expect routes to look like this the `initialRoute`.
- */
- initialRoute: PropTypes.shape({
- /**
- * The React Class to render for this route
- */
- component: PropTypes.func.isRequired,
-
- /**
- * The title displayed in the navigation bar and the back button for this
- * route.
- */
- title: PropTypes.string.isRequired,
-
- /**
- * If set, a title image will appear instead of the text title.
- */
- titleImage: Image.propTypes.source,
-
- /**
- * Use this to specify additional props to pass to the rendered
- * component. `NavigatorIOS` will automatically pass in `route` and
- * `navigator` props to the component.
- */
- passProps: PropTypes.object,
-
- /**
- * If set, the left navigation button image will be displayed using this
- * source. Note that this doesn't apply to the header of the current
- * view, but to those views that are subsequently pushed.
- */
- backButtonIcon: Image.propTypes.source,
-
- /**
- * If set, the left navigation button text will be set to this. Note that
- * this doesn't apply to the left button of the current view, but to
- * those views that are subsequently pushed
- */
- backButtonTitle: PropTypes.string,
-
- /**
- * If set, the left navigation button image will be displayed using
- * this source.
- */
- leftButtonIcon: Image.propTypes.source,
-
- /**
- * If set, the left navigation button will display this text.
- */
- leftButtonTitle: PropTypes.string,
-
- /**
- * If set, the left header button will appear with this system icon
- *
- * Supported icons are `done`, `cancel`, `edit`, `save`, `add`,
- * `compose`, `reply`, `action`, `organize`, `bookmarks`, `search`,
- * `refresh`, `stop`, `camera`, `trash`, `play`, `pause`, `rewind`,
- * `fast-forward`, `undo`, `redo`, and `page-curl`
- */
- leftButtonSystemIcon: PropTypes.oneOf(Object.keys(SystemIcons)),
-
- /**
- * This function will be invoked when the left navigation bar item is
- * pressed.
- */
- onLeftButtonPress: PropTypes.func,
-
- /**
- * If set, the right navigation button image will be displayed using
- * this source.
- */
- rightButtonIcon: Image.propTypes.source,
-
- /**
- * If set, the right navigation button will display this text.
- */
- rightButtonTitle: PropTypes.string,
-
- /**
- * If set, the right header button will appear with this system icon
- *
- * See leftButtonSystemIcon for supported icons
- */
- rightButtonSystemIcon: PropTypes.oneOf(Object.keys(SystemIcons)),
-
- /**
- * This function will be invoked when the right navigation bar item is
- * pressed.
- */
- onRightButtonPress: PropTypes.func,
-
- /**
- * Styles for the navigation item containing the component.
- */
- wrapperStyle: ViewPropTypes.style,
-
- /**
- * Boolean value that indicates whether the navigation bar is hidden.
- */
- navigationBarHidden: PropTypes.bool,
-
- /**
- * Boolean value that indicates whether to hide the 1px hairline
- * shadow.
- */
- shadowHidden: PropTypes.bool,
-
- /**
- * The color used for the buttons in the navigation bar.
- */
- tintColor: PropTypes.string,
-
- /**
- * The background color of the navigation bar.
- */
- barTintColor: PropTypes.string,
-
- /**
- * The style of the navigation bar. Supported values are 'default', 'black'.
- * Use 'black' instead of setting `barTintColor` to black. This produces
- * a navigation bar with the native iOS style with higher translucency.
- */
- barStyle: PropTypes.oneOf(['default', 'black']),
-
- /**
- * The text color of the navigation bar title.
- */
- titleTextColor: PropTypes.string,
-
- /**
- * Boolean value that indicates whether the navigation bar is
- * translucent.
- */
- translucent: PropTypes.bool,
- }).isRequired,
-
- /**
- * Boolean value that indicates whether the navigation bar is hidden
- * by default.
- */
- navigationBarHidden: PropTypes.bool,
-
- /**
- * Boolean value that indicates whether to hide the 1px hairline shadow
- * by default.
- */
- shadowHidden: PropTypes.bool,
-
- /**
- * The default wrapper style for components in the navigator.
- * A common use case is to set the `backgroundColor` for every scene.
- */
- itemWrapperStyle: ViewPropTypes.style,
-
- /**
- * The default color used for the buttons in the navigation bar.
- */
- tintColor: PropTypes.string,
-
- /**
- * The default background color of the navigation bar.
- */
- barTintColor: PropTypes.string,
-
- /**
- * The style of the navigation bar. Supported values are 'default', 'black'.
- * Use 'black' instead of setting `barTintColor` to black. This produces
- * a navigation bar with the native iOS style with higher translucency.
- */
- barStyle: PropTypes.oneOf(['default', 'black']),
-
- /**
- * The default text color of the navigation bar title.
- */
- titleTextColor: PropTypes.string,
-
- /**
- * Boolean value that indicates whether the navigation bar is
- * translucent by default
- */
- translucent: PropTypes.bool,
-
- /**
- * Boolean value that indicates whether the interactive pop gesture is
- * enabled. This is useful for enabling/disabling the back swipe navigation
- * gesture.
- *
- * If this prop is not provided, the default behavior is for the back swipe
- * gesture to be enabled when the navigation bar is shown and disabled when
- * the navigation bar is hidden. Once you've provided the
- * `interactivePopGestureEnabled` prop, you can never restore the default
- * behavior.
- */
- interactivePopGestureEnabled: PropTypes.bool,
- },
-
- navigator: (undefined: ?Object),
-
- UNSAFE_componentWillMount: function() {
- // Precompute a pack of callbacks that's frequently generated and passed to
- // instances.
- this.navigator = {
- push: this.push,
- pop: this.pop,
- popN: this.popN,
- replace: this.replace,
- replaceAtIndex: this.replaceAtIndex,
- replacePrevious: this.replacePrevious,
- replacePreviousAndPop: this.replacePreviousAndPop,
- resetTo: this.resetTo,
- popToRoute: this.popToRoute,
- popToTop: this.popToTop,
- };
- },
-
- componentDidMount: function() {
- this._enableTVEventHandler();
- },
-
- componentWillUnmount: function() {
- this._disableTVEventHandler();
- },
-
- getDefaultProps: function(): Object {
- return {
- translucent: true,
- };
- },
-
- getInitialState: function(): State {
- return {
- idStack: [getuid()],
- routeStack: [this.props.initialRoute],
- // The navigation index that we wish to push/pop to.
- requestedTopOfStack: 0,
- // The last index that native has sent confirmation of completed push/pop
- // for. At this point, we can discard any views that are beyond the
- // `requestedTopOfStack`. A value of `null` means we have not received
- // any confirmation, ever. We may receive an `observedTopOfStack` without
- // ever requesting it - native can instigate pops of its own with the
- // backswipe gesture.
- observedTopOfStack: 0,
- progress: 1,
- fromIndex: 0,
- toIndex: 0,
- // Whether or not we are making a navigator request to push/pop. (Used
- // for performance optimization).
- makingNavigatorRequest: false,
- // Whether or not we are updating children of navigator and if so (not
- // `null`) which index marks the beginning of all updates. Used for
- // performance optimization.
- updatingAllIndicesAtOrBeyond: 0,
- };
- },
-
- _toFocusOnNavigationComplete: (undefined: any),
-
- _handleFocusRequest: function(item: any) {
- if (this.state.makingNavigatorRequest) {
- this._toFocusOnNavigationComplete = item;
- } else {
- this._getFocusEmitter().emit('focus', item);
- }
- },
-
- _focusEmitter: (undefined: ?EventEmitter),
-
- _getFocusEmitter: function(): EventEmitter {
- // Flow not yet tracking assignments to instance fields.
- let focusEmitter = this._focusEmitter;
- if (!focusEmitter) {
- focusEmitter = new EventEmitter();
- this._focusEmitter = focusEmitter;
- }
- return focusEmitter;
- },
-
- getChildContext: function(): {
- onFocusRequested: Function,
- focusEmitter: EventEmitter,
- } {
- return {
- onFocusRequested: this._handleFocusRequest,
- focusEmitter: this._getFocusEmitter(),
- };
- },
-
- childContextTypes: {
- onFocusRequested: PropTypes.func,
- focusEmitter: PropTypes.instanceOf(EventEmitter),
- },
-
- _tryLockNavigator: function(cb: () => void) {
- this.refs[TRANSITIONER_REF].requestSchedulingNavigation(
- acquiredLock => acquiredLock && cb(),
- );
- },
-
- _handleNavigatorStackChanged: function(e: Event) {
- const newObservedTopOfStack = e.nativeEvent.stackLength - 1;
-
- invariant(
- newObservedTopOfStack <= this.state.requestedTopOfStack,
- 'No navigator item should be pushed without JS knowing about it %s %s',
- newObservedTopOfStack,
- this.state.requestedTopOfStack,
- );
- const wasWaitingForConfirmation =
- this.state.requestedTopOfStack !== this.state.observedTopOfStack;
- if (wasWaitingForConfirmation) {
- invariant(
- newObservedTopOfStack === this.state.requestedTopOfStack,
- 'If waiting for observedTopOfStack to reach requestedTopOfStack, ' +
- 'the only valid observedTopOfStack should be requestedTopOfStack.',
- );
- }
- // Mark the most recent observation regardless of if we can lock the
- // navigator. `observedTopOfStack` merely represents what we've observed
- // and this first `setState` is only executed to update debugging
- // overlays/navigation bar.
- // Also reset progress, toIndex, and fromIndex as they might not end
- // in the correct states for a two possible reasons:
- // Progress isn't always 0 or 1 at the end, the system rounds
- // If the Navigator is offscreen these values won't be updated
- // TOOD: Revisit this decision when no longer relying on native navigator.
- const nextState = {
- observedTopOfStack: newObservedTopOfStack,
- makingNavigatorRequest: false,
- updatingAllIndicesAtOrBeyond: null,
- progress: 1,
- toIndex: newObservedTopOfStack,
- fromIndex: newObservedTopOfStack,
- };
- this.setState(nextState, this._eliminateUnneededChildren);
- },
-
- _eliminateUnneededChildren: function() {
- // Updating the indices that we're deleting and that's all. (Truth: Nothing
- // even uses the indices in this case, but let's make this describe the
- // truth anyways).
- const updatingAllIndicesAtOrBeyond =
- this.state.routeStack.length > this.state.observedTopOfStack + 1
- ? this.state.observedTopOfStack + 1
- : null;
- this.setState({
- idStack: this.state.idStack.slice(0, this.state.observedTopOfStack + 1),
- routeStack: this.state.routeStack.slice(
- 0,
- this.state.observedTopOfStack + 1,
- ),
- // Now we rerequest the top of stack that we observed.
- requestedTopOfStack: this.state.observedTopOfStack,
- makingNavigatorRequest: true,
- updatingAllIndicesAtOrBeyond: updatingAllIndicesAtOrBeyond,
- });
- },
-
- /**
- * Navigate forward to a new route.
- * @param route The new route to navigate to.
- */
- push: function(route: Route) {
- invariant(!!route, 'Must supply route to push');
- // Make sure all previous requests are caught up first. Otherwise reject.
- if (this.state.requestedTopOfStack === this.state.observedTopOfStack) {
- this._tryLockNavigator(() => {
- const nextStack = this.state.routeStack.concat([route]);
- const nextIDStack = this.state.idStack.concat([getuid()]);
- this.setState({
- // We have to make sure that we've also supplied enough views to
- // satisfy our request to adjust the `requestedTopOfStack`.
- idStack: nextIDStack,
- routeStack: nextStack,
- requestedTopOfStack: nextStack.length - 1,
- makingNavigatorRequest: true,
- updatingAllIndicesAtOrBeyond: nextStack.length - 1,
- });
- });
- }
- },
-
- /**
- * Go back N scenes at once. When N=1, behavior matches `pop()`.
- * @param n The number of scenes to pop.
- */
- popN: function(n: number) {
- if (n === 0) {
- return;
- }
- // Make sure all previous requests are caught up first. Otherwise reject.
- if (this.state.requestedTopOfStack === this.state.observedTopOfStack) {
- if (this.state.requestedTopOfStack > 0) {
- this._tryLockNavigator(() => {
- const newRequestedTopOfStack = this.state.requestedTopOfStack - n;
- invariant(newRequestedTopOfStack >= 0, 'Cannot pop below 0');
- this.setState({
- requestedTopOfStack: newRequestedTopOfStack,
- makingNavigatorRequest: true,
- updatingAllIndicesAtOrBeyond: this.state.requestedTopOfStack - n,
- });
- });
- }
- }
- },
-
- /**
- * Pop back to the previous scene.
- */
- pop: function() {
- this.popN(1);
- },
-
- /**
- * Replace a route in the navigation stack.
- *
- * @param route The new route that will replace the specified one.
- * @param index The route into the stack that should be replaced.
- * If it is negative, it counts from the back of the stack.
- */
- replaceAtIndex: function(route: Route, index: number) {
- invariant(!!route, 'Must supply route to replace');
- if (index < 0) {
- index += this.state.routeStack.length;
- }
-
- if (this.state.routeStack.length <= index) {
- return;
- }
-
- // I don't believe we need to lock for a replace since there's no
- // navigation actually happening
- const nextIDStack = this.state.idStack.slice();
- const nextRouteStack = this.state.routeStack.slice();
- nextIDStack[index] = getuid();
- nextRouteStack[index] = route;
-
- this.setState({
- idStack: nextIDStack,
- routeStack: nextRouteStack,
- makingNavigatorRequest: false,
- updatingAllIndicesAtOrBeyond: index,
- });
- },
-
- /**
- * Replace the route for the current scene and immediately
- * load the view for the new route.
- * @param route The new route to navigate to.
- */
- replace: function(route: Route) {
- this.replaceAtIndex(route, -1);
- },
-
- /**
- * Replace the route/view for the previous scene.
- * @param route The new route to will replace the previous scene.
- */
- replacePrevious: function(route: Route) {
- this.replaceAtIndex(route, -2);
- },
-
- /**
- * Go back to the topmost item in the navigation stack.
- */
- popToTop: function() {
- this.popToRoute(this.state.routeStack[0]);
- },
-
- /**
- * Go back to the item for a particular route object.
- * @param route The new route to navigate to.
- */
- popToRoute: function(route: Route) {
- const indexOfRoute = this.state.routeStack.indexOf(route);
- invariant(
- indexOfRoute !== -1,
- "Calling pop to route for a route that doesn't exist!",
- );
- const numToPop = this.state.routeStack.length - indexOfRoute - 1;
- this.popN(numToPop);
- },
-
- /**
- * Replaces the previous route/view and transitions back to it.
- * @param route The new route that replaces the previous scene.
- */
- replacePreviousAndPop: function(route: Route) {
- // Make sure all previous requests are caught up first. Otherwise reject.
- if (this.state.requestedTopOfStack !== this.state.observedTopOfStack) {
- return;
- }
- if (this.state.routeStack.length < 2) {
- return;
- }
- this._tryLockNavigator(() => {
- this.replacePrevious(route);
- this.setState({
- requestedTopOfStack: this.state.requestedTopOfStack - 1,
- makingNavigatorRequest: true,
- });
- });
- },
-
- /**
- * Replaces the top item and pop to it.
- * @param route The new route that will replace the topmost item.
- */
- resetTo: function(route: Route) {
- invariant(!!route, 'Must supply route to push');
- // Make sure all previous requests are caught up first. Otherwise reject.
- if (this.state.requestedTopOfStack !== this.state.observedTopOfStack) {
- return;
- }
- this.replaceAtIndex(route, 0);
- this.popToRoute(route);
- },
-
- _handleNavigationComplete: function(e: Event) {
- // Don't propagate to other NavigatorIOS instances this is nested in:
- e.stopPropagation();
-
- if (this._toFocusOnNavigationComplete) {
- this._getFocusEmitter().emit('focus', this._toFocusOnNavigationComplete);
- this._toFocusOnNavigationComplete = null;
- }
- this._handleNavigatorStackChanged(e);
- },
-
- _routeToStackItem: function(routeArg: Route, i: number) {
- const {component, wrapperStyle, passProps, ...route} = routeArg;
- const {itemWrapperStyle, ...props} = this.props;
- const shouldUpdateChild =
- this.state.updatingAllIndicesAtOrBeyond != null &&
- this.state.updatingAllIndicesAtOrBeyond >= i;
- const Component = component;
- return (
- <StaticContainer key={'nav' + i} shouldUpdate={shouldUpdateChild}>
- <RCTNavigatorItem
- {...props}
- {...route}
- style={[styles.stackItem, itemWrapperStyle, wrapperStyle]}>
- <Component navigator={this.navigator} route={route} {...passProps} />
- </RCTNavigatorItem>
- </StaticContainer>
- );
- },
-
- _renderNavigationStackItems: function() {
- const shouldRecurseToNavigator =
- this.state.makingNavigatorRequest ||
- this.state.updatingAllIndicesAtOrBeyond !== null;
- // If not recursing update to navigator at all, may as well avoid
- // computation of navigator children.
- const items = shouldRecurseToNavigator
- ? this.state.routeStack.map(this._routeToStackItem)
- : null;
- return (
- <StaticContainer shouldUpdate={shouldRecurseToNavigator}>
- <NavigatorTransitionerIOS
- ref={TRANSITIONER_REF}
- style={styles.transitioner}
- // $FlowFixMe(>=0.41.0)
- vertical={this.props.vertical}
- requestedTopOfStack={this.state.requestedTopOfStack}
- onNavigationComplete={this._handleNavigationComplete}
- interactivePopGestureEnabled={
- this.props.interactivePopGestureEnabled
- }>
- {items}
- </NavigatorTransitionerIOS>
- </StaticContainer>
- );
- },
-
- _tvEventHandler: (undefined: ?TVEventHandler),
-
- _enableTVEventHandler: function() {
- this._tvEventHandler = new TVEventHandler();
- this._tvEventHandler.enable(this, function(cmp, evt) {
- if (evt && evt.eventType === 'menu') {
- cmp.pop();
- }
- });
- },
-
- _disableTVEventHandler: function() {
- if (this._tvEventHandler) {
- this._tvEventHandler.disable();
- delete this._tvEventHandler;
- }
- },
-
- render: function() {
- return (
- // $FlowFixMe(>=0.41.0)
- <View style={this.props.style}>{this._renderNavigationStackItems()}</View>
- );
- },
-});
-
-const styles = StyleSheet.create({
- stackItem: {
- backgroundColor: 'white',
- overflow: 'hidden',
- position: 'absolute',
- top: 0,
- left: 0,
- right: 0,
- bottom: 0,
- },
- transitioner: {
- flex: 1,
- },
-});
-
-const RCTNavigator = requireNativeComponent('RCTNavigator');
-const RCTNavigatorItem = requireNativeComponent('RCTNavItem');
-
-module.exports = NavigatorIOS;

Libraries/Components/Picker/AndroidDialogPickerNativeComponent.js

@@ -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.
+ *
+ * @format
+ * @flow
+ */
+
+'use strict';
+
+const requireNativeComponent = require('requireNativeComponent');
+
+import type {SyntheticEvent} from 'CoreEventTypes';
+import type {TextStyleProp} from 'StyleSheet';
+import type {NativeComponent} from 'ReactNative';
+
+type PickerAndroidChangeEvent = SyntheticEvent<
+ $ReadOnly<{|
+ position: number,
+ |}>,
+>;
+
+type Item = $ReadOnly<{|
+ label: string,
+ value: ?(number | string),
+ color?: ?number,
+|}>;
+
+type NativeProps = $ReadOnly<{|
+ enabled?: ?boolean,
+ items: $ReadOnlyArray<Item>,
+ mode?: ?('dialog' | 'dropdown'),
+ onSelect?: (event: PickerAndroidChangeEvent) => void,
+ selected: number,
+ prompt?: ?string,
+ testID?: string,
+ style?: ?TextStyleProp,
+ accessibilityLabel?: ?string,
+|}>;
+
+type DialogPickerNativeType = Class<NativeComponent<NativeProps>>;
+
+module.exports = ((requireNativeComponent(
+ 'AndroidDialogPicker',
+): any): DialogPickerNativeType);

Libraries/Components/Picker/AndroidDropdownPickerNativeComponent.js

@@ -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.
+ *
+ * @format
+ * @flow
+ */
+
+'use strict';
+
+const requireNativeComponent = require('requireNativeComponent');
+
+import type {SyntheticEvent} from 'CoreEventTypes';
+import type {TextStyleProp} from 'StyleSheet';
+import type {NativeComponent} from 'ReactNative';
+
+type PickerAndroidChangeEvent = SyntheticEvent<
+ $ReadOnly<{|
+ position: number,
+ |}>,
+>;
+
+type Item = $ReadOnly<{|
+ label: string,
+ value: ?(number | string),
+ color?: ?number,
+|}>;
+
+type NativeProps = $ReadOnly<{|
+ enabled?: ?boolean,
+ items: $ReadOnlyArray<Item>,
+ mode?: ?('dialog' | 'dropdown'),
+ onSelect?: (event: PickerAndroidChangeEvent) => void,
+ selected: number,
+ prompt?: ?string,
+ testID?: string,
+ style?: ?TextStyleProp,
+ accessibilityLabel?: ?string,
+|}>;
+
+type DropdownPickerNativeType = Class<NativeComponent<NativeProps>>;
+
+module.exports = ((requireNativeComponent(
+ 'AndroidDropdownPicker',
+): any): DropdownPickerNativeType);

Libraries/Components/Picker/PickerAndroid.android.js

@@ -1,38 +1,55 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
- * @flow
+ * @flow strict-local
*/
'use strict';
-const ColorPropType = require('ColorPropType');
+const AndroidDropdownPickerNativeComponent = require('AndroidDropdownPickerNativeComponent');
+const AndroidDialogPickerNativeComponent = require('AndroidDialogPickerNativeComponent');
const React = require('React');
-const ReactPropTypes = require('prop-types');
const StyleSheet = require('StyleSheet');
-const StyleSheetPropType = require('StyleSheetPropType');
-const ViewPropTypes = require('ViewPropTypes');
-const ViewStylePropTypes = require('ViewStylePropTypes');
const processColor = require('processColor');
-const requireNativeComponent = require('requireNativeComponent');
-
-const DropdownPicker = requireNativeComponent('AndroidDropdownPicker');
-const DialogPicker = requireNativeComponent('AndroidDialogPicker');
const REF_PICKER = 'picker';
const MODE_DROPDOWN = 'dropdown';
-const pickerStyleType = StyleSheetPropType({
- ...ViewStylePropTypes,
- color: ColorPropType,
-});
+import type {SyntheticEvent} from 'CoreEventTypes';
+import type {TextStyleProp} from 'StyleSheet';
+
+type PickerAndroidChangeEvent = SyntheticEvent<
+ $ReadOnly<{|
+ position: number,
+ |}>,
+>;
+
+type PickerAndroidProps = $ReadOnly<{|
+ children?: React.Node,
+ style?: ?TextStyleProp,
+ selectedValue?: ?(number | string),
+ enabled?: ?boolean,
+ mode?: ?('dialog' | 'dropdown'),
+ onValueChange?: ?(itemValue: ?(string | number), itemIndex: number) => mixed,
+ prompt?: ?string,
+ testID?: string,
+|}>;
-type Event = Object;
+type Item = $ReadOnly<{|
+ label: string,
+ value: ?(number | string),
+ color?: ?number,
+|}>;
+
+type PickerAndroidState = {|
+ selectedIndex: number,
+ items: $ReadOnlyArray<Item>,
+|};
/**
* Not exposed as a public API - use <Picker> instead.
@@ -37,51 +54,14 @@
/**
* Not exposed as a public API - use <Picker> instead.
*/
+
class PickerAndroid extends React.Component<
- {
- style?: $FlowFixMe,
- selectedValue?: any,
- enabled?: boolean,
- mode?: 'dialog' | 'dropdown',
- onValueChange?: Function,
- prompt?: string,
- testID?: string,
- },
- *,
+ PickerAndroidProps,
+ PickerAndroidState,
> {
- /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
- * when making Flow check .android.js files. */
- static propTypes = {
- ...ViewPropTypes,
- style: pickerStyleType,
- selectedValue: ReactPropTypes.any,
- enabled: ReactPropTypes.bool,
- mode: ReactPropTypes.oneOf(['dialog', 'dropdown']),
- onValueChange: ReactPropTypes.func,
- prompt: ReactPropTypes.string,
- testID: ReactPropTypes.string,
- };
-
- /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
- * when making Flow check .android.js files. */
- constructor(props, context) {
- super(props, context);
- const state = this._stateFromProps(props);
-
- this.state = {
- ...state,
- initialSelectedIndex: state.selectedIndex,
- };
- }
-
- /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
- * when making Flow check .android.js files. */
- UNSAFE_componentWillReceiveProps(nextProps) {
- this.setState(this._stateFromProps(nextProps));
- }
-
- // Translate prop and children into stuff that the native picker understands.
- _stateFromProps = props => {
+ static getDerivedStateFromProps(
+ props: PickerAndroidProps,
+ ): PickerAndroidState {
let selectedIndex = 0;
const items = React.Children.map(props.children, (child, index) => {
if (child.props.value === props.selectedValue) {
@@ -99,11 +79,15 @@
return childProps;
});
return {selectedIndex, items};
- };
+ }
+
+ state = PickerAndroid.getDerivedStateFromProps(this.props);
render() {
const Picker =
- this.props.mode === MODE_DROPDOWN ? DropdownPicker : DialogPicker;
+ this.props.mode === MODE_DROPDOWN
+ ? AndroidDropdownPickerNativeComponent
+ : AndroidDialogPickerNativeComponent;
const nativeProps = {
enabled: this.props.enabled,
@@ -111,7 +95,7 @@
mode: this.props.mode,
onSelect: this._onChange,
prompt: this.props.prompt,
- selected: this.state.initialSelectedIndex,
+ selected: this.state.selectedIndex,
testID: this.props.testID,
style: [styles.pickerAndroid, this.props.style],
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
@@ -122,12 +106,10 @@
return <Picker ref={REF_PICKER} {...nativeProps} />;
}
- _onChange = (event: Event) => {
+ _onChange = (event: PickerAndroidChangeEvent) => {
if (this.props.onValueChange) {
const position = event.nativeEvent.position;
if (position >= 0) {
- /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was
- * found when making Flow check .android.js files. */
const children = React.Children.toArray(this.props.children);
const value = children[position].props.value;
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was
@@ -137,19 +119,7 @@
this.props.onValueChange(null, position);
}
}
- /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
- * when making Flow check .android.js files. */
- this._lastNativePosition = event.nativeEvent.position;
- this.forceUpdate();
- };
-
- componentDidMount() {
- /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
- * when making Flow check .android.js files. */
- this._lastNativePosition = this.state.initialSelectedIndex;
- }
- componentDidUpdate() {
// The picker is a controlled component. This means we expect the
// on*Change handlers to be in charge of updating our
// `selectedValue` prop. That way they can also
@@ -158,18 +128,13 @@
// truth, not the native component.
if (
this.refs[REF_PICKER] &&
- /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
- * when making Flow check .android.js files. */
- this.state.selectedIndex !== this._lastNativePosition
+ this.state.selectedIndex !== event.nativeEvent.position
) {
this.refs[REF_PICKER].setNativeProps({
selected: this.state.selectedIndex,
});
- /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
- * when making Flow check .android.js files. */
- this._lastNativePosition = this.state.selectedIndex;
- }
}
+ };
}
const styles = StyleSheet.create({

Libraries/Components/Picker/PickerAndroid.ios.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/Picker/PickerIOS.android.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/Picker/PickerIOS.ios.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -18,7 +18,7 @@
const StyleSheet = require('StyleSheet');
const View = require('View');
const processColor = require('processColor');
-const requireNativeComponent = require('requireNativeComponent');
+const RCTPickerNativeComponent = require('RCTPickerNativeComponent');
import type {SyntheticEvent} from 'CoreEventTypes';
import type {ColorValue} from 'StyleSheetTypes';
@@ -27,14 +27,14 @@
type PickerIOSChangeEvent = SyntheticEvent<
$ReadOnly<{|
- newValue: any,
+ newValue: number | string,
newIndex: number,
|}>,
>;
type RCTPickerIOSItemType = $ReadOnly<{|
label: ?Label,
- value: ?any,
+ value: ?(number | string),
textColor: ?number,
|}>;
@@ -47,14 +47,11 @@
onStartShouldSetResponder: () => boolean,
selectedIndex: number,
style?: ?TextStyleProp,
+ testID?: ?string,
|}>,
>,
>;
-const RCTPickerIOS: RCTPickerIOSType = (requireNativeComponent(
- 'RCTPicker',
-): any);
-
type Label = Stringish | number;
type Props = $ReadOnly<{|
@@ -62,8 +59,8 @@
children: React.ChildrenArray<React.Element<typeof PickerIOSItem>>,
itemStyle?: ?TextStyleProp,
onChange?: ?(event: PickerIOSChangeEvent) => mixed,
- onValueChange?: ?(newValue: any, newIndex: number) => mixed,
- selectedValue: any,
+ onValueChange?: ?(itemValue: string | number, itemIndex: number) => mixed,
+ selectedValue: ?(number | string),
|}>;
type State = {|
@@ -73,7 +70,7 @@
type ItemProps = $ReadOnly<{|
label: ?Label,
- value?: ?any,
+ value?: ?(number | string),
color?: ?ColorValue,
|}>;
@@ -110,10 +107,11 @@
render() {
return (
<View style={this.props.style}>
- <RCTPickerIOS
+ <RCTPickerNativeComponent
ref={picker => {
this._picker = picker;
}}
+ testID={this.props.testID}
style={[styles.pickerIOS, this.props.itemStyle]}
items={this.state.items}
selectedIndex={this.state.selectedIndex}

Libraries/Components/Picker/Picker.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,120 +10,75 @@
'use strict';
-const ColorPropType = require('ColorPropType');
-const PickerIOS = require('PickerIOS');
const PickerAndroid = require('PickerAndroid');
+const PickerIOS = require('PickerIOS');
const Platform = require('Platform');
const React = require('React');
-const PropTypes = require('prop-types');
-const StyleSheetPropType = require('StyleSheetPropType');
-const TextStylePropTypes = require('TextStylePropTypes');
const UnimplementedView = require('UnimplementedView');
-const ViewPropTypes = require('ViewPropTypes');
-const ViewStylePropTypes = require('ViewStylePropTypes');
-
-const itemStylePropType = StyleSheetPropType(TextStylePropTypes);
-const pickerStyleType = StyleSheetPropType({
- ...ViewStylePropTypes,
- color: ColorPropType,
-});
+import type {TextStyleProp} from 'StyleSheet';
+import type {ColorValue} from 'StyleSheetTypes';
const MODE_DIALOG = 'dialog';
const MODE_DROPDOWN = 'dropdown';
-/**
- * Individual selectable item in a Picker.
- */
-class PickerItem extends React.Component<{
- label: string,
- value?: any,
- color?: ColorPropType,
- testID?: string,
-}> {
- static propTypes = {
+type PickerItemProps = $ReadOnly<{|
/**
* Text to display for this item.
*/
- label: PropTypes.string.isRequired,
+ label: string,
+
/**
* The value to be passed to picker's `onValueChange` callback when
* this item is selected. Can be a string or an integer.
*/
- value: PropTypes.any,
+ value?: ?(number | string),
+
/**
* Color of this item's text.
* @platform android
*/
- color: ColorPropType,
+ color?: ColorValue,
+
/**
* Used to locate the item in end-to-end tests.
*/
- testID: PropTypes.string,
- };
+ testID?: string,
+|}>;
+/**
+ * Individual selectable item in a Picker.
+ */
+class PickerItem extends React.Component<PickerItemProps> {
render() {
// The items are not rendered directly
throw null;
}
}
-/**
- * Renders the native picker component on iOS and Android. Example:
- *
- * <Picker
- * selectedValue={this.state.language}
- * onValueChange={(itemValue, itemIndex) => this.setState({language: itemValue})}>
- * <Picker.Item label="Java" value="java" />
- * <Picker.Item label="JavaScript" value="js" />
- * </Picker>
- */
-class Picker extends React.Component<{
- style?: $FlowFixMe,
- selectedValue?: any,
- onValueChange?: Function,
- enabled?: boolean,
- mode?: 'dialog' | 'dropdown',
- itemStyle?: $FlowFixMe,
- prompt?: string,
- testID?: string,
-}> {
- /**
- * On Android, display the options in a dialog.
- */
- static MODE_DIALOG = MODE_DIALOG;
-
- /**
- * On Android, display the options in a dropdown (this is the default).
- */
- static MODE_DROPDOWN = MODE_DROPDOWN;
-
- static Item = PickerItem;
-
- static defaultProps = {
- mode: MODE_DIALOG,
- };
+type PickerProps = $ReadOnly<{|
+ children?: React.Node,
+ style?: ?TextStyleProp,
- // $FlowFixMe(>=0.41.0)
- static propTypes = {
- ...ViewPropTypes,
- style: pickerStyleType,
/**
* Value matching value of one of the items. Can be a string or an integer.
*/
- selectedValue: PropTypes.any,
+ selectedValue?: ?(number | string),
+
/**
* Callback for when an item is selected. This is called with the following parameters:
* - `itemValue`: the `value` prop of the item that was selected
- * - `itemPosition`: the index of the selected item in this picker
+ * - `itemIndex`: the index of the selected item in this picker
*/
- onValueChange: PropTypes.func,
+ onValueChange?: ?(itemValue: string | number, itemIndex: number) => mixed,
+
/**
* If set to false, the picker will be disabled, i.e. the user will not be able to make a
* selection.
* @platform android
*/
- enabled: PropTypes.bool,
+ enabled?: ?boolean,
+
/**
* On Android, specifies how to display the selection items when the user taps on the picker:
*
@@ -132,30 +87,62 @@
*
* @platform android
*/
- mode: PropTypes.oneOf(['dialog', 'dropdown']),
+ mode?: ?('dialog' | 'dropdown'),
+
/**
* Style to apply to each of the item labels.
* @platform ios
*/
- itemStyle: itemStylePropType,
+ itemStyle?: ?TextStyleProp,
+
/**
* Prompt string for this picker, used on Android in dialog mode as the title of the dialog.
* @platform android
*/
- prompt: PropTypes.string,
+ prompt?: ?string,
+
/**
* Used to locate this view in end-to-end tests.
*/
- testID: PropTypes.string,
+ testID?: ?string,
+|}>;
+
+/**
+ * Renders the native picker component on iOS and Android. Example:
+ *
+ * <Picker
+ * selectedValue={this.state.language}
+ * onValueChange={(itemValue, itemIndex) => this.setState({language: itemValue})}>
+ * <Picker.Item label="Java" value="java" />
+ * <Picker.Item label="JavaScript" value="js" />
+ * </Picker>
+ */
+class Picker extends React.Component<PickerProps> {
+ /**
+ * On Android, display the options in a dialog.
+ */
+ static MODE_DIALOG = MODE_DIALOG;
+
+ /**
+ * On Android, display the options in a dropdown (this is the default).
+ */
+ static MODE_DROPDOWN = MODE_DROPDOWN;
+
+ static Item = PickerItem;
+
+ static defaultProps = {
+ mode: MODE_DIALOG,
};
render() {
if (Platform.OS === 'ios') {
- // $FlowFixMe found when converting React.createClass to ES6
+ /* $FlowFixMe(>=0.81.0 site=react_native_ios_fb) This suppression was
+ * added when renaming suppression sites. */
return <PickerIOS {...this.props}>{this.props.children}</PickerIOS>;
} else if (Platform.OS === 'android') {
return (
- // $FlowFixMe found when converting React.createClass to ES6
+ /* $FlowFixMe(>=0.81.0 site=react_native_android_fb) This suppression
+ * was added when renaming suppression sites. */
<PickerAndroid {...this.props}>{this.props.children}</PickerAndroid>
);
} else {

Libraries/Components/Picker/RCTPickerNativeComponent.js

@@ -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.
+ *
+ * @flow
+ * @format
+ */
+'use strict';
+
+const requireNativeComponent = require('requireNativeComponent');
+
+import type {SyntheticEvent} from 'CoreEventTypes';
+import type {TextStyleProp} from 'StyleSheet';
+import type {NativeComponent} from 'ReactNative';
+
+type PickerIOSChangeEvent = SyntheticEvent<
+ $ReadOnly<{|
+ newValue: number | string,
+ newIndex: number,
+ |}>,
+>;
+
+type RCTPickerIOSItemType = $ReadOnly<{|
+ label: ?Label,
+ value: ?(number | string),
+ textColor: ?number,
+|}>;
+
+type Label = Stringish | number;
+
+type RCTPickerIOSType = Class<
+ NativeComponent<
+ $ReadOnly<{|
+ items: $ReadOnlyArray<RCTPickerIOSItemType>,
+ onChange: (event: PickerIOSChangeEvent) => void,
+ onResponderTerminationRequest: () => boolean,
+ onStartShouldSetResponder: () => boolean,
+ selectedIndex: number,
+ style?: ?TextStyleProp,
+ testID?: ?string,
+ |}>,
+ >,
+>;
+
+module.exports = ((requireNativeComponent('RCTPicker'): any): RCTPickerIOSType);

Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -12,14 +12,11 @@
const React = require('React');
-const requireNativeComponent = require('requireNativeComponent');
+const ProgressBarAndroidNativeComponent = require('ProgressBarAndroidNativeComponent');
-import type {NativeComponent} from 'ReactNative';
import type {ViewProps} from 'ViewPropTypes';
-const AndroidProgressBar = requireNativeComponent('AndroidProgressBar');
-
-type Props = $ReadOnly<{|
+export type ProgressBarAndroidProps = $ReadOnly<{|
...ViewProps,
/**
@@ -83,19 +80,24 @@
* ```
*/
const ProgressBarAndroid = (
- props: Props,
- forwardedRef: ?React.Ref<'AndroidProgressBar'>,
+ props: ProgressBarAndroidProps,
+ forwardedRef: ?React.Ref<typeof ProgressBarAndroidNativeComponent>,
) => {
- return <AndroidProgressBar {...props} ref={forwardedRef} />;
+ return <ProgressBarAndroidNativeComponent {...props} ref={forwardedRef} />;
};
-// $FlowFixMe - TODO T29156721 `React.forwardRef` is not defined in Flow, yet.
const ProgressBarAndroidToExport = React.forwardRef(ProgressBarAndroid);
+/* $FlowFixMe(>=0.89.0 site=react_native_android_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
ProgressBarAndroidToExport.defaultProps = {
styleAttr: 'Normal',
indeterminate: true,
animating: true,
};
-module.exports = (ProgressBarAndroidToExport: Class<NativeComponent<Props>>);
+/* $FlowFixMe(>=0.89.0 site=react_native_android_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
+module.exports = (ProgressBarAndroidToExport: ProgressBarAndroidNativeComponent);

Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.ios.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/ProgressBarAndroid/ProgressBarAndroidNativeComponent.js

@@ -0,0 +1,33 @@
+/**
+ * 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.
+ *
+ * @flow
+ * @format
+ */
+
+'use strict';
+
+const requireNativeComponent = require('requireNativeComponent');
+
+import type {ViewProps} from 'ViewPropTypes';
+import type {NativeComponent} from 'ReactNative';
+
+type NativeProps = $ReadOnly<{|
+ ...ViewProps,
+ styleAttr?: string,
+ typeAttr?: string,
+ indeterminate: boolean,
+ progress?: number,
+ animating?: ?boolean,
+ color?: ?string,
+ testID?: ?string,
+|}>;
+
+type ProgressBarAndroidType = Class<NativeComponent<NativeProps>>;
+
+module.exports = ((requireNativeComponent(
+ 'AndroidProgressBar',
+): any): ProgressBarAndroidType);

Libraries/Components/ProgressViewIOS/ProgressViewIOS.android.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/ProgressViewIOS/ProgressViewIOS.ios.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,82 +10,62 @@
'use strict';
-const Image = require('Image');
-const NativeMethodsMixin = require('NativeMethodsMixin');
const React = require('React');
-const ReactNative = require('ReactNative');
-const PropTypes = require('prop-types');
const StyleSheet = require('StyleSheet');
-const ViewPropTypes = require('ViewPropTypes');
-const createReactClass = require('create-react-class');
-const requireNativeComponent = require('requireNativeComponent');
+const RCTProgressViewNativeComponent = require('RCTProgressViewNativeComponent');
import type {ImageSource} from 'ImageSource';
import type {ColorValue} from 'StyleSheetTypes';
import type {ViewProps} from 'ViewPropTypes';
-const RCTProgressView = requireNativeComponent('RCTProgressView');
-
type Props = $ReadOnly<{|
...ViewProps,
- progressViewStyle?: ?('default' | 'bar'),
- progress?: ?number,
- progressTintColor?: ?ColorValue,
- trackTintColor?: ?string,
- progressImage?: ?ImageSource,
- trackImage?: ?ImageSource,
-|}>;
-
-/**
- * Use `ProgressViewIOS` to render a UIProgressView on iOS.
- */
-const ProgressViewIOS = createReactClass({
- displayName: 'ProgressViewIOS',
- mixins: [NativeMethodsMixin],
- propTypes: {
- ...ViewPropTypes,
/**
* The progress bar style.
*/
- progressViewStyle: PropTypes.oneOf(['default', 'bar']),
+ progressViewStyle?: ?('default' | 'bar'),
/**
* The progress value (between 0 and 1).
*/
- progress: PropTypes.number,
+ progress?: ?number,
/**
* The tint color of the progress bar itself.
*/
- progressTintColor: PropTypes.string,
+ progressTintColor?: ?ColorValue,
/**
* The tint color of the progress bar track.
*/
- trackTintColor: PropTypes.string,
+ trackTintColor?: ?ColorValue,
/**
* A stretchable image to display as the progress bar.
*/
- progressImage: Image.propTypes.source,
+ progressImage?: ?ImageSource,
/**
* A stretchable image to display behind the progress bar.
*/
- trackImage: Image.propTypes.source,
- },
+ trackImage?: ?ImageSource,
+|}>;
- render: function() {
- return (
- <RCTProgressView
- {...this.props}
- style={[styles.progressView, this.props.style]}
+/**
+ * Use `ProgressViewIOS` to render a UIProgressView on iOS.
+ */
+const ProgressViewIOS = (
+ props: Props,
+ forwardedRef?: ?React.Ref<typeof RCTProgressViewNativeComponent>,
+) => (
+ <RCTProgressViewNativeComponent
+ {...props}
+ style={[styles.progressView, props.style]}
+ ref={forwardedRef}
/>
- );
- },
-});
+);
const styles = StyleSheet.create({
progressView: {
@@ -93,6 +73,9 @@
},
});
-module.exports = ((ProgressViewIOS: any): Class<
- ReactNative.NativeComponent<Props>,
->);
+const ProgressViewIOSWithRef = React.forwardRef(ProgressViewIOS);
+
+/* $FlowFixMe(>=0.89.0 site=react_native_ios_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
+module.exports = (ProgressViewIOSWithRef: RCTProgressViewNativeComponent);

Libraries/Components/ProgressViewIOS/RCTProgressViewNativeComponent.js

@@ -0,0 +1,34 @@
+/**
+ * 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.
+ *
+ * @flow
+ * @format
+ */
+
+'use strict';
+
+const requireNativeComponent = require('requireNativeComponent');
+
+import type {NativeComponent} from 'ReactNative';
+import type {ImageSource} from 'ImageSource';
+import type {ColorValue} from 'StyleSheetTypes';
+import type {ViewProps} from 'ViewPropTypes';
+
+type NativeProps = $ReadOnly<{|
+ ...ViewProps,
+ progressViewStyle?: ?('default' | 'bar'),
+ progress?: ?number,
+ progressTintColor?: ?ColorValue,
+ trackTintColor?: ?ColorValue,
+ progressImage?: ?ImageSource,
+ trackImage?: ?ImageSource,
+|}>;
+
+type NativeProgressViewIOS = Class<NativeComponent<NativeProps>>;
+
+module.exports = ((requireNativeComponent(
+ 'RCTProgressView',
+): any): NativeProgressViewIOS);

Libraries/Components/RefreshControl/AndroidSwipeRefreshLayoutNativeComponent.js

@@ -0,0 +1,68 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow
+ */
+
+'use strict';
+
+const requireNativeComponent = require('requireNativeComponent');
+
+import type {ColorValue} from 'StyleSheetTypes';
+import type {ViewProps} from 'ViewPropTypes';
+import type {NativeComponent} from 'ReactNative';
+
+const AndroidSwipeRefreshLayout = require('UIManager').getViewManagerConfig(
+ 'AndroidSwipeRefreshLayout',
+);
+const RefreshLayoutConsts = AndroidSwipeRefreshLayout
+ ? AndroidSwipeRefreshLayout.Constants
+ : {SIZE: {}};
+
+type NativeProps = $ReadOnly<{|
+ ...ViewProps,
+
+ /**
+ * Whether the pull to refresh functionality is enabled.
+ */
+ enabled?: ?boolean,
+ /**
+ * The colors (at least one) that will be used to draw the refresh indicator.
+ */
+ colors?: ?$ReadOnlyArray<ColorValue>,
+ /**
+ * The background color of the refresh indicator.
+ */
+ progressBackgroundColor?: ?ColorValue,
+ /**
+ * Size of the refresh indicator, see RefreshControl.SIZE.
+ */
+ size?: ?(
+ | typeof RefreshLayoutConsts.SIZE.DEFAULT
+ | typeof RefreshLayoutConsts.SIZE.LARGE
+ ),
+ /**
+ * Progress view top offset
+ */
+ progressViewOffset?: ?number,
+
+ /**
+ * Called when the view starts refreshing.
+ */
+ onRefresh?: ?() => mixed,
+
+ /**
+ * Whether the view should be indicating an active refresh.
+ */
+ refreshing: boolean,
+|}>;
+
+type AndroidSwipeRefreshLayoutNativeType = Class<NativeComponent<NativeProps>>;
+
+module.exports = ((requireNativeComponent(
+ 'AndroidSwipeRefreshLayout',
+): any): AndroidSwipeRefreshLayoutNativeType);

Libraries/Components/RefreshControl/__mocks__/RefreshControlMock.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/RefreshControl/RCTRefreshControlNativeComponent.js

@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow
+ */
+
+'use strict';
+
+const requireNativeComponent = require('requireNativeComponent');
+
+import type {ColorValue} from 'StyleSheetTypes';
+import type {ViewProps} from 'ViewPropTypes';
+import type {NativeComponent} from 'ReactNative';
+
+export type NativeProps = $ReadOnly<{|
+ ...ViewProps,
+
+ /**
+ * The color of the refresh indicator.
+ */
+ tintColor?: ?ColorValue,
+ /**
+ * Title color.
+ */
+ titleColor?: ?ColorValue,
+ /**
+ * The title displayed under the refresh indicator.
+ */
+ title?: ?string,
+
+ /**
+ * Called when the view starts refreshing.
+ */
+ onRefresh?: ?() => mixed,
+
+ /**
+ * Whether the view should be indicating an active refresh.
+ */
+ refreshing: boolean,
+|}>;
+
+type RCTRefreshControlNativeType = Class<NativeComponent<NativeProps>>;
+
+module.exports = ((requireNativeComponent(
+ 'RCTRefreshControl',
+): any): RCTRefreshControlNativeType);

Libraries/Components/RefreshControl/RefreshControl.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -14,27 +14,24 @@
const React = require('React');
const {NativeComponent} = require('ReactNative');
-const requireNativeComponent = require('requireNativeComponent');
-const nullthrows = require('fbjs/lib/nullthrows');
+const AndroidSwipeRefreshLayoutNativeComponent = require('AndroidSwipeRefreshLayoutNativeComponent');
+const RCTRefreshControlNativeComponent = require('RCTRefreshControlNativeComponent');
+const nullthrows = require('nullthrows');
import type {ColorValue} from 'StyleSheetTypes';
import type {ViewProps} from 'ViewPropTypes';
+let RefreshLayoutConsts;
if (Platform.OS === 'android') {
- const AndroidSwipeRefreshLayout = require('UIManager')
- .AndroidSwipeRefreshLayout;
- var RefreshLayoutConsts = AndroidSwipeRefreshLayout
+ const AndroidSwipeRefreshLayout = require('UIManager').getViewManagerConfig(
+ 'AndroidSwipeRefreshLayout',
+ );
+ RefreshLayoutConsts = AndroidSwipeRefreshLayout
? AndroidSwipeRefreshLayout.Constants
: {SIZE: {}};
} else {
- var RefreshLayoutConsts = {SIZE: {}};
+ RefreshLayoutConsts = {SIZE: {}};
}
-type NativeRefreshControlType = Class<NativeComponent<RefreshControlProps>>;
-
-const NativeRefreshControl: NativeRefreshControlType =
- Platform.OS === 'ios'
- ? (requireNativeComponent('RCTRefreshControl'): any)
- : (requireNativeComponent('AndroidSwipeRefreshLayout'): any);
type IOSProps = $ReadOnly<{|
/**
@@ -85,7 +82,7 @@
/**
* Called when the view starts refreshing.
*/
- onRefresh?: ?Function,
+ onRefresh?: ?() => mixed,
/**
* Whether the view should be indicating an active refresh.
@@ -141,7 +138,7 @@
class RefreshControl extends React.Component<RefreshControlProps> {
static SIZE = RefreshLayoutConsts.SIZE;
- _nativeRef: ?React.ElementRef<NativeRefreshControlType> = null;
+ _setNativePropsOnRef: ?({refreshing: boolean}) => void;
_lastNativeRefreshing = false;
componentDidMount() {
@@ -154,8 +151,11 @@
// the js value.
if (this.props.refreshing !== prevProps.refreshing) {
this._lastNativeRefreshing = this.props.refreshing;
- } else if (this.props.refreshing !== this._lastNativeRefreshing) {
- nullthrows(this._nativeRef).setNativeProps({
+ } else if (
+ this.props.refreshing !== this._lastNativeRefreshing &&
+ this._setNativePropsOnRef
+ ) {
+ this._setNativePropsOnRef({
refreshing: this.props.refreshing,
});
this._lastNativeRefreshing = this.props.refreshing;
@@ -163,15 +163,34 @@
}
render() {
+ const setRef = ref =>
+ (this._setNativePropsOnRef = ref ? ref.setNativeProps.bind(ref) : null);
+ if (Platform.OS === 'ios') {
+ const {
+ enabled,
+ colors,
+ progressBackgroundColor,
+ size,
+ progressViewOffset,
+ ...props
+ } = this.props;
return (
- <NativeRefreshControl
- {...this.props}
- ref={ref => {
- this._nativeRef = ref;
- }}
+ <RCTRefreshControlNativeComponent
+ {...props}
+ ref={setRef}
onRefresh={this._onRefresh}
/>
);
+ } else {
+ const {tintColor, titleColor, title, ...props} = this.props;
+ return (
+ <AndroidSwipeRefreshLayoutNativeComponent
+ {...props}
+ ref={setRef}
+ onRefresh={this._onRefresh}
+ />
+ );
+ }
}
_onRefresh = () => {

Libraries/Components/SafeAreaView/RCTSafeAreaViewNativeComponent.js

@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow
+ */
+
+const requireNativeComponent = require('requireNativeComponent');
+
+import type {ViewProps} from 'ViewPropTypes';
+import type {NativeComponent} from 'ReactNative';
+
+type NativeProps = $ReadOnly<{|
+ ...ViewProps,
+ emulateUnlessSupported?: boolean,
+|}>;
+
+type RCTSafeAreaViewNativeType = Class<NativeComponent<NativeProps>>;
+
+module.exports = ((requireNativeComponent(
+ 'RCTSafeAreaView',
+): any): RCTSafeAreaViewNativeType);

Libraries/Components/SafeAreaView/SafeAreaView.android.js

@@ -1,13 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow
- */
-
-'use strict';
-
-module.exports = require('View');

Libraries/Components/SafeAreaView/SafeAreaView.ios.js

@@ -1,39 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @flow
- * @format
- */
-
-const React = require('React');
-const ViewPropTypes = require('ViewPropTypes');
-const requireNativeComponent = require('requireNativeComponent');
-
-import type {ViewProps} from 'ViewPropTypes';
-
-const RCTSafeAreaView = requireNativeComponent('RCTSafeAreaView');
-
-type Props = ViewProps & {
- children: any,
-};
-
-/**
- * Renders nested content and automatically applies paddings reflect the portion of the view
- * that is not covered by navigation bars, tab bars, toolbars, and other ancestor views.
- * Moreover, and most importantly, Safe Area's paddings reflect physical limitation of the screen,
- * such as rounded corners or camera notches (aka sensor housing area on iPhone X).
- */
-class SafeAreaView extends React.Component<Props> {
- static propTypes = {
- ...ViewPropTypes,
- };
-
- render() {
- return <RCTSafeAreaView {...this.props} />;
- }
-}
-
-module.exports = SafeAreaView;

Libraries/Components/SafeAreaView/SafeAreaView.js

@@ -0,0 +1,54 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @flow strict-local
+ * @format
+ */
+
+const Platform = require('Platform');
+const React = require('React');
+const View = require('View');
+
+import type {ViewProps} from 'ViewPropTypes';
+
+type Props = $ReadOnly<{|
+ ...ViewProps,
+ emulateUnlessSupported?: boolean,
+|}>;
+
+let exported;
+
+/**
+ * Renders nested content and automatically applies paddings reflect the portion
+ * of the view that is not covered by navigation bars, tab bars, toolbars, and
+ * other ancestor views.
+ *
+ * Moreover, and most importantly, Safe Area's paddings reflect physical
+ * limitation of the screen, such as rounded corners or camera notches (aka
+ * sensor housing area on iPhone X).
+ */
+if (Platform.OS === 'android') {
+ exported = class SafeAreaView extends React.Component<Props> {
+ render(): React.Node {
+ const {emulateUnlessSupported, ...props} = this.props;
+ return <View {...props} />;
+ }
+ };
+} else {
+ const RCTSafeAreaViewNativeComponent = require('RCTSafeAreaViewNativeComponent');
+ exported = class SafeAreaView extends React.Component<Props> {
+ render(): React.Node {
+ return (
+ <RCTSafeAreaViewNativeComponent
+ emulateUnlessSupported={true}
+ {...this.props}
+ />
+ );
+ }
+ };
+}
+
+module.exports = exported;

Libraries/Components/ScrollResponder.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -14,17 +14,20 @@
const FrameRateLogger = require('FrameRateLogger');
const Keyboard = require('Keyboard');
const ReactNative = require('ReactNative');
-const Subscribable = require('Subscribable');
const TextInputState = require('TextInputState');
const UIManager = require('UIManager');
-const invariant = require('fbjs/lib/invariant');
-const nullthrows = require('fbjs/lib/nullthrows');
+const invariant = require('invariant');
+const nullthrows = require('nullthrows');
const performanceNow = require('fbjs/lib/performanceNow');
const warning = require('fbjs/lib/warning');
const {ScrollViewManager} = require('NativeModules');
+import type {PressEvent, ScrollEvent} from 'CoreEventTypes';
+import type {KeyboardEvent} from 'Keyboard';
+import type EmitterSubscription from 'EmitterSubscription';
+
/**
* Mixin that can be integrated in order to handle scrolling that plays well
* with `ResponderEventPlugin`. Integrate with your platform specific scroll
@@ -105,17 +108,19 @@
const IS_ANIMATING_TOUCH_START_THRESHOLD_MS = 16;
-type State = {
+export type State = {|
isTouching: boolean,
lastMomentumScrollBeginTime: number,
lastMomentumScrollEndTime: number,
observedScrollSinceBecomingResponder: boolean,
becameResponderWhileAnimating: boolean,
-};
-type Event = Object;
+|};
const ScrollResponderMixin = {
- mixins: [Subscribable.Mixin],
+ _subscriptionKeyboardWillShow: (null: ?EmitterSubscription),
+ _subscriptionKeyboardWillHide: (null: ?EmitterSubscription),
+ _subscriptionKeyboardDidShow: (null: ?EmitterSubscription),
+ _subscriptionKeyboardDidHide: (null: ?EmitterSubscription),
scrollResponderMixinGetInitialState: function(): State {
return {
isTouching: false,
@@ -164,7 +169,9 @@
* true.
*
*/
- scrollResponderHandleStartShouldSetResponder: function(e: Event): boolean {
+ scrollResponderHandleStartShouldSetResponder: function(
+ e: PressEvent,
+ ): boolean {
const currentlyFocusedTextInput = TextInputState.currentlyFocusedField();
if (
@@ -189,7 +196,7 @@
* Invoke this from an `onStartShouldSetResponderCapture` event.
*/
scrollResponderHandleStartShouldSetResponderCapture: function(
- e: Event,
+ e: PressEvent,
): boolean {
// The scroll view should receive taps instead of its descendants if:
// * it is already animating/decelerating
@@ -208,6 +215,7 @@
if (
keyboardNeverPersistTaps &&
currentlyFocusedTextInput != null &&
+ e.target &&
!TextInputState.isTextInput(e.target)
) {
return true;
@@ -250,9 +258,9 @@
/**
* Invoke this from an `onTouchEnd` event.
*
- * @param {SyntheticEvent} e Event.
+ * @param {PressEvent} e Event.
*/
- scrollResponderHandleTouchEnd: function(e: Event) {
+ scrollResponderHandleTouchEnd: function(e: PressEvent) {
const nativeEvent = e.nativeEvent;
this.state.isTouching = nativeEvent.touches.length !== 0;
this.props.onTouchEnd && this.props.onTouchEnd(e);
@@ -261,9 +269,9 @@
/**
* Invoke this from an `onTouchCancel` event.
*
- * @param {SyntheticEvent} e Event.
+ * @param {PressEvent} e Event.
*/
- scrollResponderHandleTouchCancel: function(e: Event) {
+ scrollResponderHandleTouchCancel: function(e: PressEvent) {
this.state.isTouching = false;
this.props.onTouchCancel && this.props.onTouchCancel(e);
},
@@ -271,7 +279,7 @@
/**
* Invoke this from an `onResponderRelease` event.
*/
- scrollResponderHandleResponderRelease: function(e: Event) {
+ scrollResponderHandleResponderRelease: function(e: PressEvent) {
this.props.onResponderRelease && this.props.onResponderRelease(e);
// By default scroll views will unfocus a textField
@@ -291,7 +299,7 @@
}
},
- scrollResponderHandleScroll: function(e: Event) {
+ scrollResponderHandleScroll: function(e: ScrollEvent) {
this.state.observedScrollSinceBecomingResponder = true;
this.props.onScroll && this.props.onScroll(e);
},
@@ -299,7 +307,7 @@
/**
* Invoke this from an `onResponderGrant` event.
*/
- scrollResponderHandleResponderGrant: function(e: Event) {
+ scrollResponderHandleResponderGrant: function(e: ScrollEvent) {
this.state.observedScrollSinceBecomingResponder = false;
this.props.onResponderGrant && this.props.onResponderGrant(e);
this.state.becameResponderWhileAnimating = this.scrollResponderIsAnimating();
@@ -312,7 +320,7 @@
*
* Invoke this from an `onScrollBeginDrag` event.
*/
- scrollResponderHandleScrollBeginDrag: function(e: Event) {
+ scrollResponderHandleScrollBeginDrag: function(e: ScrollEvent) {
FrameRateLogger.beginScroll(); // TODO: track all scrolls after implementing onScrollEndAnimation
this.props.onScrollBeginDrag && this.props.onScrollBeginDrag(e);
},
@@ -320,7 +328,7 @@
/**
* Invoke this from an `onScrollEndDrag` event.
*/
- scrollResponderHandleScrollEndDrag: function(e: Event) {
+ scrollResponderHandleScrollEndDrag: function(e: ScrollEvent) {
const {velocity} = e.nativeEvent;
// - If we are animating, then this is a "drag" that is stopping the scrollview and momentum end
// will fire.
@@ -339,7 +347,7 @@
/**
* Invoke this from an `onMomentumScrollBegin` event.
*/
- scrollResponderHandleMomentumScrollBegin: function(e: Event) {
+ scrollResponderHandleMomentumScrollBegin: function(e: ScrollEvent) {
this.state.lastMomentumScrollBeginTime = performanceNow();
this.props.onMomentumScrollBegin && this.props.onMomentumScrollBegin(e);
},
@@ -347,7 +355,7 @@
/**
* Invoke this from an `onMomentumScrollEnd` event.
*/
- scrollResponderHandleMomentumScrollEnd: function(e: Event) {
+ scrollResponderHandleMomentumScrollEnd: function(e: ScrollEvent) {
FrameRateLogger.endScroll();
this.state.lastMomentumScrollEndTime = performanceNow();
this.props.onMomentumScrollEnd && this.props.onMomentumScrollEnd(e);
@@ -362,9 +370,9 @@
* responder). The `onResponderReject` won't fire in that case - it only
* fires when a *current* responder rejects our request.
*
- * @param {SyntheticEvent} e Touch Start event.
+ * @param {PressEvent} e Touch Start event.
*/
- scrollResponderHandleTouchStart: function(e: Event) {
+ scrollResponderHandleTouchStart: function(e: PressEvent) {
this.state.isTouching = true;
this.props.onTouchStart && this.props.onTouchStart(e);
},
@@ -378,9 +386,9 @@
* responder). The `onResponderReject` won't fire in that case - it only
* fires when a *current* responder rejects our request.
*
- * @param {SyntheticEvent} e Touch Start event.
+ * @param {PressEvent} e Touch Start event.
*/
- scrollResponderHandleTouchMove: function(e: Event) {
+ scrollResponderHandleTouchMove: function(e: PressEvent) {
this.props.onTouchMove && this.props.onTouchMove(e);
},
@@ -405,7 +413,7 @@
* Components can pass what node to use by defining a `getScrollableNode`
* function otherwise `this` is used.
*/
- scrollResponderGetScrollableNode: function(): any {
+ scrollResponderGetScrollableNode: function(): ?number {
return this.getScrollableNode
? this.getScrollableNode()
: ReactNative.findNodeHandle(this);
@@ -436,7 +444,7 @@
}
UIManager.dispatchViewManagerCommand(
nullthrows(this.scrollResponderGetScrollableNode()),
- UIManager.RCTScrollView.Commands.scrollTo,
+ UIManager.getViewManagerConfig('RCTScrollView').Commands.scrollTo,
[x || 0, y || 0, animated !== false],
);
},
@@ -454,7 +462,7 @@
const animated = (options && options.animated) !== false;
UIManager.dispatchViewManagerCommand(
this.scrollResponderGetScrollableNode(),
- UIManager.RCTScrollView.Commands.scrollToEnd,
+ UIManager.getViewManagerConfig('RCTScrollView').Commands.scrollToEnd,
[animated],
);
},
@@ -513,7 +521,8 @@
scrollResponderFlashScrollIndicators: function() {
UIManager.dispatchViewManagerCommand(
this.scrollResponderGetScrollableNode(),
- UIManager.RCTScrollView.Commands.flashScrollIndicators,
+ UIManager.getViewManagerConfig('RCTScrollView').Commands
+ .flashScrollIndicators,
[],
);
},
@@ -522,14 +531,14 @@
* This method should be used as the callback to onFocus in a TextInputs'
* parent view. Note that any module using this mixin needs to return
* the parent view's ref in getScrollViewRef() in order to use this method.
- * @param {any} nodeHandle The TextInput node handle
+ * @param {number} nodeHandle The TextInput node handle
* @param {number} additionalOffset The scroll view's bottom "contentInset".
* Default is 0.
* @param {bool} preventNegativeScrolling Whether to allow pulling the content
* down to make it meet the keyboard's top. Default is false.
*/
scrollResponderScrollNativeHandleToKeyboard: function(
- nodeHandle: any,
+ nodeHandle: number,
additionalOffset?: number,
preventNegativeScrollOffset?: boolean,
) {
@@ -579,8 +588,8 @@
this.preventNegativeScrollOffset = false;
},
- scrollResponderTextInputFocusError: function(e: Event) {
- console.error('Error measuring text field: ', e);
+ scrollResponderTextInputFocusError: function(msg: string) {
+ console.error('Error measuring text field: ', msg);
},
/**
@@ -601,28 +610,40 @@
this.keyboardWillOpenTo = null;
this.additionalScrollOffset = 0;
- this.addListenerOn(
- Keyboard,
+ this._subscriptionKeyboardWillShow = Keyboard.addListener(
'keyboardWillShow',
this.scrollResponderKeyboardWillShow,
);
- this.addListenerOn(
- Keyboard,
+
+ this._subscriptionKeyboardWillHide = Keyboard.addListener(
'keyboardWillHide',
this.scrollResponderKeyboardWillHide,
);
- this.addListenerOn(
- Keyboard,
+ this._subscriptionKeyboardDidShow = Keyboard.addListener(
'keyboardDidShow',
this.scrollResponderKeyboardDidShow,
);
- this.addListenerOn(
- Keyboard,
+ this._subscriptionKeyboardDidHide = Keyboard.addListener(
'keyboardDidHide',
this.scrollResponderKeyboardDidHide,
);
},
+ componentWillUnmount: function() {
+ if (this._subscriptionKeyboardWillShow != null) {
+ this._subscriptionKeyboardWillShow.remove();
+ }
+ if (this._subscriptionKeyboardWillHide != null) {
+ this._subscriptionKeyboardWillHide.remove();
+ }
+ if (this._subscriptionKeyboardDidShow != null) {
+ this._subscriptionKeyboardDidShow.remove();
+ }
+ if (this._subscriptionKeyboardDidHide != null) {
+ this._subscriptionKeyboardDidHide.remove();
+ }
+ },
+
/**
* Warning, this may be called several times for a single keyboard opening.
* It's best to store the information in this method and then take any action
@@ -651,17 +672,17 @@
* relevant to you. (For example, only if you receive these callbacks after
* you had explicitly focused a node etc).
*/
- scrollResponderKeyboardWillShow: function(e: Event) {
+ scrollResponderKeyboardWillShow: function(e: KeyboardEvent) {
this.keyboardWillOpenTo = e;
this.props.onKeyboardWillShow && this.props.onKeyboardWillShow(e);
},
- scrollResponderKeyboardWillHide: function(e: Event) {
+ scrollResponderKeyboardWillHide: function(e: KeyboardEvent) {
this.keyboardWillOpenTo = null;
this.props.onKeyboardWillHide && this.props.onKeyboardWillHide(e);
},
- scrollResponderKeyboardDidShow: function(e: Event) {
+ scrollResponderKeyboardDidShow: function(e: KeyboardEvent) {
// TODO(7693961): The event for DidShow is not available on iOS yet.
// Use the one from WillShow and do not assign.
if (e) {
@@ -670,7 +691,7 @@
this.props.onKeyboardDidShow && this.props.onKeyboardDidShow(e);
},
- scrollResponderKeyboardDidHide: function(e: Event) {
+ scrollResponderKeyboardDidHide: function(e: KeyboardEvent) {
this.keyboardWillOpenTo = null;
this.props.onKeyboardDidHide && this.props.onKeyboardDidHide(e);
},

Libraries/Components/ScrollView/InternalScrollViewType.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/ScrollView/__mocks__/ScrollViewMock.js

@@ -1,19 +1,17 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
- * @flow
+ * @flow strict-local
*/
/* eslint-env jest */
'use strict';
-declare var jest: any;
-
const React = require('React');
const View = require('View');

Libraries/Components/ScrollView/processDecelerationRate.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/ScrollView/ScrollView.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -20,13 +20,11 @@
const View = require('View');
const InternalScrollViewType = require('InternalScrollViewType');
-const createReactClass = require('create-react-class');
const dismissKeyboard = require('dismissKeyboard');
const flattenStyle = require('flattenStyle');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
const processDecelerationRate = require('processDecelerationRate');
const requireNativeComponent = require('requireNativeComponent');
-const warning = require('fbjs/lib/warning');
const resolveAssetSource = require('resolveAssetSource');
import type {PressEvent} from 'CoreEventTypes';
@@ -37,6 +35,7 @@
import type {PointProp} from 'PointPropType';
import type {ColorValue} from 'StyleSheetTypes';
+import type {State as ScrollResponderState} from 'ScrollResponder';
let AndroidScrollView;
let AndroidHorizontalScrollContentView;
@@ -212,12 +211,23 @@
*/
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.
* @platform ios
*/
scrollsToTop?: ?boolean,
/**
+ * Fires when the scroll view scrolls to top after the status bar has been tapped
+ * @platform ios
+ */
+ onScrollToTop?: ?Function,
+ /**
* When true, shows a horizontal scroll indicator.
* The default value is true.
*/
@@ -297,6 +307,13 @@
* @platform android
*/
overScrollMode?: ?('auto' | 'always' | 'never'),
+ /**
+ * Causes the scrollbars not to turn transparent when they are not in use.
+ * The default value is false.
+ *
+ * @platform android
+ */
+ persistentScrollbar?: ?boolean,
|}>;
type VRProps = $ReadOnly<{|
@@ -392,7 +409,9 @@
* - `false`, deprecated, use 'never' instead
* - `true`, deprecated, use 'always' instead
*/
- // $FlowFixMe(site=react_native_fb) Issues found when typing ScrollView
+ /* $FlowFixMe(>=0.92.0 site=react_native_fb) This comment suppresses an error
+ * found when Flow v0.92 was deployed. To see the error, delete this comment
+ * and run Flow. */
keyboardShouldPersistTaps?: ?('always' | 'never' | 'handled' | false | true),
/**
* Called when the momentum scroll starts (scroll which occurs as the ScrollView glides to a stop).
@@ -475,6 +495,22 @@
*/
snapToOffsets?: ?$ReadOnlyArray<number>,
/**
+ * Use in conjuction with `snapToOffsets`. By default, the beginning
+ * of the list counts as a snap offset. Set `snapToStart` to false to disable
+ * this behavior and allow the list to scroll freely between its start and
+ * the first `snapToOffsets` offset.
+ * The default value is true.
+ */
+ snapToStart?: ?boolean,
+ /**
+ * Use in conjuction with `snapToOffsets`. By default, the end
+ * of the list counts as a snap offset. Set `snapToEnd` to false to disable
+ * this behavior and allow the list to scroll freely between its end and
+ * the last `snapToOffsets` offset.
+ * The default value is true.
+ */
+ snapToEnd?: ?boolean,
+ /**
* Experimental: When true, offscreen child views (whose `overflow` value is
* `hidden`) are removed from their native backing superview when offscreen.
* This can improve scrolling performance on long lists. The default value is
@@ -489,10 +525,28 @@
* See [RefreshControl](docs/refreshcontrol.html).
*/
refreshControl?: ?React.Element<any>,
- style?: ?ViewStyleProp,
children?: React.Node,
|}>;
+type State = {|
+ layoutHeight: ?number,
+ ...ScrollResponderState,
+|};
+
+function createScrollResponder(
+ node: React.ElementRef<typeof ScrollView>,
+): typeof ScrollResponder.Mixin {
+ const scrollResponder = {...ScrollResponder.Mixin};
+
+ for (const key in scrollResponder) {
+ if (typeof scrollResponder[key] === 'function') {
+ scrollResponder[key] = scrollResponder[key].bind(node);
+ }
+ }
+
+ return scrollResponder;
+}
+
/**
* Component that wraps platform ScrollView while providing
* integration with touch locking "responder" system.
@@ -528,24 +582,71 @@
* multiple columns, infinite scroll loading, or any number of other features it
* supports out of the box.
*/
-const ScrollView = createReactClass({
- displayName: 'ScrollView',
- mixins: [ScrollResponder.Mixin],
+class ScrollView extends React.Component<Props, State> {
+ /**
+ * Part 1: Removing ScrollResponder.Mixin:
+ *
+ * 1. Mixin methods should be flow typed. That's why we create a
+ * copy of ScrollResponder.Mixin and attach it to this._scrollResponder.
+ * Otherwise, we'd have to manually declare each method on the component
+ * class and assign it a flow type.
+ * 2. Mixin methods can call component methods, and access the component's
+ * props and state. So, we need to bind all mixin methods to the
+ * component instance.
+ * 3. Continued...
+ */
+ _scrollResponder: typeof ScrollResponder.Mixin = createScrollResponder(this);
+
+ constructor(...args) {
+ super(...args);
+
+ /**
+ * Part 2: Removing ScrollResponder.Mixin
+ *
+ * 3. Mixin methods access other mixin methods via dynamic dispatch using
+ * this. Since mixin methods are bound to the component instance, we need
+ * to copy all mixin methods to the component instance. This is also
+ * necessary because getScrollResponder() is a public method that returns
+ * an object that can be used to execute all scrollResponder methods.
+ * Since the object returned from that method is the ScrollView instance,
+ * we need to bind all mixin methods to the ScrollView instance.
+ */
+ for (const key in ScrollResponder.Mixin) {
+ if (
+ typeof ScrollResponder.Mixin[key] === 'function' &&
+ key.startsWith('scrollResponder')
+ ) {
+ (this: any)[key] = ScrollResponder.Mixin[key].bind(this);
+ }
+ }
+
+ /**
+ * Part 3: Removing ScrollResponder.Mixin
+ *
+ * 4. Mixins can initialize properties and use properties on the component
+ * instance.
+ */
+ Object.keys(ScrollResponder.Mixin)
+ .filter(key => typeof ScrollResponder.Mixin[key] !== 'function')
+ .forEach(key => {
+ (this: any)[key] = ScrollResponder.Mixin[key];
+ });
+ }
- _scrollAnimatedValue: (new AnimatedImplementation.Value(
+ _scrollAnimatedValue: AnimatedImplementation.Value = new AnimatedImplementation.Value(
0,
- ): AnimatedImplementation.Value),
- _scrollAnimatedValueAttachment: (null: ?{detach: () => void}),
- _stickyHeaderRefs: (new Map(): Map<number, ScrollViewStickyHeader>),
- _headerLayoutYs: (new Map(): Map<string, number>),
- getInitialState: function() {
- return {
- ...this.scrollResponderMixinGetInitialState(),
+ );
+ _scrollAnimatedValueAttachment: ?{detach: () => void} = null;
+ _stickyHeaderRefs: Map<number, ScrollViewStickyHeader> = new Map();
+ _headerLayoutYs: Map<string, number> = new Map();
+
+ state = {
layoutHeight: null,
+ ...ScrollResponder.Mixin.scrollResponderMixinGetInitialState(),
};
- },
- UNSAFE_componentWillMount: function() {
+ UNSAFE_componentWillMount() {
+ this._scrollResponder.UNSAFE_componentWillMount();
this._scrollAnimatedValue = new AnimatedImplementation.Value(
this.props.contentOffset ? this.props.contentOffset.y : 0,
);
@@ -554,25 +655,26 @@
);
this._stickyHeaderRefs = new Map();
this._headerLayoutYs = new Map();
- },
+ }
- componentDidMount: function() {
+ componentDidMount() {
this._updateAnimatedNodeAttachment();
- },
+ }
- componentDidUpdate: function() {
+ componentDidUpdate() {
this._updateAnimatedNodeAttachment();
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
+ this._scrollResponder.componentWillUnmount();
if (this._scrollAnimatedValueAttachment) {
this._scrollAnimatedValueAttachment.detach();
}
- },
+ }
- setNativeProps: function(props: Object) {
+ setNativeProps(props: Object) {
this._scrollViewRef && this._scrollViewRef.setNativeProps(props);
- },
+ }
/**
* Returns a reference to the underlying scroll responder, which supports
@@ -580,17 +682,23 @@
* implement this method so that they can be composed while providing access
* to the underlying scroll responder's methods.
*/
- getScrollResponder: function(): ScrollView {
- return this;
- },
+ getScrollResponder(): {
+ ...typeof ScrollView,
+ ...typeof ScrollResponder.Mixin,
+ } {
+ return ((this: any): {
+ ...typeof ScrollView,
+ ...typeof ScrollResponder.Mixin,
+ });
+ }
- getScrollableNode: function(): any {
+ getScrollableNode(): any {
return ReactNative.findNodeHandle(this._scrollViewRef);
- },
+ }
- getInnerViewNode: function(): any {
+ getInnerViewNode(): any {
return ReactNative.findNodeHandle(this._innerViewRef);
- },
+ }
/**
* Scrolls to a given x, y offset, either immediately or with a smooth animation.
@@ -603,7 +711,7 @@
* the function also accepts separate arguments as an alternative to the options object.
* This is deprecated due to ambiguity (y before x), and SHOULD NOT BE USED.
*/
- scrollTo: function(
+ scrollTo(
y?: number | {x?: number, y?: number, animated?: boolean},
x?: number,
animated?: boolean,
@@ -616,12 +724,12 @@
} else {
({x, y, animated} = y || {});
}
- this.getScrollResponder().scrollResponderScrollTo({
+ this._scrollResponder.scrollResponderScrollTo({
x: x || 0,
y: y || 0,
animated: animated !== false,
});
- },
+ }
/**
* If this is a vertical ScrollView scrolls to the bottom.
@@ -631,40 +739,39 @@
* `scrollToEnd({animated: false})` for immediate scrolling.
* If no options are passed, `animated` defaults to true.
*/
- scrollToEnd: function(options?: {animated?: boolean}) {
+ scrollToEnd(options?: {animated?: boolean}) {
// Default to true
const animated = (options && options.animated) !== false;
- this.getScrollResponder().scrollResponderScrollToEnd({
+ this._scrollResponder.scrollResponderScrollToEnd({
animated: animated,
});
- },
+ }
/**
* Deprecated, use `scrollTo` instead.
*/
- scrollWithoutAnimationTo: function(y: number = 0, x: number = 0) {
+ scrollWithoutAnimationTo(y: number = 0, x: number = 0) {
console.warn(
'`scrollWithoutAnimationTo` is deprecated. Use `scrollTo` instead',
);
this.scrollTo({x, y, animated: false});
- },
+ }
/**
* Displays the scroll indicators momentarily.
*
* @platform ios
*/
- flashScrollIndicators: function() {
- this.getScrollResponder().scrollResponderFlashScrollIndicators();
- },
+ flashScrollIndicators() {
+ this._scrollResponder.scrollResponderFlashScrollIndicators();
+ }
- _getKeyForIndex: function(index, childArray) {
- // $FlowFixMe Invalid prop usage
+ _getKeyForIndex(index, childArray) {
const child = childArray[index];
return child && child.key;
- },
+ }
- _updateAnimatedNodeAttachment: function() {
+ _updateAnimatedNodeAttachment() {
if (this._scrollAnimatedValueAttachment) {
this._scrollAnimatedValueAttachment.detach();
}
@@ -678,18 +785,19 @@
[{nativeEvent: {contentOffset: {y: this._scrollAnimatedValue}}}],
);
}
- },
+ }
- _setStickyHeaderRef: function(key, ref) {
+ _setStickyHeaderRef(key, ref) {
if (ref) {
this._stickyHeaderRefs.set(key, ref);
} else {
this._stickyHeaderRefs.delete(key);
}
- },
+ }
- _onStickyHeaderLayout: function(index, event, key) {
- if (!this.props.stickyHeaderIndices) {
+ _onStickyHeaderLayout(index, event, key) {
+ const {stickyHeaderIndices} = this.props;
+ if (!stickyHeaderIndices) {
return;
}
const childArray = React.Children.toArray(this.props.children);
@@ -701,19 +809,17 @@
const layoutY = event.nativeEvent.layout.y;
this._headerLayoutYs.set(key, layoutY);
- const indexOfIndex = this.props.stickyHeaderIndices.indexOf(index);
- const previousHeaderIndex = this.props.stickyHeaderIndices[
- indexOfIndex - 1
- ];
+ const indexOfIndex = stickyHeaderIndices.indexOf(index);
+ const previousHeaderIndex = stickyHeaderIndices[indexOfIndex - 1];
if (previousHeaderIndex != null) {
const previousHeader = this._stickyHeaderRefs.get(
this._getKeyForIndex(previousHeaderIndex, childArray),
);
previousHeader && previousHeader.setNextHeaderY(layoutY);
}
- },
+ }
- _handleScroll: function(e: Object) {
+ _handleScroll = (e: Object) => {
if (__DEV__) {
if (
this.props.onScroll &&
@@ -737,35 +843,35 @@
dismissKeyboard();
}
}
- this.scrollResponderHandleScroll(e);
- },
+ this._scrollResponder.scrollResponderHandleScroll(e);
+ };
- _handleLayout: function(e: Object) {
+ _handleLayout = (e: Object) => {
if (this.props.invertStickyHeaders) {
this.setState({layoutHeight: e.nativeEvent.layout.height});
}
if (this.props.onLayout) {
this.props.onLayout(e);
}
- },
+ };
- _handleContentOnLayout: function(e: Object) {
+ _handleContentOnLayout = (e: Object) => {
const {width, height} = e.nativeEvent.layout;
this.props.onContentSizeChange &&
this.props.onContentSizeChange(width, height);
- },
+ };
- _scrollViewRef: (null: ?ScrollView),
- _setScrollViewRef: function(ref: ?ScrollView) {
+ _scrollViewRef: ?ScrollView = null;
+ _setScrollViewRef = (ref: ?ScrollView) => {
this._scrollViewRef = ref;
- },
+ };
- _innerViewRef: (null: ?NativeMethodsMixinType),
- _setInnerViewRef: function(ref: ?NativeMethodsMixinType) {
+ _innerViewRef: ?NativeMethodsMixinType = null;
+ _setInnerViewRef = (ref: ?NativeMethodsMixinType) => {
this._innerViewRef = ref;
- },
+ };
- render: function() {
+ render() {
let ScrollViewClass;
let ScrollContentContainerViewClass;
if (Platform.OS === 'android') {
@@ -816,13 +922,12 @@
}
const {stickyHeaderIndices} = this.props;
- const hasStickyHeaders =
- stickyHeaderIndices && stickyHeaderIndices.length > 0;
- const childArray =
- hasStickyHeaders && React.Children.toArray(this.props.children);
- const children = hasStickyHeaders
- ? // $FlowFixMe Invalid prop usage
- childArray.map((child, index) => {
+ let children = this.props.children;
+
+ if (stickyHeaderIndices != null && stickyHeaderIndices.length > 0) {
+ const childArray = React.Children.toArray(this.props.children);
+
+ children = childArray.map((child, index) => {
const indexOfIndex = child ? stickyHeaderIndices.indexOf(index) : -1;
if (indexOfIndex > -1) {
const key = child.key;
@@ -834,9 +939,7 @@
nextHeaderLayoutY={this._headerLayoutYs.get(
this._getKeyForIndex(nextIndex, childArray),
)}
- onLayout={event =>
- this._onStickyHeaderLayout(index, event, key)
- }
+ onLayout={event => this._onStickyHeaderLayout(index, event, key)}
scrollAnimatedValue={this._scrollAnimatedValue}
inverted={this.props.invertStickyHeaders}
scrollViewHeight={this.state.layoutHeight}>
@@ -846,8 +949,12 @@
} else {
return child;
}
- })
- : this.props.children;
+ });
+ }
+
+ const hasStickyHeaders =
+ stickyHeaderIndices && stickyHeaderIndices.length > 0;
+
const contentContainer = (
<ScrollContentContainerViewClass
{...contentSizeChangeProps}
@@ -891,28 +998,35 @@
// bubble up from TextInputs
onContentSizeChange: null,
onLayout: this._handleLayout,
- onMomentumScrollBegin: this.scrollResponderHandleMomentumScrollBegin,
- onMomentumScrollEnd: this.scrollResponderHandleMomentumScrollEnd,
- onResponderGrant: this.scrollResponderHandleResponderGrant,
- onResponderReject: this.scrollResponderHandleResponderReject,
- onResponderRelease: this.scrollResponderHandleResponderRelease,
+ onMomentumScrollBegin: this._scrollResponder
+ .scrollResponderHandleMomentumScrollBegin,
+ onMomentumScrollEnd: this._scrollResponder
+ .scrollResponderHandleMomentumScrollEnd,
+ onResponderGrant: this._scrollResponder
+ .scrollResponderHandleResponderGrant,
+ onResponderReject: this._scrollResponder
+ .scrollResponderHandleResponderReject,
+ onResponderRelease: this._scrollResponder
+ .scrollResponderHandleResponderRelease,
// $FlowFixMe
- onResponderTerminate: this.scrollResponderHandleTerminate,
- onResponderTerminationRequest: this
+ onResponderTerminate: this._scrollResponder
+ .scrollResponderHandleTerminate,
+ onResponderTerminationRequest: this._scrollResponder
.scrollResponderHandleTerminationRequest,
- onScroll: this._handleScroll,
- onScrollBeginDrag: this.scrollResponderHandleScrollBeginDrag,
- onScrollEndDrag: this.scrollResponderHandleScrollEndDrag,
- onScrollShouldSetResponder: this
+ onScrollBeginDrag: this._scrollResponder
+ .scrollResponderHandleScrollBeginDrag,
+ onScrollEndDrag: this._scrollResponder.scrollResponderHandleScrollEndDrag,
+ onScrollShouldSetResponder: this._scrollResponder
.scrollResponderHandleScrollShouldSetResponder,
- onStartShouldSetResponder: this
+ onStartShouldSetResponder: this._scrollResponder
.scrollResponderHandleStartShouldSetResponder,
- onStartShouldSetResponderCapture: this
+ onStartShouldSetResponderCapture: this._scrollResponder
.scrollResponderHandleStartShouldSetResponderCapture,
- onTouchEnd: this.scrollResponderHandleTouchEnd,
- onTouchMove: this.scrollResponderHandleTouchMove,
- onTouchStart: this.scrollResponderHandleTouchStart,
- onTouchCancel: this.scrollResponderHandleTouchCancel,
+ onTouchEnd: this._scrollResponder.scrollResponderHandleTouchEnd,
+ onTouchMove: this._scrollResponder.scrollResponderHandleTouchMove,
+ onTouchStart: this._scrollResponder.scrollResponderHandleTouchStart,
+ onTouchCancel: this._scrollResponder.scrollResponderHandleTouchCancel,
+ onScroll: this._handleScroll,
scrollBarThumbImage: resolveAssetSource(this.props.scrollBarThumbImage),
scrollEventThrottle: hasStickyHeaders
? 1
@@ -922,6 +1036,10 @@
? true
: false,
DEPRECATED_sendUpdatedChildFrames,
+ // default to true
+ snapToStart: this.props.snapToStart !== false,
+ // default to true
+ snapToEnd: this.props.snapToEnd !== false,
// pagingEnabled is overridden by snapToInterval / snapToOffsets
pagingEnabled: Platform.select({
// on iOS, pagingEnabled must be set to false to have snapToInterval / snapToOffsets work
@@ -949,6 +1067,7 @@
// On iOS the RefreshControl is a child of the ScrollView.
// tvOS lacks native support for RefreshControl, so don't include it in that case
return (
+ // $FlowFixMe
<ScrollViewClass {...props} ref={this._setScrollViewRef}>
{Platform.isTV ? null : refreshControl}
{contentContainer}
@@ -967,6 +1086,7 @@
<ScrollViewClass
{...props}
style={baseStyle}
+ // $FlowFixMe
ref={this._setScrollViewRef}>
{contentContainer}
</ScrollViewClass>,
@@ -974,12 +1094,13 @@
}
}
return (
+ // $FlowFixMe
<ScrollViewClass {...props} ref={this._setScrollViewRef}>
{contentContainer}
</ScrollViewClass>
);
- },
-});
+ }
+}
const TypedScrollView = ((ScrollView: any): Class<
InternalScrollViewType<Props>,

Libraries/Components/ScrollView/ScrollViewStickyHeader.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/SegmentedControlIOS/RCTSegmentedControlNativeComponent.js

@@ -0,0 +1,67 @@
+/**
+ * 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.
+ *
+ * @flow
+ * @format
+ */
+'use strict';
+
+const requireNativeComponent = require('requireNativeComponent');
+
+import type {ViewProps} from 'ViewPropTypes';
+import type {SyntheticEvent} from 'CoreEventTypes';
+import type {NativeComponent} from 'ReactNative';
+
+type Event = SyntheticEvent<
+ $ReadOnly<{|
+ value: number,
+ selectedSegmentIndex: number,
+ |}>,
+>;
+
+type SegmentedControlIOSProps = $ReadOnly<{|
+ ...ViewProps,
+ /**
+ * The labels for the control's segment buttons, in order.
+ */
+ values?: $ReadOnlyArray<string>,
+ /**
+ * The index in `props.values` of the segment to be (pre)selected.
+ */
+ selectedIndex?: ?number,
+ /**
+ * Callback that is called when the user taps a segment;
+ * passes the segment's value as an argument
+ */
+ onValueChange?: ?(value: number) => mixed,
+ /**
+ * Callback that is called when the user taps a segment;
+ * passes the event as an argument
+ */
+ onChange?: ?(event: Event) => mixed,
+ /**
+ * If false the user won't be able to interact with the control.
+ * Default value is true.
+ */
+ enabled?: boolean,
+ /**
+ * Accent color of the control.
+ */
+ tintColor?: ?string,
+ /**
+ * If true, then selecting a segment won't persist visually.
+ * The `onValueChange` callback will still work as expected.
+ */
+ momentary?: ?boolean,
+|}>;
+
+type NativeSegmentedControlIOS = Class<
+ NativeComponent<SegmentedControlIOSProps>,
+>;
+
+module.exports = ((requireNativeComponent(
+ 'RCTSegmentedControl',
+): any): NativeSegmentedControlIOS);

Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.android.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.ios.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,39 +10,61 @@
'use strict';
-const NativeMethodsMixin = require('NativeMethodsMixin');
const React = require('React');
-const ReactNative = require('ReactNative');
-const PropTypes = require('prop-types');
const StyleSheet = require('StyleSheet');
-const ViewPropTypes = require('ViewPropTypes');
-const createReactClass = require('create-react-class');
-const requireNativeComponent = require('requireNativeComponent');
+const RCTSegmentedControlNativeComponent = require('RCTSegmentedControlNativeComponent');
+import type {SyntheticEvent} from 'CoreEventTypes';
import type {ViewProps} from 'ViewPropTypes';
-const RCTSegmentedControl = requireNativeComponent('RCTSegmentedControl');
+type Event = SyntheticEvent<
+ $ReadOnly<{|
+ value: number,
+ selectedSegmentIndex: number,
+ |}>,
+>;
-type DefaultProps = {
- values: $ReadOnlyArray<string>,
- enabled: boolean,
-};
-
-type Props = $ReadOnly<{|
+type SegmentedControlIOSProps = $ReadOnly<{|
...ViewProps,
- values?: ?$ReadOnlyArray<string>,
+ /**
+ * The labels for the control's segment buttons, in order.
+ */
+ values?: $ReadOnlyArray<string>,
+ /**
+ * The index in `props.values` of the segment to be (pre)selected.
+ */
selectedIndex?: ?number,
- onValueChange?: ?Function,
- onChange?: ?Function,
- enabled?: ?boolean,
+ /**
+ * Callback that is called when the user taps a segment;
+ * passes the segment's value as an argument
+ */
+ onValueChange?: ?(value: number) => mixed,
+ /**
+ * Callback that is called when the user taps a segment;
+ * passes the event as an argument
+ */
+ onChange?: ?(event: Event) => mixed,
+ /**
+ * If false the user won't be able to interact with the control.
+ * Default value is true.
+ */
+ enabled?: boolean,
+ /**
+ * Accent color of the control.
+ */
tintColor?: ?string,
+ /**
+ * If true, then selecting a segment won't persist visually.
+ * The `onValueChange` callback will still work as expected.
+ */
momentary?: ?boolean,
|}>;
-const SEGMENTED_CONTROL_REFERENCE = 'segmentedcontrol';
-
-type Event = Object;
+type Props = $ReadOnly<{|
+ ...SegmentedControlIOSProps,
+ forwardedRef: ?React.Ref<typeof RCTSegmentedControlNativeComponent>,
+|}>;
/**
* Use `SegmentedControlIOS` to render a UISegmentedControl iOS.
@@ -64,76 +86,31 @@
* />
* ````
*/
-const SegmentedControlIOS = createReactClass({
- displayName: 'SegmentedControlIOS',
- mixins: [NativeMethodsMixin],
-
- propTypes: {
- ...ViewPropTypes,
- /**
- * The labels for the control's segment buttons, in order.
- */
- values: PropTypes.arrayOf(PropTypes.string),
-
- /**
- * The index in `props.values` of the segment to be (pre)selected.
- */
- selectedIndex: PropTypes.number,
-
- /**
- * Callback that is called when the user taps a segment;
- * passes the segment's value as an argument
- */
- onValueChange: PropTypes.func,
-
- /**
- * Callback that is called when the user taps a segment;
- * passes the event as an argument
- */
- onChange: PropTypes.func,
-
- /**
- * If false the user won't be able to interact with the control.
- * Default value is true.
- */
- enabled: PropTypes.bool,
- /**
- * Accent color of the control.
- */
- tintColor: PropTypes.string,
-
- /**
- * If true, then selecting a segment won't persist visually.
- * The `onValueChange` callback will still work as expected.
- */
- momentary: PropTypes.bool,
- },
-
- getDefaultProps: function(): DefaultProps {
- return {
+class SegmentedControlIOS extends React.Component<Props> {
+ static defaultProps = {
values: [],
enabled: true,
};
- },
- _onChange: function(event: Event) {
+ _onChange = (event: Event) => {
this.props.onChange && this.props.onChange(event);
this.props.onValueChange &&
this.props.onValueChange(event.nativeEvent.value);
- },
+ };
- render: function() {
+ render() {
+ const {forwardedRef, ...props} = this.props;
return (
- <RCTSegmentedControl
- {...this.props}
- ref={SEGMENTED_CONTROL_REFERENCE}
+ <RCTSegmentedControlNativeComponent
+ {...props}
+ ref={forwardedRef}
style={[styles.segmentedControl, this.props.style]}
onChange={this._onChange}
/>
);
- },
-});
+ }
+}
const styles = StyleSheet.create({
segmentedControl: {
@@ -141,6 +118,16 @@
},
});
-module.exports = ((SegmentedControlIOS: any): Class<
- ReactNative.NativeComponent<Props>,
->);
+const SegmentedControlIOSWithRef = React.forwardRef(
+ (
+ props: SegmentedControlIOSProps,
+ forwardedRef: ?React.Ref<typeof RCTSegmentedControlNativeComponent>,
+ ) => {
+ return <SegmentedControlIOS {...props} forwardedRef={forwardedRef} />;
+ },
+);
+
+/* $FlowFixMe(>=0.89.0 site=react_native_ios_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
+module.exports = (SegmentedControlIOSWithRef: NativeSegmentedControlIOS);

Libraries/Components/Slider/RCTSliderNativeComponent.js

@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow
+ */
+
+'use strict';
+
+const requireNativeComponent = require('requireNativeComponent');
+
+import type {ColorValue} from 'StyleSheetTypes';
+import type {ImageSource} from 'ImageSource';
+import type {NativeComponent} from 'ReactNative';
+import type {SyntheticEvent} from 'CoreEventTypes';
+import type {ViewProps} from 'ViewPropTypes';
+import type {ViewStyleProp} from 'StyleSheet';
+
+type Event = SyntheticEvent<
+ $ReadOnly<{|
+ value: number,
+ fromUser?: boolean,
+ |}>,
+>;
+
+type NativeProps = $ReadOnly<{|
+ ...ViewProps,
+ disabled?: ?boolean,
+ enabled?: ?boolean,
+ maximumTrackImage?: ?ImageSource,
+ maximumTrackTintColor?: ?ColorValue,
+ maximumValue?: ?number,
+ minimumTrackImage?: ?ImageSource,
+ minimumTrackTintColor?: ?ColorValue,
+ minimumValue?: ?number,
+ onChange?: ?(event: Event) => void,
+ onSlidingComplete?: ?(event: Event) => void,
+ onValueChange?: ?(event: Event) => void,
+ step?: ?number,
+ testID?: ?string,
+ thumbImage?: ?ImageSource,
+ thumbTintColor?: ?ColorValue,
+ trackImage?: ?ImageSource,
+ value?: ?number,
+|}>;
+
+type RCTSliderType = Class<NativeComponent<NativeProps>>;
+
+module.exports = ((requireNativeComponent('RCTSlider'): any): RCTSliderType);

Libraries/Components/Slider/Slider.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,21 +10,27 @@
'use strict';
-const ReactNative = require('ReactNative');
const Platform = require('Platform');
+const RCTSliderNativeComponent = require('RCTSliderNativeComponent');
const React = require('React');
+const ReactNative = require('ReactNative');
const StyleSheet = require('StyleSheet');
-const requireNativeComponent = require('requireNativeComponent');
-
import type {ImageSource} from 'ImageSource';
import type {ViewStyleProp} from 'StyleSheet';
import type {ColorValue} from 'StyleSheetTypes';
import type {ViewProps} from 'ViewPropTypes';
+import type {SyntheticEvent} from 'CoreEventTypes';
-const RCTSlider = requireNativeComponent('RCTSlider');
-
-type Event = Object;
+type Event = SyntheticEvent<
+ $ReadOnly<{|
+ value: number,
+ /**
+ * Android Only.
+ */
+ fromUser?: boolean,
+ |}>,
+>;
type IOSProps = $ReadOnly<{|
/**
@@ -51,22 +57,13 @@
thumbImage?: ?ImageSource,
|}>;
-type AndroidProps = $ReadOnly<{|
- /**
- * Color of the foreground switch grip.
- * @platform android
- */
- thumbTintColor?: ?ColorValue,
-|}>;
-
type Props = $ReadOnly<{|
...ViewProps,
...IOSProps,
- ...AndroidProps,
/**
* Used to style and layout the `Slider`. See `StyleSheet.js` and
- * `ViewStylePropTypes.js` for more info.
+ * `DeprecatedViewStylePropTypes.js` for more info.
*/
style?: ?ViewStyleProp,
@@ -108,6 +105,11 @@
* Overrides the default blue gradient image on iOS.
*/
maximumTrackTintColor?: ?ColorValue,
+ /**
+ * The color used to tint the default thumb images on iOS, or the
+ * color of the foreground switch grip on Android.
+ */
+ thumbTintColor?: ?ColorValue,
/**
* If true the user won't be able to move the slider.
@@ -118,14 +120,14 @@
/**
* Callback continuously called while the user is dragging the slider.
*/
- onValueChange?: ?Function,
+ onValueChange?: ?(value: number) => void,
/**
* Callback that is called when the user releases the slider,
* regardless if the value has changed. The current value is passed
* as an argument to the callback handler.
*/
- onSlidingComplete?: ?Function,
+ onSlidingComplete?: ?(value: number) => void,
/**
* Used to locate this view in UI automation tests.
@@ -195,44 +197,43 @@
*/
const Slider = (
props: Props,
- forwardedRef?: ?React.Ref<'RCTActivityIndicatorView'>,
+ forwardedRef?: ?React.Ref<typeof RCTSliderNativeComponent>,
) => {
const style = StyleSheet.compose(
styles.slider,
props.style,
);
- const onValueChange =
- props.onValueChange &&
- ((event: Event) => {
+ const {onValueChange, onSlidingComplete, ...localProps} = props;
+
+ const onValueChangeEvent = onValueChange
+ ? (event: Event) => {
let userEvent = true;
if (Platform.OS === 'android') {
// On Android there's a special flag telling us the user is
// dragging the slider.
- userEvent = event.nativeEvent.fromUser;
+ userEvent =
+ event.nativeEvent.fromUser != null && event.nativeEvent.fromUser;
}
- props.onValueChange &&
- userEvent &&
- props.onValueChange(event.nativeEvent.value);
- });
-
- const onChange = onValueChange;
+ userEvent && onValueChange(event.nativeEvent.value);
+ }
+ : null;
- const onSlidingComplete =
- props.onSlidingComplete &&
- ((event: Event) => {
- props.onSlidingComplete &&
- props.onSlidingComplete(event.nativeEvent.value);
- });
+ const onChangeEvent = onValueChangeEvent;
+ const onSlidingCompleteEvent = onSlidingComplete
+ ? (event: Event) => {
+ onSlidingComplete(event.nativeEvent.value);
+ }
+ : null;
return (
- <RCTSlider
- {...props}
+ <RCTSliderNativeComponent
+ {...localProps}
ref={forwardedRef}
style={style}
- onChange={onChange}
- onSlidingComplete={onSlidingComplete}
- onValueChange={onValueChange}
+ onChange={onChangeEvent}
+ onSlidingComplete={onSlidingCompleteEvent}
+ onValueChange={onValueChangeEvent}
enabled={!props.disabled}
onStartShouldSetResponder={() => true}
onResponderTerminationRequest={() => false}
@@ -240,9 +241,11 @@
);
};
-// $FlowFixMe - TODO T29156721 `React.forwardRef` is not defined in Flow, yet.
const SliderWithRef = React.forwardRef(Slider);
+/* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an error
+ * found when Flow v0.89 was deployed. To see the error, delete this comment
+ * and run Flow. */
SliderWithRef.defaultProps = {
disabled: false,
value: 0,
@@ -264,4 +267,7 @@
});
}
+/* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an error
+ * found when Flow v0.89 was deployed. To see the error, delete this comment
+ * and run Flow. */
module.exports = (SliderWithRef: Class<ReactNative.NativeComponent<Props>>);

Libraries/Components/StaticContainer.react.js

@@ -1,11 +1,11 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
- * @flow
+ * @flow strict-local
*/
'use strict';
@@ -27,8 +27,19 @@
* Typically, you will not need to use this component and should opt for normal
* React reconciliation.
*/
-class StaticContainer extends React.Component<Object> {
- shouldComponentUpdate(nextProps: Object): boolean {
+
+type Props = $ReadOnly<{|
+ /**
+ * Whether or not this component should update.
+ */
+ shouldUpdate: ?boolean,
+ /**
+ * Content short-circuited by React reconciliation process.
+ */
+ children: React.Node,
+|}>;
+class StaticContainer extends React.Component<Props> {
+ shouldComponentUpdate(nextProps: Props): boolean {
return !!nextProps.shouldUpdate;
}

Libraries/Components/StaticRenderer.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -12,18 +12,20 @@
const React = require('React');
-const PropTypes = require('prop-types');
-
-class StaticRenderer extends React.Component<{
+type Props = $ReadOnly<{|
+ /**
+ * Indicates whether the render function needs to be called again
+ */
shouldUpdate: boolean,
- render: Function,
-}> {
- static propTypes = {
- shouldUpdate: PropTypes.bool.isRequired,
- render: PropTypes.func.isRequired,
- };
+ /**
+ * () => renderable
+ * A function that returns a renderable component
+ */
+ render: () => React.Node,
+|}>;
- shouldComponentUpdate(nextProps: {shouldUpdate: boolean}): boolean {
+class StaticRenderer extends React.Component<Props> {
+ shouldComponentUpdate(nextProps: Props): boolean {
return nextProps.shouldUpdate;
}

Libraries/Components/StatusBar/StatusBarIOS.android.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/StatusBar/StatusBarIOS.ios.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/StatusBar/StatusBar.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,8 +11,6 @@
'use strict';
const React = require('React');
-const PropTypes = require('prop-types');
-const ColorPropType = require('ColorPropType');
const Platform = require('Platform');
const processColor = require('processColor');
@@ -55,9 +53,55 @@
slide: string,
}>;
-type DefaultProps = {
- animated: boolean,
-};
+type AndroidProps = $ReadOnly<{|
+ /**
+ * The background color of the status bar.
+ * @platform android
+ */
+ backgroundColor?: ?string,
+ /**
+ * If the status bar is translucent.
+ * When translucent is set to true, the app will draw under the status bar.
+ * This is useful when using a semi transparent status bar color.
+ *
+ * @platform android
+ */
+ translucent?: ?boolean,
+|}>;
+
+type IOSProps = $ReadOnly<{|
+ /**
+ * If the network activity indicator should be visible.
+ *
+ * @platform ios
+ */
+ networkActivityIndicatorVisible?: ?boolean,
+ /**
+ * The transition effect when showing and hiding the status bar using the `hidden`
+ * prop. Defaults to 'fade'.
+ *
+ * @platform ios
+ */
+ showHideTransition?: ?('fade' | 'slide'),
+|}>;
+
+type Props = $ReadOnly<{|
+ ...AndroidProps,
+ ...IOSProps,
+ /**
+ * If the status bar is hidden.
+ */
+ hidden?: ?boolean,
+ /**
+ * If the transition between status bar property changes should be animated.
+ * Supported for backgroundColor, barStyle and hidden.
+ */
+ animated?: ?boolean,
+ /**
+ * Sets the color of the status bar text.
+ */
+ barStyle?: ?('default' | 'light-content' | 'dark-content'),
+|}>;
/**
* Merges the prop stack with the default values.
@@ -138,31 +182,49 @@
*
* ### Imperative API
*
- * For cases where using a component is not ideal, there is also an imperative
- * API exposed as static functions on the component. It is however not recommended
- * to use the static API and the component for the same prop because any value
- * set by the static API will get overriden by the one set by the component in
- * the next render.
+ * For cases where using a component is not ideal, there are static methods
+ * to manipulate the `StatusBar` display stack. These methods have the same
+ * behavior as mounting and unmounting a `StatusBar` component.
+ *
+ * For example, you can call `StatusBar.pushStackEntry` to update the status bar
+ * before launching a third-party native UI component, and then call
+ * `StatusBar.popStackEntry` when completed.
+ *
+ * ```
+ * const openThirdPartyBugReporter = async () => {
+ * // The bug reporter has a dark background, so we push a new status bar style.
+ * const stackEntry = StatusBar.pushStackEntry({barStyle: 'light-content'});
+ *
+ * // `open` returns a promise that resolves when the UI is dismissed.
+ * await BugReporter.open();
+ *
+ * // Don't forget to call `popStackEntry` when you're done.
+ * StatusBar.popStackEntry(stackEntry);
+ * };
+ * ```
+ *
+ * There is a legacy imperative API that enables you to manually update the
+ * status bar styles. However, the legacy API does not update the internal
+ * `StatusBar` display stack, which means that any changes will be overridden
+ * whenever a `StatusBar` component is mounted or unmounted.
+ *
+ * It is strongly advised that you use `pushStackEntry`, `popStackEntry`, or
+ * `replaceStackEntry` instead of the static methods beginning with `set`.
*
* ### Constants
*
* `currentHeight` (Android only) The height of the status bar.
*/
-class StatusBar extends React.Component<{
- hidden?: boolean,
- animated?: boolean,
- backgroundColor?: string,
- translucent?: boolean,
- barStyle?: 'default' | 'light-content' | 'dark-content',
- networkActivityIndicatorVisible?: boolean,
- showHideTransition?: 'fade' | 'slide',
-}> {
+class StatusBar extends React.Component<Props> {
static _propsStack = [];
static _defaultProps = createStackEntry({
animated: false,
showHideTransition: 'fade',
- backgroundColor: 'black',
+ backgroundColor: Platform.select({
+ android: StatusBarManager.DEFAULT_BACKGROUND_COLOR ?? 'black',
+ ios: 'black',
+ }),
barStyle: 'default',
translucent: false,
hidden: false,
@@ -261,47 +323,47 @@
StatusBarManager.setTranslucent(translucent);
}
- static propTypes = {
- /**
- * If the status bar is hidden.
- */
- hidden: PropTypes.bool,
- /**
- * If the transition between status bar property changes should be animated.
- * Supported for backgroundColor, barStyle and hidden.
- */
- animated: PropTypes.bool,
/**
- * The background color of the status bar.
- * @platform android
- */
- backgroundColor: ColorPropType,
- /**
- * If the status bar is translucent.
- * When translucent is set to true, the app will draw under the status bar.
- * This is useful when using a semi transparent status bar color.
+ * Push a StatusBar entry onto the stack.
+ * The return value should be passed to `popStackEntry` when complete.
*
- * @platform android
- */
- translucent: PropTypes.bool,
- /**
- * Sets the color of the status bar text.
+ * @param props Object containing the StatusBar props to use in the stack entry.
*/
- barStyle: PropTypes.oneOf(['default', 'light-content', 'dark-content']),
+ static pushStackEntry(props: any) {
+ const entry = createStackEntry(props);
+ StatusBar._propsStack.push(entry);
+ StatusBar._updatePropsStack();
+ return entry;
+ }
+
/**
- * If the network activity indicator should be visible.
+ * Pop a StatusBar entry from the stack.
*
- * @platform ios
+ * @param entry Entry returned from `pushStackEntry`.
*/
- networkActivityIndicatorVisible: PropTypes.bool,
+ static popStackEntry(entry: any) {
+ const index = StatusBar._propsStack.indexOf(entry);
+ if (index !== -1) {
+ StatusBar._propsStack.splice(index, 1);
+ }
+ StatusBar._updatePropsStack();
+ }
+
/**
- * The transition effect when showing and hiding the status bar using the `hidden`
- * prop. Defaults to 'fade'.
+ * Replace an existing StatusBar stack entry with new props.
*
- * @platform ios
+ * @param entry Entry returned from `pushStackEntry` to replace.
+ * @param props Object containing the StatusBar props to use in the replacement stack entry.
*/
- showHideTransition: PropTypes.oneOf(['fade', 'slide']),
- };
+ static replaceStackEntry(entry: any, props: any) {
+ const newEntry = createStackEntry(props);
+ const index = StatusBar._propsStack.indexOf(entry);
+ if (index !== -1) {
+ StatusBar._propsStack[index] = newEntry;
+ }
+ StatusBar._updatePropsStack();
+ return newEntry;
+ }
static defaultProps = {
animated: false,
@@ -314,33 +376,27 @@
// Every time a StatusBar component is mounted, we push it's prop to a stack
// and always update the native status bar with the props from the top of then
// stack. This allows having multiple StatusBar components and the one that is
- // added last or is deeper in the view hierarchy will have priority.
- this._stackEntry = createStackEntry(this.props);
- StatusBar._propsStack.push(this._stackEntry);
- this._updatePropsStack();
+ // added last or is deeper in the view hierachy will have priority.
+ this._stackEntry = StatusBar.pushStackEntry(this.props);
}
componentWillUnmount() {
// When a StatusBar is unmounted, remove itself from the stack and update
// the native bar with the next props.
- const index = StatusBar._propsStack.indexOf(this._stackEntry);
- StatusBar._propsStack.splice(index, 1);
-
- this._updatePropsStack();
+ StatusBar.popStackEntry(this._stackEntry);
}
componentDidUpdate() {
- const index = StatusBar._propsStack.indexOf(this._stackEntry);
- this._stackEntry = createStackEntry(this.props);
- StatusBar._propsStack[index] = this._stackEntry;
-
- this._updatePropsStack();
+ this._stackEntry = StatusBar.replaceStackEntry(
+ this._stackEntry,
+ this.props,
+ );
}
/**
* Updates the native status bar with the props from the stack.
*/
- _updatePropsStack = () => {
+ static _updatePropsStack = () => {
// Send the update to the native module only once at the end of the frame.
clearImmediate(StatusBar._updateImmediate);
StatusBar._updateImmediate = setImmediate(() => {
@@ -358,7 +414,7 @@
) {
StatusBarManager.setStyle(
mergedProps.barStyle.value,
- mergedProps.barStyle.animated,
+ mergedProps.barStyle.animated || false,
);
}
if (!oldProps || oldProps.hidden.value !== mergedProps.hidden.value) {

Libraries/Components/Subscribable.js

@@ -1,65 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow
- */
-
-'use strict';
-
-import type EventEmitter from 'EventEmitter';
-
-/**
- * Subscribable provides a mixin for safely subscribing a component to an
- * eventEmitter
- *
- * This will be replaced with the observe interface that will be coming soon to
- * React Core
- */
-
-const Subscribable = {};
-
-Subscribable.Mixin = {
- UNSAFE_componentWillMount: function() {
- this._subscribableSubscriptions = [];
- },
-
- componentWillUnmount: function() {
- // This null check is a fix for a broken version of uglify-es. Should be deleted eventually
- // https://github.com/facebook/react-native/issues/17348
- this._subscribableSubscriptions &&
- this._subscribableSubscriptions.forEach(subscription =>
- subscription.remove(),
- );
- this._subscribableSubscriptions = null;
- },
-
- /**
- * Special form of calling `addListener` that *guarantees* that a
- * subscription *must* be tied to a component instance, and therefore will
- * be cleaned up when the component is unmounted. It is impossible to create
- * the subscription and pass it in - this method must be the one to create
- * the subscription and therefore can guarantee it is retained in a way that
- * will be cleaned up.
- *
- * @param {EventEmitter} eventEmitter emitter to subscribe to.
- * @param {string} eventType Type of event to listen to.
- * @param {function} listener Function to invoke when event occurs.
- * @param {object} context Object to use as listener context.
- */
- addListenerOn: function(
- eventEmitter: EventEmitter,
- eventType: string,
- listener: Function,
- context: Object,
- ) {
- this._subscribableSubscriptions.push(
- eventEmitter.addListener(eventType, listener, context),
- );
- },
-};
-
-module.exports = Subscribable;

Libraries/Components/Switch/Switch.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -137,6 +137,8 @@
on: value === true,
style,
thumbTintColor: _thumbColor,
+ trackColorForFalse: _trackColorForFalse,
+ trackColorForTrue: _trackColorForTrue,
trackTintColor:
value === true ? _trackColorForTrue : _trackColorForFalse,
}: NativeAndroidProps)

Libraries/Components/Switch/SwitchNativeComponent.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -18,25 +18,33 @@
import type {SwitchChangeEvent} from 'CoreEventTypes';
import type {ViewProps} from 'ViewPropTypes';
+type SwitchProps = $ReadOnly<{|
+ ...ViewProps,
+ disabled?: ?boolean,
+ onChange?: ?(event: SwitchChangeEvent) => mixed,
+ thumbColor?: ?string,
+ trackColorForFalse?: ?string,
+ trackColorForTrue?: ?string,
+ value?: ?boolean,
+|}>;
+
// @see ReactSwitchManager.java
export type NativeAndroidProps = $ReadOnly<{|
- ...ViewProps,
+ ...SwitchProps,
+
enabled?: ?boolean,
on?: ?boolean,
- onChange?: ?(event: SwitchChangeEvent) => mixed,
thumbTintColor?: ?string,
trackTintColor?: ?string,
|}>;
// @see RCTSwitchManager.m
export type NativeIOSProps = $ReadOnly<{|
- ...ViewProps,
- disabled?: ?boolean,
- onChange?: ?(event: SwitchChangeEvent) => mixed,
+ ...SwitchProps,
+
onTintColor?: ?string,
thumbTintColor?: ?string,
tintColor?: ?string,
- value?: ?boolean,
|}>;
type SwitchNativeComponentType = Class<

Libraries/Components/Switch/SwitchSchema.js

@@ -0,0 +1,94 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow
+ */
+
+'use strict';
+
+import type {SchemaType} from '../../../packages/react-native-codegen/src/CodegenSchema.js';
+
+const SwitchSchema: SchemaType = {
+ modules: {
+ Switch: {
+ components: {
+ Switch: {
+ extendsProps: [
+ {
+ type: 'ReactNativeBuiltInType',
+ knownTypeName: 'ReactNativeCoreViewProps',
+ },
+ ],
+ events: [
+ {
+ name: 'onChange',
+ optional: true,
+ bubblingType: 'bubble',
+ typeAnnotation: {
+ type: 'EventTypeAnnotation',
+ argument: {
+ type: 'ObjectTypeAnnotation',
+ properties: [
+ {
+ type: 'BooleanTypeAnnotation',
+ name: 'value',
+ optional: false,
+ },
+ ],
+ },
+ },
+ },
+ ],
+ props: [
+ {
+ name: 'disabled',
+ optional: true,
+ typeAnnotation: {
+ type: 'BooleanTypeAnnotation',
+ default: false,
+ },
+ },
+ {
+ name: 'value',
+ optional: true,
+ typeAnnotation: {
+ type: 'BooleanTypeAnnotation',
+ default: false,
+ },
+ },
+ {
+ name: 'tintColor',
+ optional: true,
+ typeAnnotation: {
+ type: 'NativePrimitiveTypeAnnotation',
+ name: 'ColorPrimitive',
+ },
+ },
+ {
+ name: 'onTintColor',
+ optional: true,
+ typeAnnotation: {
+ type: 'NativePrimitiveTypeAnnotation',
+ name: 'ColorPrimitive',
+ },
+ },
+ {
+ name: 'thumbTintColor',
+ optional: true,
+ typeAnnotation: {
+ type: 'NativePrimitiveTypeAnnotation',
+ name: 'ColorPrimitive',
+ },
+ },
+ ],
+ },
+ },
+ },
+ },
+};
+
+module.exports = SwitchSchema;

Libraries/Components/TabBarIOS/TabBarIOS.android.js

@@ -1,36 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow
- */
-
-'use strict';
-
-const React = require('React');
-const StyleSheet = require('StyleSheet');
-const TabBarItemIOS = require('TabBarItemIOS');
-const View = require('View');
-
-class DummyTabBarIOS extends React.Component<$FlowFixMeProps> {
- static Item = TabBarItemIOS;
-
- render() {
- return (
- <View style={[this.props.style, styles.tabGroup]}>
- {this.props.children}
- </View>
- );
- }
-}
-
-const styles = StyleSheet.create({
- tabGroup: {
- flex: 1,
- },
-});
-
-module.exports = DummyTabBarIOS;

Libraries/Components/TabBarIOS/TabBarIOS.ios.js

@@ -1,107 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow
- */
-
-'use strict';
-
-const ColorPropType = require('ColorPropType');
-const React = require('React');
-const PropTypes = require('prop-types');
-const StyleSheet = require('StyleSheet');
-const TabBarItemIOS = require('TabBarItemIOS');
-const ViewPropTypes = require('ViewPropTypes');
-
-const requireNativeComponent = require('requireNativeComponent');
-
-import type {DangerouslyImpreciseStyleProp} from 'StyleSheet';
-import type {ViewProps} from 'ViewPropTypes';
-
-const RCTTabBar = requireNativeComponent('RCTTabBar');
-
-type Props = $ReadOnly<{|
- ...ViewProps,
- style?: DangerouslyImpreciseStyleProp,
- unselectedTintColor?: string,
- tintColor?: string,
- unselectedItemTintColor?: string,
- barTintColor?: string,
- barStyle?: 'default' | 'black',
- translucent?: boolean,
- itemPositioning?: 'fill' | 'center' | 'auto',
- children: React.Node,
-|}>;
-
-class TabBarIOS extends React.Component<Props> {
- static Item = TabBarItemIOS;
-
- static propTypes = {
- ...ViewPropTypes,
- style: ViewPropTypes.style,
- /**
- * Color of text on unselected tabs
- */
- unselectedTintColor: ColorPropType,
- /**
- * Color of the currently selected tab icon
- */
- tintColor: ColorPropType,
- /**
- * Color of unselected tab icons. Available since iOS 10.
- */
- unselectedItemTintColor: ColorPropType,
- /**
- * Background color of the tab bar
- */
- barTintColor: ColorPropType,
- /**
- * The style of the tab bar. Supported values are 'default', 'black'.
- * Use 'black' instead of setting `barTintColor` to black. This produces
- * a tab bar with the native iOS style with higher translucency.
- */
- barStyle: PropTypes.oneOf(['default', 'black']),
- /**
- * A Boolean value that indicates whether the tab bar is translucent
- */
- translucent: PropTypes.bool,
- /**
- * Specifies tab bar item positioning. Available values are:
- * - fill - distributes items across the entire width of the tab bar
- * - center - centers item in the available tab bar space
- * - auto (default) - distributes items dynamically according to the
- * user interface idiom. In a horizontally compact environment (e.g. iPhone 5)
- * this value defaults to `fill`, in a horizontally regular one (e.g. iPad)
- * it defaults to center.
- */
- itemPositioning: PropTypes.oneOf(['fill', 'center', 'auto']),
- };
-
- render() {
- return (
- <RCTTabBar
- style={[styles.tabGroup, this.props.style]}
- unselectedTintColor={this.props.unselectedTintColor}
- unselectedItemTintColor={this.props.unselectedItemTintColor}
- tintColor={this.props.tintColor}
- barTintColor={this.props.barTintColor}
- barStyle={this.props.barStyle}
- itemPositioning={this.props.itemPositioning}
- translucent={this.props.translucent !== false}>
- {this.props.children}
- </RCTTabBar>
- );
- }
-}
-
-const styles = StyleSheet.create({
- tabGroup: {
- flex: 1,
- },
-});
-
-module.exports = TabBarIOS;

Libraries/Components/TabBarIOS/TabBarItemIOS.android.js

@@ -1,40 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const React = require('React');
-const View = require('View');
-const StyleSheet = require('StyleSheet');
-
-class DummyTab extends React.Component {
- render() {
- if (!this.props.selected) {
- return <View />;
- }
- return (
- <View style={[this.props.style, styles.tab]}>{this.props.children}</View>
- );
- }
-}
-
-const styles = StyleSheet.create({
- tab: {
- // TODO(5405356): Implement overflow: visible so position: absolute isn't useless
- // position: 'absolute',
- top: 0,
- right: 0,
- bottom: 0,
- left: 0,
- borderColor: 'red',
- borderWidth: 1,
- },
-});
-
-module.exports = DummyTab;

Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js

@@ -1,148 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @noflow
- */
-
-'use strict';
-
-const ColorPropType = require('ColorPropType');
-const Image = require('Image');
-const React = require('React');
-const PropTypes = require('prop-types');
-const StaticContainer = require('StaticContainer.react');
-const StyleSheet = require('StyleSheet');
-const View = require('View');
-
-const ViewPropTypes = require('ViewPropTypes');
-
-const requireNativeComponent = require('requireNativeComponent');
-
-class TabBarItemIOS extends React.Component {
- static propTypes = {
- ...ViewPropTypes,
- /**
- * Little red bubble that sits at the top right of the icon.
- */
- badge: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
- /**
- * Background color for the badge. Available since iOS 10.
- */
- badgeColor: ColorPropType,
- /**
- * Items comes with a few predefined system icons. Note that if you are
- * using them, the title and selectedIcon will be overridden with the
- * system ones.
- */
- systemIcon: PropTypes.oneOf([
- 'bookmarks',
- 'contacts',
- 'downloads',
- 'favorites',
- 'featured',
- 'history',
- 'more',
- 'most-recent',
- 'most-viewed',
- 'recents',
- 'search',
- 'top-rated',
- ]),
- /**
- * A custom icon for the tab. It is ignored when a system icon is defined.
- */
- icon: Image.propTypes.source,
- /**
- * A custom icon when the tab is selected. It is ignored when a system
- * icon is defined. If left empty, the icon will be tinted in blue.
- */
- selectedIcon: Image.propTypes.source,
- /**
- * Callback when this tab is being selected, you should change the state of your
- * component to set selected={true}.
- */
- onPress: PropTypes.func,
- /**
- * If set to true it renders the image as original,
- * it defaults to being displayed as a template
- */
- renderAsOriginal: PropTypes.bool,
- /**
- * It specifies whether the children are visible or not. If you see a
- * blank content, you probably forgot to add a selected one.
- */
- selected: PropTypes.bool,
- /**
- * React style object.
- */
- style: ViewPropTypes.style,
- /**
- * Text that appears under the icon. It is ignored when a system icon
- * is defined.
- */
- title: PropTypes.string,
- /**
- *(Apple TV only)* When set to true, this view will be focusable
- * and navigable using the Apple TV remote.
- *
- * @platform ios
- */
- isTVSelectable: PropTypes.bool,
- };
-
- state = {
- hasBeenSelected: false,
- };
-
- UNSAFE_componentWillMount() {
- if (this.props.selected) {
- this.setState({hasBeenSelected: true});
- }
- }
-
- UNSAFE_componentWillReceiveProps(nextProps: {selected?: boolean}) {
- if (this.state.hasBeenSelected || nextProps.selected) {
- this.setState({hasBeenSelected: true});
- }
- }
-
- render() {
- const {style, children, ...props} = this.props;
-
- // if the tab has already been shown once, always continue to show it so we
- // preserve state between tab transitions
- if (this.state.hasBeenSelected) {
- var tabContents = (
- <StaticContainer shouldUpdate={this.props.selected}>
- {children}
- </StaticContainer>
- );
- } else {
- var tabContents = <View />;
- }
-
- return (
- <RCTTabBarItem {...props} style={[styles.tab, style]}>
- {tabContents}
- </RCTTabBarItem>
- );
- }
-}
-
-const styles = StyleSheet.create({
- tab: {
- position: 'absolute',
- top: 0,
- right: 0,
- bottom: 0,
- left: 0,
- },
-});
-
-const RCTTabBarItem = requireNativeComponent('RCTTabBarItem');
-
-module.exports = TabBarItemIOS;

Libraries/Components/TextInput/InputAccessoryView.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -9,14 +9,14 @@
*/
'use strict';
-const ColorPropType = require('ColorPropType');
+const DeprecatedColorPropType = require('DeprecatedColorPropType');
+const Platform = require('Platform');
const React = require('React');
const StyleSheet = require('StyleSheet');
-const ViewPropTypes = require('ViewPropTypes');
-const requireNativeComponent = require('requireNativeComponent');
+const RCTInputAccessoryViewNativeComponent = require('RCTInputAccessoryViewNativeComponent');
-const RCTInputAccessoryView = requireNativeComponent('RCTInputAccessoryView');
+import type {ViewStyleProp} from 'StyleSheet';
/**
* Note: iOS only
@@ -76,32 +76,34 @@
* For an example, look at InputAccessoryViewExample.js in RNTester.
*/
-type Props = {
+type Props = $ReadOnly<{|
+children: React.Node,
/**
* An ID which is used to associate this `InputAccessoryView` to
* specified TextInput(s).
*/
- nativeID?: string,
- style?: ViewPropTypes.style,
- backgroundColor?: ColorPropType,
-};
+ nativeID?: ?string,
+ style?: ?ViewStyleProp,
+ backgroundColor?: ?DeprecatedColorPropType,
+|}>;
class InputAccessoryView extends React.Component<Props> {
render(): React.Node {
- console.warn('<InputAccessoryView> is not supported on Android yet.');
+ if (Platform.OS !== 'ios') {
+ console.warn('<InputAccessoryView> is only supported on iOS.');
+ }
if (React.Children.count(this.props.children) === 0) {
return null;
}
return (
- <RCTInputAccessoryView
+ <RCTInputAccessoryViewNativeComponent
style={[this.props.style, styles.container]}
nativeID={this.props.nativeID}
backgroundColor={this.props.backgroundColor}>
{this.props.children}
- </RCTInputAccessoryView>
+ </RCTInputAccessoryViewNativeComponent>
);
}
}

Libraries/Components/TextInput/RCTInputAccessoryViewNativeComponent.js

@@ -0,0 +1,34 @@
+/**
+ * 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.
+ *
+ * @flow
+ * @format
+ */
+'use strict';
+
+import type {NativeComponent} from 'ReactNative';
+import type {ColorValue} from 'StyleSheetTypes';
+import type {ViewStyleProp} from 'StyleSheet';
+
+const React = require('React');
+const requireNativeComponent = require('requireNativeComponent');
+
+type NativeProps = $ReadOnly<{|
+ +children: React.Node,
+ /**
+ * An ID which is used to associate this `InputAccessoryView` to
+ * specified TextInput(s).
+ */
+ nativeID?: ?string,
+ style?: ?ViewStyleProp,
+ backgroundColor?: ?ColorValue,
+|}>;
+
+type NativeInputAccessoryView = Class<NativeComponent<NativeProps>>;
+
+module.exports = ((requireNativeComponent(
+ 'RCTInputAccessoryView',
+): any): NativeInputAccessoryView);

Libraries/Components/TextInput/TextInput.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,32 +9,31 @@
*/
'use strict';
-const ColorPropType = require('ColorPropType');
+const DeprecatedColorPropType = require('DeprecatedColorPropType');
+const DeprecatedViewPropTypes = require('DeprecatedViewPropTypes');
const DocumentSelectionState = require('DocumentSelectionState');
-const EventEmitter = require('EventEmitter');
const NativeMethodsMixin = require('NativeMethodsMixin');
const Platform = require('Platform');
-const React = require('React');
-const createReactClass = require('create-react-class');
const PropTypes = require('prop-types');
+const React = require('React');
const ReactNative = require('ReactNative');
const StyleSheet = require('StyleSheet');
const Text = require('Text');
const TextAncestor = require('TextAncestor');
const TextInputState = require('TextInputState');
-const TimerMixin = require('react-timer-mixin');
const TouchableWithoutFeedback = require('TouchableWithoutFeedback');
const UIManager = require('UIManager');
-const ViewPropTypes = require('ViewPropTypes');
-const emptyFunction = require('fbjs/lib/emptyFunction');
-const invariant = require('fbjs/lib/invariant');
+const createReactClass = require('create-react-class');
+const invariant = require('invariant');
const requireNativeComponent = require('requireNativeComponent');
const warning = require('fbjs/lib/warning');
+import type {TextStyleProp, ViewStyleProp} from 'StyleSheet';
import type {ColorValue} from 'StyleSheetTypes';
-import type {TextStyleProp} from 'StyleSheet';
import type {ViewProps} from 'ViewPropTypes';
+import type {SyntheticEvent, ScrollEvent} from 'CoreEventTypes';
+import type {PressEvent} from 'CoreEventTypes';
let AndroidTextInput;
let RCTMultilineTextInputView;
@@ -56,11 +55,73 @@
children: true,
};
-type Event = Object;
-type Selection = {
+export type ChangeEvent = SyntheticEvent<
+ $ReadOnly<{|
+ eventCount: number,
+ target: number,
+ text: string,
+ |}>,
+>;
+
+export type TextInputEvent = SyntheticEvent<
+ $ReadOnly<{|
+ eventCount: number,
+ previousText: string,
+ range: $ReadOnly<{|
start: number,
- end?: number,
-};
+ end: number,
+ |}>,
+ target: number,
+ text: string,
+ |}>,
+>;
+
+export type ContentSizeChangeEvent = SyntheticEvent<
+ $ReadOnly<{|
+ target: number,
+ contentSize: $ReadOnly<{|
+ width: number,
+ height: number,
+ |}>,
+ |}>,
+>;
+
+type TargetEvent = SyntheticEvent<
+ $ReadOnly<{|
+ target: number,
+ |}>,
+>;
+
+export type BlurEvent = TargetEvent;
+export type FocusEvent = TargetEvent;
+
+type Selection = $ReadOnly<{|
+ start: number,
+ end: number,
+|}>;
+
+export type SelectionChangeEvent = SyntheticEvent<
+ $ReadOnly<{|
+ selection: Selection,
+ target: number,
+ |}>,
+>;
+
+export type KeyPressEvent = SyntheticEvent<
+ $ReadOnly<{|
+ key: string,
+ target?: ?number,
+ eventCount?: ?number,
+ |}>,
+>;
+
+export type EditingEvent = SyntheticEvent<
+ $ReadOnly<{|
+ eventCount: number,
+ text: string,
+ target: number,
+ |}>,
+>;
const DataDetectorTypes = [
'phoneNumber',
@@ -162,6 +223,21 @@
|}>;
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,
@@ -169,32 +245,40 @@
underlineColorAndroid?: ?ColorValue,
inlineImageLeft?: ?string,
inlineImagePadding?: ?number,
+ importantForAutofill?: ?(
+ | 'auto'
+ | 'no'
+ | 'noExcludeDescendants'
+ | 'yes'
+ | 'yesExcludeDescendants'
+ ),
|}>;
type Props = $ReadOnly<{|
- ...ViewProps,
+ ...$Diff<ViewProps, $ReadOnly<{|style: ?ViewStyleProp|}>>,
...IOSProps,
...AndroidProps,
autoCapitalize?: ?AutoCapitalize,
autoCorrect?: ?boolean,
autoFocus?: ?boolean,
allowFontScaling?: ?boolean,
+ maxFontSizeMultiplier?: ?number,
editable?: ?boolean,
keyboardType?: ?KeyboardType,
returnKeyType?: ?ReturnKeyType,
maxLength?: ?number,
multiline?: ?boolean,
- onBlur?: ?Function,
- onFocus?: ?Function,
- onChange?: ?Function,
- onChangeText?: ?Function,
- onContentSizeChange?: ?Function,
- onTextInput?: ?Function,
- onEndEditing?: ?Function,
- onSelectionChange?: ?Function,
- onSubmitEditing?: ?Function,
- onKeyPress?: ?Function,
- onScroll?: ?Function,
+ onBlur?: ?(e: BlurEvent) => mixed,
+ onFocus?: ?(e: FocusEvent) => mixed,
+ onChange?: ?(e: ChangeEvent) => mixed,
+ onChangeText?: ?(text: string) => mixed,
+ onContentSizeChange?: ?(e: ContentSizeChangeEvent) => mixed,
+ onTextInput?: ?(e: TextInputEvent) => mixed,
+ onEndEditing?: ?(e: EditingEvent) => mixed,
+ onSelectionChange?: ?(e: SelectionChangeEvent) => mixed,
+ onSubmitEditing?: ?(e: EditingEvent) => mixed,
+ onKeyPress?: ?(e: KeyPressEvent) => mixed,
+ onScroll?: ?(e: ScrollEvent) => mixed,
placeholder?: ?Stringish,
placeholderTextColor?: ?ColorValue,
secureTextEntry?: ?boolean,
@@ -212,6 +296,8 @@
contextMenuHidden?: ?boolean,
|}>;
+const emptyFunctionThatReturnsTrue = () => true;
+
/**
* A foundational component for inputting text into the app via a
* keyboard. Props provide configurability for several features, such as
@@ -334,7 +420,7 @@
},
},
propTypes: {
- ...ViewPropTypes,
+ ...DeprecatedViewPropTypes,
/**
* Can tell `TextInput` to automatically capitalize certain characters.
*
@@ -350,6 +436,45 @@
'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`.
*/
autoCorrect: PropTypes.bool,
@@ -370,6 +495,14 @@
*/
allowFontScaling: PropTypes.bool,
/**
+ * Specifies largest possible scale a font can reach when `allowFontScaling` is enabled.
+ * Possible values:
+ * `null/undefined` (default): inherit from the parent node or the global default (0)
+ * `0`: no max, ignore parent/global default
+ * `>= 1`: sets the maxFontSizeMultiplier of this node to this value
+ */
+ maxFontSizeMultiplier: PropTypes.number,
+ /**
* If `false`, text is not editable. The default value is `true`.
*/
editable: PropTypes.bool,
@@ -583,7 +716,7 @@
/**
* The text color of the placeholder string.
*/
- placeholderTextColor: ColorPropType,
+ placeholderTextColor: DeprecatedColorPropType,
/**
* If `false`, scrolling of the text view will be disabled.
* The default value is `true`. Does only work with 'multiline={true}'.
@@ -598,7 +731,7 @@
/**
* The highlight and cursor color of the text input.
*/
- selectionColor: ColorPropType,
+ selectionColor: DeprecatedColorPropType,
/**
* An instance of `DocumentSelectionState`, this is some state that is responsible for
* maintaining selection information for a document.
@@ -689,7 +822,7 @@
* The color of the `TextInput` underline.
* @platform android
*/
- underlineColorAndroid: ColorPropType,
+ underlineColorAndroid: DeprecatedColorPropType,
/**
* If defined, the provided image resource will be rendered on the left.
@@ -711,6 +844,15 @@
inlineImagePadding: PropTypes.number,
/**
+ * If `true`, allows TextInput to pass touch events to the parent component.
+ * This allows components such as SwipeableListView to be swipeable from the TextInput on iOS,
+ * as is the case on Android by default.
+ * If `false`, TextInput always asks to handle the input (except when disabled).
+ * @platform ios
+ */
+ rejectResponderTermination: PropTypes.bool,
+
+ /**
* Determines the types of data converted to clickable URLs in the text input.
* Only valid if `multiline={true}` and `editable={false}`.
* By default no data types are detected.
@@ -784,9 +926,10 @@
'oneTimeCode',
]),
},
- getDefaultProps(): Object {
+ getDefaultProps() {
return {
allowFontScaling: true,
+ rejectResponderTermination: true,
underlineColorAndroid: 'transparent',
};
},
@@ -794,7 +937,7 @@
* `NativeMethodsMixin` will look for this when invoking `setNativeProps`. We
* make `this` look like an actual native component class.
*/
- mixins: [NativeMethodsMixin, TimerMixin],
+ mixins: [NativeMethodsMixin],
/**
* Returns `true` if the input is currently focused; `false` otherwise.
@@ -810,6 +953,7 @@
_focusSubscription: (undefined: ?Function),
_lastNativeText: (undefined: ?string),
_lastNativeSelection: (undefined: ?Selection),
+ _rafId: (null: ?AnimationFrameID),
componentDidMount: function() {
this._lastNativeText = this.props.value;
@@ -819,24 +963,8 @@
TextInputState.registerInput(tag);
}
- if (this.context.focusEmitter) {
- this._focusSubscription = this.context.focusEmitter.addListener(
- 'focus',
- el => {
- if (this === el) {
- this.requestAnimationFrame(this.focus);
- } else if (this.isFocused()) {
- this.blur();
- }
- },
- );
- if (this.props.autoFocus) {
- this.context.onFocusRequested(this);
- }
- } else {
if (this.props.autoFocus) {
- this.requestAnimationFrame(this.focus);
- }
+ this._rafId = requestAnimationFrame(this.focus);
}
},
@@ -849,11 +977,9 @@
if (tag != null) {
TextInputState.unregisterInput(tag);
}
- },
-
- contextTypes: {
- onFocusRequested: PropTypes.func,
- focusEmitter: PropTypes.instanceOf(EventEmitter),
+ if (this._rafId != null) {
+ cancelAnimationFrame(this._rafId);
+ }
},
/**
@@ -866,7 +992,7 @@
render: function() {
let textInput;
if (Platform.OS === 'ios') {
- textInput = UIManager.RCTVirtualText
+ textInput = UIManager.getViewManagerConfig('RCTVirtualText')
? this._renderIOS()
: this._renderIOSLegacy();
} else if (Platform.OS === 'android') {
@@ -923,7 +1049,7 @@
onBlur={this._onBlur}
onChange={this._onChange}
onSelectionChange={this._onSelectionChange}
- onSelectionChangeShouldSetResponder={emptyFunction.thatReturnsTrue}
+ onSelectionChangeShouldSetResponder={emptyFunctionThatReturnsTrue}
text={this._getText()}
/>
);
@@ -937,7 +1063,10 @@
);
if (childCount >= 1) {
children = (
- <Text style={props.style} allowFontScaling={props.allowFontScaling}>
+ <Text
+ style={props.style}
+ allowFontScaling={props.allowFontScaling}
+ maxFontSizeMultiplier={props.maxFontSizeMultiplier}>
{children}
</Text>
);
@@ -957,7 +1086,7 @@
onContentSizeChange={this.props.onContentSizeChange}
onSelectionChange={this._onSelectionChange}
onTextInput={this._onTextInput}
- onSelectionChangeShouldSetResponder={emptyFunction.thatReturnsTrue}
+ onSelectionChangeShouldSetResponder={emptyFunctionThatReturnsTrue}
text={this._getText()}
dataDetectorTypes={this.props.dataDetectorTypes}
onScroll={this._onScroll}
@@ -1010,7 +1139,7 @@
onContentSizeChange={this.props.onContentSizeChange}
onSelectionChange={this._onSelectionChange}
onTextInput={this._onTextInput}
- onSelectionChangeShouldSetResponder={emptyFunction.thatReturnsTrue}
+ onSelectionChangeShouldSetResponder={emptyFunctionThatReturnsTrue}
text={this._getText()}
dataDetectorTypes={this.props.dataDetectorTypes}
onScroll={this._onScroll}
@@ -1021,7 +1150,7 @@
<TouchableWithoutFeedback
onLayout={props.onLayout}
onPress={this._onPress}
- rejectResponderTermination={true}
+ rejectResponderTermination={props.rejectResponderTermination}
accessible={props.accessible}
accessibilityLabel={props.accessibilityLabel}
accessibilityRole={props.accessibilityRole}
@@ -1036,10 +1165,9 @@
_renderAndroid: function() {
const props = Object.assign({}, this.props);
props.style = [this.props.style];
- props.autoCapitalize =
- UIManager.AndroidTextInput.Constants.AutoCapitalizationType[
- props.autoCapitalize || 'sentences'
- ];
+ props.autoCapitalize = UIManager.getViewManagerConfig(
+ 'AndroidTextInput',
+ ).Constants.AutoCapitalizationType[props.autoCapitalize || 'sentences'];
/* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This comment
* suppresses an error when upgrading Flow's support for React. To see the
* error delete this comment and run Flow. */
@@ -1094,7 +1222,7 @@
);
},
- _onFocus: function(event: Event) {
+ _onFocus: function(event: FocusEvent) {
if (this.props.onFocus) {
this.props.onFocus(event);
}
@@ -1104,16 +1232,16 @@
}
},
- _onPress: function(event: Event) {
+ _onPress: function(event: PressEvent) {
if (this.props.editable || this.props.editable === undefined) {
this.focus();
}
},
- _onChange: function(event: Event) {
+ _onChange: function(event: ChangeEvent) {
// Make sure to fire the mostRecentEventCount first so it is already set on
// native when the text value is set.
- if (this._inputRef) {
+ if (this._inputRef && this._inputRef.setNativeProps) {
this._inputRef.setNativeProps({
mostRecentEventCount: event.nativeEvent.eventCount,
});
@@ -1133,7 +1261,7 @@
this.forceUpdate();
},
- _onSelectionChange: function(event: Event) {
+ _onSelectionChange: function(event: SelectionChangeEvent) {
this.props.onSelectionChange && this.props.onSelectionChange(event);
if (!this._inputRef) {
@@ -1174,7 +1302,11 @@
nativeProps.selection = this.props.selection;
}
- if (Object.keys(nativeProps).length > 0 && this._inputRef) {
+ if (
+ Object.keys(nativeProps).length > 0 &&
+ this._inputRef &&
+ this._inputRef.setNativeProps
+ ) {
this._inputRef.setNativeProps(nativeProps);
}
@@ -1183,7 +1315,9 @@
}
},
- _onBlur: function(event: Event) {
+ _onBlur: function(event: BlurEvent) {
+ // This is a hack to fix https://fburl.com/toehyir8
+ // @todo(rsnara) Figure out why this is necessary.
this.blur();
if (this.props.onBlur) {
this.props.onBlur(event);
@@ -1194,11 +1328,11 @@
}
},
- _onTextInput: function(event: Event) {
+ _onTextInput: function(event: TextInputEvent) {
this.props.onTextInput && this.props.onTextInput(event);
},
- _onScroll: function(event: Event) {
+ _onScroll: function(event: ScrollEvent) {
this.props.onScroll && this.props.onScroll(event);
},
});

Libraries/Components/TextInput/TextInputState.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -42,7 +42,8 @@
} else if (Platform.OS === 'android') {
UIManager.dispatchViewManagerCommand(
textFieldID,
- UIManager.AndroidTextInput.Commands.focusTextInput,
+ UIManager.getViewManagerConfig('AndroidTextInput').Commands
+ .focusTextInput,
null,
);
}
@@ -62,7 +63,8 @@
} else if (Platform.OS === 'android') {
UIManager.dispatchViewManagerCommand(
textFieldID,
- UIManager.AndroidTextInput.Commands.blurTextInput,
+ UIManager.getViewManagerConfig('AndroidTextInput').Commands
+ .blurTextInput,
null,
);
}

Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js

@@ -1,17 +1,22 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
- * @flow
+ * @flow strict-local
*/
'use strict';
const TimePickerModule = require('NativeModules').TimePickerAndroid;
+import type {
+ TimePickerOptions,
+ TimePickerResult,
+} from './TimePickerAndroidTypes';
+
/**
* Opens the standard Android time picker dialog.
*
@@ -52,22 +57,18 @@
* still be resolved with action being `TimePickerAndroid.dismissedAction` and all the other keys
* being undefined. **Always** check whether the `action` before reading the values.
*/
- static async open(options: Object): Promise<Object> {
+ static async open(options: TimePickerOptions): Promise<TimePickerResult> {
return TimePickerModule.open(options);
}
/**
* A time has been selected.
*/
- static get timeSetAction() {
- return 'timeSetAction';
- }
+ static +timeSetAction: 'timeSetAction' = 'timeSetAction';
/**
* The dialog has been dismissed.
*/
- static get dismissedAction() {
- return 'dismissedAction';
- }
+ static +dismissedAction: 'dismissedAction' = 'dismissedAction';
}
module.exports = TimePickerAndroid;

Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js

@@ -1,17 +1,22 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
- * @flow
+ * @flow strict-local
*/
'use strict';
+import type {
+ TimePickerOptions,
+ TimePickerResult,
+} from './TimePickerAndroidTypes';
+
const TimePickerAndroid = {
- async open(options: Object): Promise<Object> {
+ async open(options: TimePickerOptions): Promise<TimePickerResult> {
return Promise.reject({
message: 'TimePickerAndroid is not supported on this platform.',
});

Libraries/Components/TimePickerAndroid/TimePickerAndroidTypes.js

@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow strict-local
+ */
+
+'use strict';
+
+export type TimePickerOptions = {|
+ hour?: number,
+ minute?: number,
+ is24Hour?: boolean,
+ mode?: 'clock' | 'spinner' | 'default',
+|};
+
+export type TimePickerResult = $ReadOnly<{|
+ action: string,
+ hour: number,
+ minute: number,
+|}>;

Libraries/Components/ToastAndroid/ToastAndroid.android.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/ToastAndroid/ToastAndroid.ios.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js

@@ -1,32 +1,26 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
+ * @flow
*/
'use strict';
-const Image = require('Image');
-const NativeMethodsMixin = require('NativeMethodsMixin');
const React = require('React');
-const PropTypes = require('prop-types');
const UIManager = require('UIManager');
-const ViewPropTypes = require('ViewPropTypes');
-const ColorPropType = require('ColorPropType');
-const createReactClass = require('create-react-class');
-const requireNativeComponent = require('requireNativeComponent');
+const ToolbarAndroidNativeComponent = require('ToolbarAndroidNativeComponent');
const resolveAssetSource = require('resolveAssetSource');
-const optionalImageSource = PropTypes.oneOfType([
- Image.propTypes.source,
- // Image.propTypes.source is required but we want it to be optional, so we OR
- // it with a nullable propType.
- PropTypes.oneOf([]),
-]);
+import type {SyntheticEvent} from 'CoreEventTypes';
+import type {ImageSource} from 'ImageSource';
+import type {ColorValue} from 'StyleSheetTypes';
+import type {ViewProps} from 'ViewPropTypes';
+import type {NativeComponent} from 'ReactNative';
/**
* React component that wraps the Android-only [`Toolbar` widget][0]. A Toolbar can display a logo,
@@ -63,15 +57,25 @@
*
* [0]: https://developer.android.com/reference/android/support/v7/widget/Toolbar.html
*/
-const ToolbarAndroid = createReactClass({
- displayName: 'ToolbarAndroid',
- mixins: [NativeMethodsMixin],
- propTypes: {
- ...ViewPropTypes,
+type Action = $ReadOnly<{|
+ title: string,
+ icon?: ?ImageSource,
+ show?: 'always' | 'ifRoom' | 'never',
+ showWithText?: boolean,
+|}>;
+
+type ToolbarAndroidChangeEvent = SyntheticEvent<
+ $ReadOnly<{|
+ position: number,
+ |}>,
+>;
+
+type ToolbarAndroidProps = $ReadOnly<{|
+ ...ViewProps,
/**
- * Sets possible actions on the toolbar as part of the action menu. These are displayed as icons
* or text on the right side of the widget. If they don't fit they are placed in an 'overflow'
+ * Sets possible actions on the toolbar as part of the action menu. These are displayed as icons
* menu.
*
* This property takes an array of objects, where each object has the following keys:
@@ -82,51 +86,44 @@
* `ifRoom` or `never`
* * `showWithText`: boolean, whether to show text alongside the icon or not
*/
- actions: PropTypes.arrayOf(
- PropTypes.shape({
- title: PropTypes.string.isRequired,
- icon: optionalImageSource,
- show: PropTypes.oneOf(['always', 'ifRoom', 'never']),
- showWithText: PropTypes.bool,
- }),
- ),
+ actions?: ?Array<Action>,
/**
* Sets the toolbar logo.
*/
- logo: optionalImageSource,
+ logo?: ?ImageSource,
/**
* Sets the navigation icon.
*/
- navIcon: optionalImageSource,
+ navIcon?: ?ImageSource,
/**
* Callback that is called when an action is selected. The only argument that is passed to the
* callback is the position of the action in the actions array.
*/
- onActionSelected: PropTypes.func,
+ onActionSelected?: ?(position: number) => void,
/**
* Callback called when the icon is selected.
*/
- onIconClicked: PropTypes.func,
+ onIconClicked?: ?() => void,
/**
* Sets the overflow icon.
*/
- overflowIcon: optionalImageSource,
+ overflowIcon?: ?ImageSource,
/**
* Sets the toolbar subtitle.
*/
- subtitle: PropTypes.string,
+ subtitle?: ?string,
/**
* Sets the toolbar subtitle color.
*/
- subtitleColor: ColorPropType,
+ subtitleColor?: ?ColorValue,
/**
* Sets the toolbar title.
*/
- title: PropTypes.string,
+ title?: ?Stringish,
/**
* Sets the toolbar title color.
*/
- titleColor: ColorPropType,
+ titleColor?: ?ColorValue,
/**
* Sets the content inset for the toolbar starting edge.
*
@@ -135,7 +132,7 @@
* these components and can be used to effectively align Toolbar content
* along well-known gridlines.
*/
- contentInsetStart: PropTypes.number,
+ contentInsetStart?: ?number,
/**
* Sets the content inset for the toolbar ending edge.
*
@@ -144,7 +141,7 @@
* these components and can be used to effectively align Toolbar content
* along well-known gridlines.
*/
- contentInsetEnd: PropTypes.number,
+ contentInsetEnd?: ?number,
/**
* Used to set the toolbar direction to RTL.
* In addition to this property you need to add
@@ -155,17 +152,40 @@
* `setLayoutDirection(LayoutDirection.RTL)` in your MainActivity
* `onCreate` method.
*/
- rtl: PropTypes.bool,
+ rtl?: ?boolean,
/**
* Used to locate this view in end-to-end tests.
*/
- testID: PropTypes.string,
- },
+ testID?: ?string,
+|}>;
+
+type Props = $ReadOnly<{|
+ ...ToolbarAndroidProps,
+ forwardedRef: ?React.Ref<typeof ToolbarAndroidNativeComponent>,
+|}>;
+
+class ToolbarAndroid extends React.Component<Props> {
+ _onSelect = (event: ToolbarAndroidChangeEvent) => {
+ const position = event.nativeEvent.position;
+ if (position === -1) {
+ this.props.onIconClicked && this.props.onIconClicked();
+ } else {
+ this.props.onActionSelected && this.props.onActionSelected(position);
+ }
+ };
+
+ render() {
+ const {
+ onIconClicked,
+ onActionSelected,
+ forwardedRef,
+ ...otherProps
+ } = this.props;
- render: function() {
- const nativeProps = {
- ...this.props,
+ const nativeProps: {...typeof otherProps, nativeActions?: Array<Action>} = {
+ ...otherProps,
};
+
if (this.props.logo) {
nativeProps.logo = resolveAssetSource(this.props.logo);
}
@@ -175,37 +197,55 @@
if (this.props.overflowIcon) {
nativeProps.overflowIcon = resolveAssetSource(this.props.overflowIcon);
}
+
if (this.props.actions) {
const nativeActions = [];
for (let i = 0; i < this.props.actions.length; i++) {
const action = {
- ...this.props.actions[i],
+ icon: this.props.actions[i].icon,
+ show: this.props.actions[i].show,
};
+
if (action.icon) {
action.icon = resolveAssetSource(action.icon);
}
if (action.show) {
- action.show =
- UIManager.ToolbarAndroid.Constants.ShowAsAction[action.show];
+ action.show = UIManager.getViewManagerConfig(
+ 'ToolbarAndroid',
+ ).Constants.ShowAsAction[action.show];
}
- nativeActions.push(action);
+
+ nativeActions.push({
+ ...this.props.actions[i],
+ ...action,
+ });
}
+
nativeProps.nativeActions = nativeActions;
}
- return <NativeToolbar onSelect={this._onSelect} {...nativeProps} />;
- },
-
- _onSelect: function(event) {
- const position = event.nativeEvent.position;
- if (position === -1) {
- this.props.onIconClicked && this.props.onIconClicked();
- } else {
- this.props.onActionSelected && this.props.onActionSelected(position);
- }
+ return (
+ <ToolbarAndroidNativeComponent
+ onSelect={this._onSelect}
+ {...nativeProps}
+ ref={forwardedRef}
+ />
+ );
+ }
+}
+
+const ToolbarAndroidToExport = React.forwardRef(
+ (
+ props: ToolbarAndroidProps,
+ forwardedRef: ?React.Ref<typeof ToolbarAndroidNativeComponent>,
+ ) => {
+ return <ToolbarAndroid {...props} forwardedRef={forwardedRef} />;
},
-});
-
-const NativeToolbar = requireNativeComponent('ToolbarAndroid');
+);
-module.exports = ToolbarAndroid;
+/* $FlowFixMe(>=0.89.0 site=react_native_android_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
+module.exports = (ToolbarAndroidToExport: Class<
+ NativeComponent<ToolbarAndroidProps>,
+>);

Libraries/Components/ToolbarAndroid/ToolbarAndroid.ios.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/ToolbarAndroid/ToolbarAndroidNativeComponent.js

@@ -0,0 +1,133 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow
+ */
+
+'use strict';
+
+const requireNativeComponent = require('requireNativeComponent');
+
+import type {SyntheticEvent} from 'CoreEventTypes';
+import type {ImageSource} from 'ImageSource';
+import type {ViewProps} from 'ViewPropTypes';
+import type {NativeComponent} from 'ReactNative';
+
+type Action = $ReadOnly<{|
+ title: string,
+ icon?: ?ImageSource,
+ show?: 'always' | 'ifRoom' | 'never',
+ showWithText?: boolean,
+|}>;
+
+type ToolbarAndroidChangeEvent = SyntheticEvent<
+ $ReadOnly<{|
+ position: number,
+ |}>,
+>;
+
+type NativeProps = $ReadOnly<{|
+ onSelect: (event: ToolbarAndroidChangeEvent) => mixed,
+ nativeActions?: Array<Action>,
+|}>;
+
+type ColorValue = null | string;
+
+type ToolbarAndroidProps = $ReadOnly<{|
+ ...ViewProps,
+ ...NativeProps,
+ /**
+ * or text on the right side of the widget. If they don't fit they are placed in an 'overflow'
+ * Sets possible actions on the toolbar as part of the action menu. These are displayed as icons
+ * menu.
+ *
+ * This property takes an array of objects, where each object has the following keys:
+ *
+ * * `title`: **required**, the title of this action
+ * * `icon`: the icon for this action, e.g. `require('./some_icon.png')`
+ * * `show`: when to show this action as an icon or hide it in the overflow menu: `always`,
+ * `ifRoom` or `never`
+ * * `showWithText`: boolean, whether to show text alongside the icon or not
+ */
+ actions?: ?Array<Action>,
+ /**
+ * Sets the toolbar logo.
+ */
+ logo?: ?ImageSource,
+ /**
+ * Sets the navigation icon.
+ */
+ navIcon?: ?ImageSource,
+ /**
+ * Callback that is called when an action is selected. The only argument that is passed to the
+ * callback is the position of the action in the actions array.
+ */
+ onActionSelected?: ?(position: number) => void,
+ /**
+ * Callback called when the icon is selected.
+ */
+ onIconClicked?: ?() => void,
+ /**
+ * Sets the overflow icon.
+ */
+ overflowIcon?: ?ImageSource,
+ /**
+ * Sets the toolbar subtitle.
+ */
+ subtitle?: ?string,
+ /**
+ * Sets the toolbar subtitle color.
+ */
+ subtitleColor?: ?ColorValue,
+ /**
+ * Sets the toolbar title.
+ */
+ title?: ?Stringish,
+ /**
+ * Sets the toolbar title color.
+ */
+ titleColor?: ?ColorValue,
+ /**
+ * Sets the content inset for the toolbar starting edge.
+ *
+ * The content inset affects the valid area for Toolbar content other than
+ * the navigation button and menu. Insets define the minimum margin for
+ * these components and can be used to effectively align Toolbar content
+ * along well-known gridlines.
+ */
+ contentInsetStart?: ?number,
+ /**
+ * Sets the content inset for the toolbar ending edge.
+ *
+ * The content inset affects the valid area for Toolbar content other than
+ * the navigation button and menu. Insets define the minimum margin for
+ * these components and can be used to effectively align Toolbar content
+ * along well-known gridlines.
+ */
+ contentInsetEnd?: ?number,
+ /**
+ * Used to set the toolbar direction to RTL.
+ * In addition to this property you need to add
+ *
+ * android:supportsRtl="true"
+ *
+ * to your application AndroidManifest.xml and then call
+ * `setLayoutDirection(LayoutDirection.RTL)` in your MainActivity
+ * `onCreate` method.
+ */
+ rtl?: ?boolean,
+ /**
+ * Used to locate this view in end-to-end tests.
+ */
+ testID?: ?string,
+|}>;
+
+type NativeToolbarAndroidProps = Class<NativeComponent<ToolbarAndroidProps>>;
+
+module.exports = ((requireNativeComponent(
+ 'ToolbarAndroid',
+): any): NativeToolbarAndroidProps);

Libraries/Components/Touchable/BoundingDimensions.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/Touchable/ensureComponentIsNative.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,7 +10,7 @@
'use strict';
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
const ensureComponentIsNative = function(component: any) {
invariant(

Libraries/Components/Touchable/ensurePositiveDelayProps.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,7 +10,7 @@
'use strict';
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
const ensurePositiveDelayProps = function(props: any) {
invariant(

Libraries/Components/Touchable/__mocks__/ensureComponentIsNative.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/Touchable/PooledClass.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -10,7 +10,7 @@
'use strict';
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
/**
* Static poolers. Several custom versions for each potential number of

Libraries/Components/Touchable/Position.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/Touchable/TouchableBounce.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,20 +10,21 @@
'use strict';
const Animated = require('Animated');
-const EdgeInsetsPropType = require('EdgeInsetsPropType');
+const DeprecatedViewPropTypes = require('DeprecatedViewPropTypes');
+const DeprecatedEdgeInsetsPropType = require('DeprecatedEdgeInsetsPropType');
const NativeMethodsMixin = require('NativeMethodsMixin');
-const React = require('React');
-const createReactClass = require('create-react-class');
+const Platform = require('Platform');
const PropTypes = require('prop-types');
+const React = require('React');
const Touchable = require('Touchable');
const TouchableWithoutFeedback = require('TouchableWithoutFeedback');
-const ViewPropTypes = require('ViewPropTypes');
+
+const createReactClass = require('create-react-class');
import type {EdgeInsetsProp} from 'EdgeInsetsPropType';
-import type {Props as TouchableWithoutFeedbackProps} from 'TouchableWithoutFeedback';
import type {ViewStyleProp} from 'StyleSheet';
-
-type Event = Object;
+import type {Props as TouchableWithoutFeedbackProps} from 'TouchableWithoutFeedback';
+import type {PressEvent} from 'CoreEventTypes';
type State = {
animationID: ?number,
@@ -35,8 +36,8 @@
type Props = $ReadOnly<{|
...TouchableWithoutFeedbackProps,
- onPressWithCompletion?: ?Function,
- onPressAnimationComplete?: ?Function,
+ onPressWithCompletion?: ?(fn: () => void) => void,
+ onPressAnimationComplete?: ?() => void,
pressRetentionOffset?: ?EdgeInsetsProp,
releaseVelocity?: ?number,
releaseBounciness?: ?number,
@@ -52,9 +53,12 @@
*/
const TouchableBounce = ((createReactClass({
displayName: 'TouchableBounce',
- mixins: [Touchable.Mixin, NativeMethodsMixin],
+ mixins: [Touchable.Mixin.withoutDefaultFocusAndBlur, NativeMethodsMixin],
propTypes: {
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
...TouchableWithoutFeedback.propTypes,
// The function passed takes a callback to start the animation which should
// be run after this onPress handler is done. You can use this (for example)
@@ -69,14 +73,14 @@
* reactivated! Move it back and forth several times while the scroll view
* is disabled. Ensure you pass in a constant to reduce memory allocations.
*/
- pressRetentionOffset: EdgeInsetsPropType,
+ pressRetentionOffset: DeprecatedEdgeInsetsPropType,
releaseVelocity: PropTypes.number.isRequired,
releaseBounciness: PropTypes.number.isRequired,
/**
* Style to apply to the container/underlay. Most commonly used to make sure
* rounded corners match the wrapped component.
*/
- style: ViewPropTypes.style,
+ style: DeprecatedViewPropTypes.style,
},
getDefaultProps: function() {
@@ -85,6 +89,9 @@
getInitialState: function(): State {
return {
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete
+ * this comment and run Flow. */
...this.touchableGetInitialState(),
scale: new Animated.Value(1),
};
@@ -94,7 +101,7 @@
value: number,
velocity: number,
bounciness: number,
- callback?: ?Function,
+ callback?: ?() => void,
) {
Animated.spring(this.state.scale, {
toValue: value,
@@ -108,17 +115,31 @@
* `Touchable.Mixin` self callbacks. The mixin will invoke these if they are
* defined on your component.
*/
- touchableHandleActivePressIn: function(e: Event) {
+ touchableHandleActivePressIn: function(e: PressEvent) {
this.bounceTo(0.93, 0.1, 0);
this.props.onPressIn && this.props.onPressIn(e);
},
- touchableHandleActivePressOut: function(e: Event) {
+ touchableHandleActivePressOut: function(e: PressEvent) {
this.bounceTo(1, 0.4, 0);
this.props.onPressOut && this.props.onPressOut(e);
},
- touchableHandlePress: function(e: Event) {
+ touchableHandleFocus: function(e: Event) {
+ if (Platform.isTV) {
+ this.bounceTo(0.93, 0.1, 0);
+ }
+ this.props.onFocus && this.props.onFocus(e);
+ },
+
+ touchableHandleBlur: function(e: Event) {
+ if (Platform.isTV) {
+ this.bounceTo(1, 0.4, 0);
+ }
+ this.props.onBlur && this.props.onBlur(e);
+ },
+
+ touchableHandlePress: function(e: PressEvent) {
const onPressWithCompletion = this.props.onPressWithCompletion;
if (onPressWithCompletion) {
onPressWithCompletion(() => {
@@ -146,7 +167,7 @@
return this.props.pressRetentionOffset || PRESS_RETENTION_OFFSET;
},
- touchableGetHitSlop: function(): ?Object {
+ touchableGetHitSlop: function(): ?EdgeInsetsProp {
return this.props.hitSlop;
},
@@ -166,13 +187,31 @@
nativeID={this.props.nativeID}
testID={this.props.testID}
hitSlop={this.props.hitSlop}
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete
+ * this comment and run Flow. */
onStartShouldSetResponder={this.touchableHandleStartShouldSetResponder}
onResponderTerminationRequest={
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses
+ * an error found when Flow v0.89 was deployed. To see the error,
+ * delete this comment and run Flow. */
this.touchableHandleResponderTerminationRequest
}
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete
+ * this comment and run Flow. */
onResponderGrant={this.touchableHandleResponderGrant}
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete
+ * this comment and run Flow. */
onResponderMove={this.touchableHandleResponderMove}
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete
+ * this comment and run Flow. */
onResponderRelease={this.touchableHandleResponderRelease}
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete
+ * this comment and run Flow. */
onResponderTerminate={this.touchableHandleResponderTerminate}>
{this.props.children}
{Touchable.renderDebugView({

Libraries/Components/Touchable/TouchableHighlight.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,25 +9,26 @@
*/
'use strict';
-const ColorPropType = require('ColorPropType');
+const DeprecatedColorPropType = require('DeprecatedColorPropType');
+const DeprecatedViewPropTypes = require('DeprecatedViewPropTypes');
const NativeMethodsMixin = require('NativeMethodsMixin');
-const PropTypes = require('prop-types');
const Platform = require('Platform');
+const PropTypes = require('prop-types');
const React = require('React');
const ReactNativeViewAttributes = require('ReactNativeViewAttributes');
const StyleSheet = require('StyleSheet');
const Touchable = require('Touchable');
const TouchableWithoutFeedback = require('TouchableWithoutFeedback');
const View = require('View');
-const ViewPropTypes = require('ViewPropTypes');
const createReactClass = require('create-react-class');
const ensurePositiveDelayProps = require('ensurePositiveDelayProps');
import type {PressEvent} from 'CoreEventTypes';
-import type {Props as TouchableWithoutFeedbackProps} from 'TouchableWithoutFeedback';
import type {ViewStyleProp} from 'StyleSheet';
import type {ColorValue} from 'StyleSheetTypes';
+import type {Props as TouchableWithoutFeedbackProps} from 'TouchableWithoutFeedback';
+import type {TVParallaxPropertiesType} from 'TVViewPropTypes';
const DEFAULT_PROPS = {
activeOpacity: 0.85,
@@ -39,7 +40,7 @@
type IOSProps = $ReadOnly<{|
hasTVPreferredFocus?: ?boolean,
- tvParallaxProperties?: ?Object,
+ tvParallaxProperties?: ?TVParallaxPropertiesType,
|}>;
type Props = $ReadOnly<{|
@@ -49,8 +50,8 @@
activeOpacity?: ?number,
underlayColor?: ?ColorValue,
style?: ?ViewStyleProp,
- onShowUnderlay?: ?Function,
- onHideUnderlay?: ?Function,
+ onShowUnderlay?: ?() => void,
+ onHideUnderlay?: ?() => void,
testOnly_pressed?: ?boolean,
|}>;
@@ -154,6 +155,9 @@
const TouchableHighlight = ((createReactClass({
displayName: 'TouchableHighlight',
propTypes: {
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
...TouchableWithoutFeedback.propTypes,
/**
* Determines what the opacity of the wrapped view should be when touch is
@@ -164,12 +168,12 @@
* The color of the underlay that will show through when the touch is
* active.
*/
- underlayColor: ColorPropType,
+ underlayColor: DeprecatedColorPropType,
/**
* Style to apply to the container/underlay. Most commonly used to make sure
* rounded corners match the wrapped component.
*/
- style: ViewPropTypes.style,
+ style: DeprecatedViewPropTypes.style,
/**
* Called immediately after the underlay is shown
*/
@@ -185,18 +189,7 @@
*/
hasTVPreferredFocus: PropTypes.bool,
/**
- * *(Apple TV only)* Object with properties to control Apple TV parallax effects.
- *
- * enabled: If true, parallax effects are enabled. Defaults to true.
- * shiftDistanceX: Defaults to 2.0.
- * shiftDistanceY: Defaults to 2.0.
- * tiltAngle: Defaults to 0.05.
- * magnification: Defaults to 1.0.
- * pressMagnification: Defaults to 1.0.
- * pressDuration: Defaults to 0.3.
- * pressDelay: Defaults to 0.0.
- *
- * @platform ios
+ * Apple TV parallax effects
*/
tvParallaxProperties: PropTypes.object,
/**
@@ -205,14 +198,20 @@
testOnly_pressed: PropTypes.bool,
},
- mixins: [NativeMethodsMixin, Touchable.Mixin],
+ mixins: [NativeMethodsMixin, Touchable.Mixin.withoutDefaultFocusAndBlur],
getDefaultProps: () => DEFAULT_PROPS,
getInitialState: function() {
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
this._isMounted = false;
if (this.props.testOnly_pressed) {
return {
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete
+ * this comment and run Flow. */
...this.touchableGetInitialState(),
extraChildStyle: {
opacity: this.props.activeOpacity,
@@ -223,6 +222,9 @@
};
} else {
return {
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete
+ * this comment and run Flow. */
...this.touchableGetInitialState(),
extraChildStyle: null,
extraUnderlayStyle: null,
@@ -231,12 +233,21 @@
},
componentDidMount: function() {
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
this._isMounted = true;
ensurePositiveDelayProps(this.props);
},
componentWillUnmount: function() {
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
this._isMounted = false;
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
clearTimeout(this._hideTimeout);
},
@@ -254,23 +265,52 @@
* defined on your component.
*/
touchableHandleActivePressIn: function(e: PressEvent) {
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
clearTimeout(this._hideTimeout);
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
this._hideTimeout = null;
this._showUnderlay();
this.props.onPressIn && this.props.onPressIn(e);
},
touchableHandleActivePressOut: function(e: PressEvent) {
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
if (!this._hideTimeout) {
this._hideUnderlay();
}
this.props.onPressOut && this.props.onPressOut(e);
},
+ touchableHandleFocus: function(e: Event) {
+ if (Platform.isTV) {
+ this._showUnderlay();
+ }
+ this.props.onFocus && this.props.onFocus(e);
+ },
+
+ touchableHandleBlur: function(e: Event) {
+ if (Platform.isTV) {
+ this._hideUnderlay();
+ }
+ this.props.onBlur && this.props.onBlur(e);
+ },
+
touchableHandlePress: function(e: PressEvent) {
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
clearTimeout(this._hideTimeout);
if (!Platform.isTV) {
this._showUnderlay();
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete
+ * this comment and run Flow. */
this._hideTimeout = setTimeout(
this._hideUnderlay,
this.props.delayPressOut,
@@ -304,6 +344,9 @@
},
_showUnderlay: function() {
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
if (!this._isMounted || !this._hasPressHandler()) {
return;
}
@@ -319,7 +362,13 @@
},
_hideUnderlay: function() {
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
clearTimeout(this._hideTimeout);
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
this._hideTimeout = null;
if (this.props.testOnly_pressed) {
return;
@@ -360,13 +409,31 @@
isTVSelectable={true}
tvParallaxProperties={this.props.tvParallaxProperties}
hasTVPreferredFocus={this.props.hasTVPreferredFocus}
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete
+ * this comment and run Flow. */
onStartShouldSetResponder={this.touchableHandleStartShouldSetResponder}
onResponderTerminationRequest={
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses
+ * an error found when Flow v0.89 was deployed. To see the error,
+ * delete this comment and run Flow. */
this.touchableHandleResponderTerminationRequest
}
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete
+ * this comment and run Flow. */
onResponderGrant={this.touchableHandleResponderGrant}
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete
+ * this comment and run Flow. */
onResponderMove={this.touchableHandleResponderMove}
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete
+ * this comment and run Flow. */
onResponderRelease={this.touchableHandleResponderRelease}
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete
+ * this comment and run Flow. */
onResponderTerminate={this.touchableHandleResponderTerminate}
nativeID={this.props.nativeID}
testID={this.props.testID}>

Libraries/Components/Touchable/Touchable.js

@@ -1,9 +1,10 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
*
+ * @flow
* @format
*/
@@ -14,14 +15,30 @@
const Position = require('Position');
const React = require('React');
const ReactNative = require('ReactNative');
+const StyleSheet = require('StyleSheet');
const TVEventHandler = require('TVEventHandler');
-const TouchEventUtils = require('fbjs/lib/TouchEventUtils');
const UIManager = require('UIManager');
const View = require('View');
const keyMirror = require('fbjs/lib/keyMirror');
const normalizeColor = require('normalizeColor');
+import type {PressEvent} from 'CoreEventTypes';
+import type {EdgeInsetsProp} from 'EdgeInsetsPropType';
+
+const extractSingleTouch = nativeEvent => {
+ const touches = nativeEvent.touches;
+ const changedTouches = nativeEvent.changedTouches;
+ const hasTouches = touches && touches.length > 0;
+ const hasChangedTouches = changedTouches && changedTouches.length > 0;
+
+ return !hasTouches && hasChangedTouches
+ ? changedTouches[0]
+ : hasTouches
+ ? touches[0]
+ : nativeEvent;
+};
+
/**
* `Touchable`: Taps done right.
*
@@ -121,10 +139,33 @@
ERROR: null,
});
-/**
+type State =
+ | typeof States.NOT_RESPONDER
+ | typeof States.RESPONDER_INACTIVE_PRESS_IN
+ | typeof States.RESPONDER_INACTIVE_PRESS_OUT
+ | typeof States.RESPONDER_ACTIVE_PRESS_IN
+ | typeof States.RESPONDER_ACTIVE_PRESS_OUT
+ | typeof States.RESPONDER_ACTIVE_LONG_PRESS_IN
+ | typeof States.RESPONDER_ACTIVE_LONG_PRESS_OUT
+ | typeof States.ERROR;
+
+/*
* Quick lookup map for states that are considered to be "active"
*/
+
+const baseStatesConditions = {
+ NOT_RESPONDER: false,
+ RESPONDER_INACTIVE_PRESS_IN: false,
+ RESPONDER_INACTIVE_PRESS_OUT: false,
+ RESPONDER_ACTIVE_PRESS_IN: false,
+ RESPONDER_ACTIVE_PRESS_OUT: false,
+ RESPONDER_ACTIVE_LONG_PRESS_IN: false,
+ RESPONDER_ACTIVE_LONG_PRESS_OUT: false,
+ ERROR: false,
+};
+
const IsActive = {
+ ...baseStatesConditions,
RESPONDER_ACTIVE_PRESS_OUT: true,
RESPONDER_ACTIVE_PRESS_IN: true,
};
@@ -134,12 +175,14 @@
* therefore eligible to result in a "selection" if the press stops.
*/
const IsPressingIn = {
+ ...baseStatesConditions,
RESPONDER_INACTIVE_PRESS_IN: true,
RESPONDER_ACTIVE_PRESS_IN: true,
RESPONDER_ACTIVE_LONG_PRESS_IN: true,
};
const IsLongPressingIn = {
+ ...baseStatesConditions,
RESPONDER_ACTIVE_LONG_PRESS_IN: true,
};
@@ -156,6 +199,15 @@
LONG_PRESS_DETECTED: null,
});
+type Signal =
+ | typeof Signals.DELAY
+ | typeof Signals.RESPONDER_GRANT
+ | typeof Signals.RESPONDER_RELEASE
+ | typeof Signals.RESPONDER_TERMINATED
+ | typeof Signals.ENTER_PRESS_RECT
+ | typeof Signals.LEAVE_PRESS_RECT
+ | typeof Signals.LONG_PRESS_DETECTED;
+
/**
* Mapping from States x Signals => States
*/
@@ -390,7 +442,7 @@
* @param {SyntheticEvent} e Synthetic event from event system.
*
*/
- touchableHandleResponderGrant: function(e) {
+ touchableHandleResponderGrant: function(e: PressEvent) {
const dispatchID = e.currentTarget;
// Since e is used in a callback invoked on another event loop
// (as in setTimeout etc), we need to call e.persist() on the
@@ -431,29 +483,23 @@
/**
* Place as callback for a DOM element's `onResponderRelease` event.
*/
- touchableHandleResponderRelease: function(e) {
+ touchableHandleResponderRelease: function(e: PressEvent) {
+ this.pressInLocation = null;
this._receiveSignal(Signals.RESPONDER_RELEASE, e);
},
/**
* Place as callback for a DOM element's `onResponderTerminate` event.
*/
- touchableHandleResponderTerminate: function(e) {
+ touchableHandleResponderTerminate: function(e: PressEvent) {
+ this.pressInLocation = null;
this._receiveSignal(Signals.RESPONDER_TERMINATED, e);
},
/**
* Place as callback for a DOM element's `onResponderMove` event.
*/
- touchableHandleResponderMove: function(e) {
- // Not enough time elapsed yet, wait for highlight -
- // this is just a perf optimization.
- if (
- this.state.touchable.touchState === States.RESPONDER_INACTIVE_PRESS_IN
- ) {
- return;
- }
-
+ touchableHandleResponderMove: function(e: PressEvent) {
// Measurement may not have returned yet.
if (!this.state.touchable.positionOnActivate) {
return;
@@ -486,7 +532,7 @@
pressExpandBottom += hitSlop.bottom || 0;
}
- const touch = TouchEventUtils.extractSingleTouch(e.nativeEvent);
+ const touch = extractSingleTouch(e.nativeEvent);
const pageX = touch && touch.pageX;
const pageY = touch && touch.pageY;
@@ -514,9 +560,13 @@
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();
}
@@ -531,7 +581,8 @@
* visually distinguish the `VisualRect` so that the user knows that it
* currently has the focus. Most platforms only support a single element being
* focused at a time, in which case there may have been a previously focused
- * element that was blurred just prior to this.
+ * element that was blurred just prior to this. This can be overridden when
+ * using `Touchable.Mixin.withoutDefaultFocusAndBlur`.
*/
touchableHandleFocus: function(e: Event) {
this.props.onFocus && this.props.onFocus(e);
@@ -542,6 +593,8 @@
* visually distinguish the `VisualRect` so that the user knows that it
* no longer has focus. Most platforms only support a single element being
* focused at a time, in which case the focus may have moved to another.
+ * This can be overridden when using
+ * `Touchable.Mixin.withoutDefaultFocusAndBlur`.
*/
touchableHandleBlur: function(e: Event) {
this.props.onBlur && this.props.onBlur(e);
@@ -632,7 +685,14 @@
UIManager.measure(tag, this._handleQueryLayout);
},
- _handleQueryLayout: function(l, t, w, h, globalX, globalY) {
+ _handleQueryLayout: function(
+ l: number,
+ t: number,
+ w: number,
+ h: number,
+ globalX: number,
+ globalY: number,
+ ) {
//don't do anything UIManager failed to measure node
if (!l && !t && !w && !h && !globalX && !globalY) {
return;
@@ -651,12 +711,12 @@
);
},
- _handleDelay: function(e) {
+ _handleDelay: function(e: PressEvent) {
this.touchableDelayTimeout = null;
this._receiveSignal(Signals.DELAY, e);
},
- _handleLongDelay: function(e) {
+ _handleLongDelay: function(e: PressEvent) {
this.longPressDelayTimeout = null;
const curState = this.state.touchable.touchState;
if (
@@ -684,7 +744,7 @@
* @throws Error if invalid state transition or unrecognized signal.
* @sideeffects
*/
- _receiveSignal: function(signal, e) {
+ _receiveSignal: function(signal: Signal, e: PressEvent) {
const responderID = this.state.touchable.responderID;
const curState = this.state.touchable.touchState;
const nextState = Transitions[curState] && Transitions[curState][signal];
@@ -724,15 +784,15 @@
this.longPressDelayTimeout = null;
},
- _isHighlight: function(state) {
+ _isHighlight: function(state: State) {
return (
state === States.RESPONDER_ACTIVE_PRESS_IN ||
state === States.RESPONDER_ACTIVE_LONG_PRESS_IN
);
},
- _savePressInLocation: function(e) {
- const touch = TouchEventUtils.extractSingleTouch(e.nativeEvent);
+ _savePressInLocation: function(e: PressEvent) {
+ const touch = extractSingleTouch(e.nativeEvent);
const pageX = touch && touch.pageX;
const pageY = touch && touch.pageY;
const locationX = touch && touch.locationX;
@@ -740,7 +800,12 @@
this.pressInLocation = {pageX, pageY, locationX, locationY};
},
- _getDistanceBetweenPoints: function(aX, aY, bX, bY) {
+ _getDistanceBetweenPoints: function(
+ aX: number,
+ aY: number,
+ bX: number,
+ bY: number,
+ ) {
const deltaX = aX - bX;
const deltaY = aY - bY;
return Math.sqrt(deltaX * deltaX + deltaY * deltaY);
@@ -757,7 +822,12 @@
* @param {Event} e Native event.
* @sideeffects
*/
- _performSideEffectsForTransition: function(curState, nextState, signal, e) {
+ _performSideEffectsForTransition: function(
+ curState: State,
+ nextState: State,
+ signal: Signal,
+ e: PressEvent,
+ ) {
const curIsHighlight = this._isHighlight(curState);
const newIsHighlight = this._isHighlight(nextState);
@@ -769,7 +839,12 @@
this._cancelLongPressDelayTimeout();
}
- if (!IsActive[curState] && IsActive[nextState]) {
+ const isInitialTransition =
+ curState === States.NOT_RESPONDER &&
+ nextState === States.RESPONDER_INACTIVE_PRESS_IN;
+
+ const isActiveTransition = !IsActive[curState] && IsActive[nextState];
+ if (isInitialTransition || isActiveTransition) {
this._remeasureMetricsOnActivation();
}
@@ -812,12 +887,12 @@
UIManager.playTouchSound();
},
- _startHighlight: function(e) {
+ _startHighlight: function(e: PressEvent) {
this._savePressInLocation(e);
this.touchableHandleActivePressIn && this.touchableHandleActivePressIn(e);
},
- _endHighlight: function(e) {
+ _endHighlight: function(e: PressEvent) {
if (this.touchableHandleActivePressOut) {
if (
this.touchableGetPressOutDelayMS &&
@@ -831,15 +906,36 @@
}
}
},
+
+ withoutDefaultFocusAndBlur: {},
};
+/**
+ * Provide an optional version of the mixin where `touchableHandleFocus` and
+ * `touchableHandleBlur` can be overridden. This allows appropriate defaults to
+ * be set on TV platforms, without breaking existing implementations of
+ * `Touchable`.
+ */
+const {
+ touchableHandleFocus,
+ touchableHandleBlur,
+ ...TouchableMixinWithoutDefaultFocusAndBlur
+} = TouchableMixin;
+TouchableMixin.withoutDefaultFocusAndBlur = TouchableMixinWithoutDefaultFocusAndBlur;
+
const Touchable = {
Mixin: TouchableMixin,
TOUCH_TARGET_DEBUG: false, // Highlights all touchable targets. Toggle with Inspector.
/**
* Renders a debugging overlay to visualize touch target with hitSlop (might not work on Android).
*/
- renderDebugView: ({color, hitSlop}) => {
+ renderDebugView: ({
+ color,
+ hitSlop,
+ }: {
+ color: string | number,
+ hitSlop: EdgeInsetsProp,
+ }) => {
if (!Touchable.TOUCH_TARGET_DEBUG) {
return null;
}
@@ -853,22 +949,34 @@
for (const key in hitSlop) {
debugHitSlopStyle[key] = -hitSlop[key];
}
+ const normalizedColor = normalizeColor(color);
+ if (typeof normalizedColor !== 'number') {
+ return null;
+ }
const hexColor =
- '#' + ('00000000' + normalizeColor(color).toString(16)).substr(-8);
+ '#' + ('00000000' + normalizedColor.toString(16)).substr(-8);
return (
<View
pointerEvents="none"
- style={{
- position: 'absolute',
+ style={[
+ styles.debug,
+ {
borderColor: hexColor.slice(0, -2) + '55', // More opaque
- borderWidth: 1,
- borderStyle: 'dashed',
backgroundColor: hexColor.slice(0, -2) + '0F', // Less opaque
...debugHitSlopStyle,
- }}
+ },
+ ]}
/>
);
},
};
+const styles = StyleSheet.create({
+ debug: {
+ position: 'absolute',
+ borderWidth: 1,
+ borderStyle: 'dashed',
+ },
+});
+
module.exports = Touchable;

Libraries/Components/Touchable/TouchableNativeFeedback.android.js

@@ -1,9 +1,10 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
*
+ * @flow strict-local
* @format
*/
@@ -22,6 +23,8 @@
const ensurePositiveDelayProps = require('ensurePositiveDelayProps');
const processColor = require('processColor');
+import type {PressEvent} from 'CoreEventTypes';
+
const rippleBackgroundPropType = PropTypes.shape({
type: PropTypes.oneOf(['RippleAndroid']),
color: PropTypes.number,
@@ -38,8 +41,6 @@
themeAttributeBackgroundPropType,
]);
-type Event = Object;
-
const PRESS_RETENTION_OFFSET = {top: 20, left: 20, right: 20, bottom: 30};
/**
@@ -74,6 +75,9 @@
const TouchableNativeFeedback = createReactClass({
displayName: 'TouchableNativeFeedback',
propTypes: {
+ /* $FlowFixMe(>=0.89.0 site=react_native_android_fb) This comment
+ * suppresses an error found when Flow v0.89 was deployed. To see the
+ * error, delete this comment and run Flow. */
...TouchableWithoutFeedback.propTypes,
/**
@@ -106,7 +110,10 @@
* Creates an object that represents android theme's default background for
* selectable elements (?android:attr/selectableItemBackground).
*/
- SelectableBackground: function() {
+ SelectableBackground: function(): {
+ type: 'ThemeAttrAndroid',
+ attribute: 'selectableItemBackground',
+ } {
return {type: 'ThemeAttrAndroid', attribute: 'selectableItemBackground'};
},
/**
@@ -114,7 +121,10 @@
* selectable elements (?android:attr/selectableItemBackgroundBorderless).
* Available on android API level 21+.
*/
- SelectableBackgroundBorderless: function() {
+ SelectableBackgroundBorderless: function(): {
+ type: 'ThemeAttrAndroid',
+ attribute: 'selectableItemBackgroundBorderless',
+ } {
return {
type: 'ThemeAttrAndroid',
attribute: 'selectableItemBackgroundBorderless',
@@ -130,7 +140,14 @@
* @param color The ripple color
* @param borderless If the ripple can render outside it's bounds
*/
- Ripple: function(color: string, borderless: boolean) {
+ Ripple: function(
+ color: string,
+ borderless: boolean,
+ ): {
+ type: 'RippleAndroid',
+ color: ?number,
+ borderless: boolean,
+ } {
return {
type: 'RippleAndroid',
color: processColor(color),
@@ -138,7 +155,7 @@
};
},
- canUseNativeForeground: function() {
+ canUseNativeForeground: function(): boolean {
return Platform.OS === 'android' && Platform.Version >= 23;
},
},
@@ -167,27 +184,36 @@
* `Touchable.Mixin` self callbacks. The mixin will invoke these if they are
* defined on your component.
*/
- touchableHandleActivePressIn: function(e: Event) {
+ touchableHandleActivePressIn: function(e: PressEvent) {
this.props.onPressIn && this.props.onPressIn(e);
this._dispatchPressedStateChange(true);
+ /* $FlowFixMe(>=0.89.0 site=react_native_android_fb) This comment
+ * suppresses an error found when Flow v0.89 was deployed. To see the
+ * error, delete this comment and run Flow. */
if (this.pressInLocation) {
this._dispatchHotspotUpdate(
+ /* $FlowFixMe(>=0.89.0 site=react_native_android_fb) This comment
+ * suppresses an error found when Flow v0.89 was deployed. To see the
+ * error, delete this comment and run Flow. */
this.pressInLocation.locationX,
+ /* $FlowFixMe(>=0.89.0 site=react_native_android_fb) This comment
+ * suppresses an error found when Flow v0.89 was deployed. To see the
+ * error, delete this comment and run Flow. */
this.pressInLocation.locationY,
);
}
},
- touchableHandleActivePressOut: function(e: Event) {
+ touchableHandleActivePressOut: function(e: PressEvent) {
this.props.onPressOut && this.props.onPressOut(e);
this._dispatchPressedStateChange(false);
},
- touchableHandlePress: function(e: Event) {
+ touchableHandlePress: function(e: PressEvent) {
this.props.onPress && this.props.onPress(e);
},
- touchableHandleLongPress: function(e: Event) {
+ touchableHandleLongPress: function(e: PressEvent) {
this.props.onLongPress && this.props.onLongPress(e);
},
@@ -223,7 +249,7 @@
_dispatchHotspotUpdate: function(destX, destY) {
UIManager.dispatchViewManagerCommand(
ReactNative.findNodeHandle(this),
- UIManager.RCTView.Commands.hotspotUpdate,
+ UIManager.getViewManagerConfig('RCTView').Commands.hotspotUpdate,
[destX || 0, destY || 0],
);
},
@@ -231,7 +257,7 @@
_dispatchPressedStateChange: function(pressed) {
UIManager.dispatchViewManagerCommand(
ReactNative.findNodeHandle(this),
- UIManager.RCTView.Commands.setPressed,
+ UIManager.getViewManagerConfig('RCTView').Commands.setPressed,
[pressed],
);
},

Libraries/Components/Touchable/TouchableNativeFeedback.ios.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/Touchable/TouchableOpacity.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -13,9 +13,9 @@
const Animated = require('Animated');
const Easing = require('Easing');
const NativeMethodsMixin = require('NativeMethodsMixin');
+const Platform = require('Platform');
const React = require('React');
const PropTypes = require('prop-types');
-const TimerMixin = require('react-timer-mixin');
const Touchable = require('Touchable');
const TouchableWithoutFeedback = require('TouchableWithoutFeedback');
@@ -25,14 +25,14 @@
import type {Props as TouchableWithoutFeedbackProps} from 'TouchableWithoutFeedback';
import type {ViewStyleProp} from 'StyleSheet';
-
-type Event = Object;
+import type {TVParallaxPropertiesType} from 'TVViewPropTypes';
+import type {PressEvent} from 'CoreEventTypes';
const PRESS_RETENTION_OFFSET = {top: 20, left: 20, right: 20, bottom: 30};
type TVProps = $ReadOnly<{|
hasTVPreferredFocus?: ?boolean,
- tvParallaxProperties?: ?Object,
+ tvParallaxProperties?: ?TVParallaxPropertiesType,
|}>;
type Props = $ReadOnly<{|
@@ -132,9 +132,12 @@
*/
const TouchableOpacity = ((createReactClass({
displayName: 'TouchableOpacity',
- mixins: [TimerMixin, Touchable.Mixin, NativeMethodsMixin],
+ mixins: [Touchable.Mixin.withoutDefaultFocusAndBlur, NativeMethodsMixin],
propTypes: {
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
...TouchableWithoutFeedback.propTypes,
/**
* Determines what the opacity of the wrapped view should be when touch is
@@ -159,7 +162,13 @@
getInitialState: function() {
return {
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete
+ * this comment and run Flow. */
...this.touchableGetInitialState(),
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete
+ * this comment and run Flow. */
anim: new Animated.Value(this._getChildStyleOpacityWithDefault()),
};
},
@@ -194,7 +203,7 @@
* `Touchable.Mixin` self callbacks. The mixin will invoke these if they are
* defined on your component.
*/
- touchableHandleActivePressIn: function(e: Event) {
+ touchableHandleActivePressIn: function(e: PressEvent) {
if (e.dispatchConfig.registrationName === 'onResponderGrant') {
this._opacityActive(0);
} else {
@@ -203,16 +212,30 @@
this.props.onPressIn && this.props.onPressIn(e);
},
- touchableHandleActivePressOut: function(e: Event) {
+ touchableHandleActivePressOut: function(e: PressEvent) {
this._opacityInactive(250);
this.props.onPressOut && this.props.onPressOut(e);
},
- touchableHandlePress: function(e: Event) {
+ touchableHandleFocus: function(e: Event) {
+ if (Platform.isTV) {
+ this._opacityActive(150);
+ }
+ this.props.onFocus && this.props.onFocus(e);
+ },
+
+ touchableHandleBlur: function(e: Event) {
+ if (Platform.isTV) {
+ this._opacityInactive(250);
+ }
+ this.props.onBlur && this.props.onBlur(e);
+ },
+
+ touchableHandlePress: function(e: PressEvent) {
this.props.onPress && this.props.onPress(e);
},
- touchableHandleLongPress: function(e: Event) {
+ touchableHandleLongPress: function(e: PressEvent) {
this.props.onLongPress && this.props.onLongPress(e);
},
@@ -243,12 +266,15 @@
},
_opacityInactive: function(duration: number) {
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
this.setOpacityTo(this._getChildStyleOpacityWithDefault(), duration);
},
_getChildStyleOpacityWithDefault: function() {
const childStyle = flattenStyle(this.props.style) || {};
- return childStyle.opacity == undefined ? 1 : childStyle.opacity;
+ return childStyle.opacity == null ? 1 : childStyle.opacity;
},
render: function() {
@@ -267,13 +293,31 @@
hasTVPreferredFocus={this.props.hasTVPreferredFocus}
tvParallaxProperties={this.props.tvParallaxProperties}
hitSlop={this.props.hitSlop}
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete
+ * this comment and run Flow. */
onStartShouldSetResponder={this.touchableHandleStartShouldSetResponder}
onResponderTerminationRequest={
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses
+ * an error found when Flow v0.89 was deployed. To see the error,
+ * delete this comment and run Flow. */
this.touchableHandleResponderTerminationRequest
}
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete
+ * this comment and run Flow. */
onResponderGrant={this.touchableHandleResponderGrant}
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete
+ * this comment and run Flow. */
onResponderMove={this.touchableHandleResponderMove}
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete
+ * this comment and run Flow. */
onResponderRelease={this.touchableHandleResponderRelease}
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete
+ * this comment and run Flow. */
onResponderTerminate={this.touchableHandleResponderTerminate}>
{this.props.children}
{Touchable.renderDebugView({

Libraries/Components/Touchable/TouchableWithoutFeedback.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,48 +10,51 @@
'use strict';
-const EdgeInsetsPropType = require('EdgeInsetsPropType');
+const DeprecatedEdgeInsetsPropType = require('DeprecatedEdgeInsetsPropType');
const React = require('React');
const PropTypes = require('prop-types');
-const TimerMixin = require('react-timer-mixin');
const Touchable = require('Touchable');
const View = require('View');
const createReactClass = require('create-react-class');
const ensurePositiveDelayProps = require('ensurePositiveDelayProps');
-const warning = require('fbjs/lib/warning');
const {
- AccessibilityComponentTypes,
- AccessibilityRoles,
- AccessibilityStates,
- AccessibilityTraits,
-} = require('ViewAccessibility');
+ DeprecatedAccessibilityComponentTypes,
+ DeprecatedAccessibilityRoles,
+ DeprecatedAccessibilityStates,
+ DeprecatedAccessibilityTraits,
+} = require('DeprecatedViewAccessibility');
-import type {PressEvent} from 'CoreEventTypes';
+import type {SyntheticEvent, LayoutEvent, PressEvent} from 'CoreEventTypes';
import type {EdgeInsetsProp} from 'EdgeInsetsPropType';
import type {
AccessibilityComponentType,
AccessibilityRole,
- AccessibilityStates as AccessibilityStatesFlow,
- AccessibilityTraits as AccessibilityTraitsFlow,
+ AccessibilityStates,
+ AccessibilityTraits,
} from 'ViewAccessibility';
+type TargetEvent = SyntheticEvent<
+ $ReadOnly<{|
+ target: number,
+ |}>,
+>;
+
+type BlurEvent = TargetEvent;
+type FocusEvent = TargetEvent;
+
const PRESS_RETENTION_OFFSET = {top: 20, left: 20, right: 20, bottom: 30};
export type Props = $ReadOnly<{|
accessible?: ?boolean,
accessibilityComponentType?: ?AccessibilityComponentType,
- accessibilityLabel?:
- | null
- | React$PropType$Primitive<any>
- | string
- | Array<any>
- | any,
- accessibilityHint?: string,
+ accessibilityLabel?: ?Stringish,
+ accessibilityHint?: ?Stringish,
+ accessibilityIgnoresInvertColors?: ?boolean,
accessibilityRole?: ?AccessibilityRole,
- accessibilityStates?: ?AccessibilityStatesFlow,
- accessibilityTraits?: ?AccessibilityTraitsFlow,
+ accessibilityStates?: ?AccessibilityStates,
+ accessibilityTraits?: ?AccessibilityTraits,
children?: ?React.Node,
delayLongPress?: ?number,
delayPressIn?: ?number,
@@ -59,11 +62,13 @@
disabled?: ?boolean,
hitSlop?: ?EdgeInsetsProp,
nativeID?: ?string,
- onLayout?: ?Function,
- onLongPress?: ?Function,
- onPress?: ?Function,
- onPressIn?: ?Function,
- onPressOut?: ?Function,
+ onBlur?: ?(e: BlurEvent) => void,
+ onFocus?: ?(e: FocusEvent) => void,
+ onLayout?: ?(event: LayoutEvent) => mixed,
+ onLongPress?: ?(event: PressEvent) => mixed,
+ onPress?: ?(event: PressEvent) => mixed,
+ onPressIn?: ?(event: PressEvent) => mixed,
+ onPressOut?: ?(event: PressEvent) => mixed,
pressRetentionOffset?: ?EdgeInsetsProp,
rejectResponderTermination?: ?boolean,
testID?: ?string,
@@ -78,20 +83,22 @@
*/
const TouchableWithoutFeedback = ((createReactClass({
displayName: 'TouchableWithoutFeedback',
- mixins: [TimerMixin, Touchable.Mixin],
+ mixins: [Touchable.Mixin],
propTypes: {
accessible: PropTypes.bool,
accessibilityLabel: PropTypes.node,
accessibilityHint: PropTypes.string,
- accessibilityComponentType: PropTypes.oneOf(AccessibilityComponentTypes),
- accessibilityRole: PropTypes.oneOf(AccessibilityRoles),
+ accessibilityComponentType: PropTypes.oneOf(
+ DeprecatedAccessibilityComponentTypes,
+ ),
+ accessibilityRole: PropTypes.oneOf(DeprecatedAccessibilityRoles),
accessibilityStates: PropTypes.arrayOf(
- PropTypes.oneOf(AccessibilityStates),
+ PropTypes.oneOf(DeprecatedAccessibilityStates),
),
accessibilityTraits: PropTypes.oneOfType([
- PropTypes.oneOf(AccessibilityTraits),
- PropTypes.arrayOf(PropTypes.oneOf(AccessibilityTraits)),
+ PropTypes.oneOf(DeprecatedAccessibilityTraits),
+ PropTypes.arrayOf(PropTypes.oneOf(DeprecatedAccessibilityTraits)),
]),
/**
* When `accessible` is true (which is the default) this may be called when
@@ -154,7 +161,7 @@
* reactivated! Move it back and forth several times while the scroll view
* is disabled. Ensure you pass in a constant to reduce memory allocations.
*/
- pressRetentionOffset: EdgeInsetsPropType,
+ pressRetentionOffset: DeprecatedEdgeInsetsPropType,
/**
* This defines how far your touch can start away from the button. This is
* added to `pressRetentionOffset` when moving off of the button.
@@ -163,7 +170,7 @@
* of sibling views always takes precedence if a touch hits two overlapping
* views.
*/
- hitSlop: EdgeInsetsPropType,
+ hitSlop: DeprecatedEdgeInsetsPropType,
},
getInitialState: function() {

Libraries/Components/UnimplementedViews/UnimplementedView.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/View/PlatformViewPropTypes.android.js

@@ -0,0 +1,14 @@
+/**
+ * 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.
+ *
+ * @providesModule PlatformViewPropTypes
+ * @format
+ * @flow
+ */
+
+'use strict';
+
+export type PlatformViewPropTypes = {};

Libraries/Components/View/PlatformViewPropTypes.ios.js

@@ -0,0 +1,16 @@
+/**
+ * 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.
+ *
+ * @providesModule PlatformViewPropTypes
+ * @format
+ * @flow
+ */
+
+'use strict';
+
+import type {TVViewProps} from 'TVViewPropTypes';
+
+export type PlatformViewPropTypes = TVViewProps;

Libraries/Components/View/PlatformViewPropTypes.js

@@ -1,21 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow strict-local
- */
-
-const Platform = require('Platform');
-
-let TVViewPropTypes = {};
-// We need to always include TVViewPropTypes on Android
-// as unlike on iOS we can't detect TV devices at build time
-// and hence make view manager export a different list of native properties.
-if (Platform.isTV || Platform.OS === 'android') {
- TVViewPropTypes = require('TVViewPropTypes');
-}
-
-module.exports = TVViewPropTypes;

Libraries/Components/View/ReactNativeStyleAttributes.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,9 +10,9 @@
'use strict';
-const ImageStylePropTypes = require('ImageStylePropTypes');
+const DeprecatedImageStylePropTypes = require('DeprecatedImageStylePropTypes');
const TextStylePropTypes = require('TextStylePropTypes');
-const ViewStylePropTypes = require('ViewStylePropTypes');
+const DeprecatedViewStylePropTypes = require('DeprecatedViewStylePropTypes');
const processColor = require('processColor');
const processTransform = require('processTransform');
@@ -21,9 +21,9 @@
const ReactNativeStyleAttributes = {};
for (const attributeName of Object.keys({
- ...ViewStylePropTypes,
+ ...DeprecatedViewStylePropTypes,
...TextStylePropTypes,
- ...ImageStylePropTypes,
+ ...DeprecatedImageStylePropTypes,
})) {
ReactNativeStyleAttributes[attributeName] = true;
}

Libraries/Components/View/ReactNativeViewAttributes.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -34,6 +34,7 @@
onAccessibilityAction: true,
onAccessibilityTap: true,
onMagicTap: true,
+ onAccessibilityEscape: true,
collapsable: true,
needsOffscreenAlphaCompositing: true,
style: ReactNativeStyleAttributes,

Libraries/Components/View/ShadowPropTypesIOS.js

@@ -1,50 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @flow
- * @format
- */
-'use strict';
-
-const ColorPropType = require('ColorPropType');
-const ReactPropTypes = require('prop-types');
-
-/**
- * These props can be used to dynamically generate shadows on views, images, text, etc.
- *
- * Because they are dynamically generated, they may cause performance regressions. Static
- * shadow image asset may be a better way to go for optimal performance.
- *
- * These properties are iOS only - for similar functionality on Android, use the [`elevation`
- * property](docs/viewstyleproptypes.html#elevation).
- */
-const ShadowPropTypesIOS = {
- /**
- * Sets the drop shadow color
- * @platform ios
- */
- shadowColor: ColorPropType,
- /**
- * Sets the drop shadow offset
- * @platform ios
- */
- shadowOffset: ReactPropTypes.shape({
- width: ReactPropTypes.number,
- height: ReactPropTypes.number,
- }),
- /**
- * Sets the drop shadow opacity (multiplied by the color's alpha component)
- * @platform ios
- */
- shadowOpacity: ReactPropTypes.number,
- /**
- * Sets the drop shadow blur radius
- * @platform ios
- */
- shadowRadius: ReactPropTypes.number,
-};
-
-module.exports = ShadowPropTypesIOS;

Libraries/Components/View/ViewAccessibility.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -39,6 +39,7 @@
| 'radiobutton_checked'
| 'radiobutton_unchecked';
+// This must be kept in sync with the AccessibilityRolesMask in RCTViewManager.m
export type AccessibilityRole =
| 'none'
| 'button'
@@ -52,52 +53,5 @@
| 'header'
| 'summary';
-export type AccessibilityState = 'selected' | 'disabled';
-
-export type AccessibilityStates =
- | AccessibilityState
- | $ReadOnlyArray<AccessibilityState>;
-
-module.exports = {
- AccessibilityTraits: [
- 'none',
- 'button',
- 'link',
- 'header',
- 'search',
- 'image',
- 'selected',
- 'plays',
- 'key',
- 'text',
- 'summary',
- 'disabled',
- 'frequentUpdates',
- 'startsMedia',
- 'adjustable',
- 'allowsDirectInteraction',
- 'pageTurn',
- ],
- AccessibilityComponentTypes: [
- 'none',
- 'button',
- 'radiobutton_checked',
- 'radiobutton_unchecked',
- ],
- // This must be kept in sync with the AccessibilityRolesMask in RCTViewManager.m
- AccessibilityRoles: [
- 'none',
- 'button',
- 'link',
- 'search',
- 'image',
- 'keyboardkey',
- 'text',
- 'adjustable',
- 'imagebutton',
- 'header',
- 'summary',
- ],
- // This must be kept in sync with the AccessibilityStatesMask in RCTViewManager.m
- AccessibilityStates: ['selected', 'disabled'],
-};
+// This must be kept in sync with the AccessibilityStatesMask in RCTViewManager.m
+export type AccessibilityStates = $ReadOnlyArray<'disabled' | 'selected'>;

Libraries/Components/View/View.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -14,7 +14,7 @@
const TextAncestor = require('TextAncestor');
const ViewNativeComponent = require('ViewNativeComponent');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
import type {ViewProps} from 'ViewPropTypes';
@@ -47,7 +47,6 @@
</TextAncestor.Consumer>
);
};
- // $FlowFixMe - TODO T29156721 `React.forwardRef` is not defined in Flow, yet.
ViewToExport = React.forwardRef(View);
ViewToExport.displayName = 'View';
}

Libraries/Components/View/ViewNativeComponent.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/View/ViewPropTypes.js

@@ -1,303 +1,115 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
- * @flow
+ * @flow strict-local
*/
'use strict';
-const React = require('React');
-const EdgeInsetsPropType = require('EdgeInsetsPropType');
-const PlatformViewPropTypes = require('PlatformViewPropTypes');
-const PropTypes = require('prop-types');
-const StyleSheetPropType = require('StyleSheetPropType');
-const ViewStylePropTypes = require('ViewStylePropTypes');
-
-const {
- AccessibilityComponentTypes,
- AccessibilityTraits,
- AccessibilityRoles,
- AccessibilityStates,
-} = require('ViewAccessibility');
-
+import type {PressEvent, Layout, LayoutEvent} from 'CoreEventTypes';
+import type {EdgeInsetsProp} from 'EdgeInsetsPropType';
+import type React from 'React';
+import type {ViewStyleProp} from 'StyleSheet';
+import type {TVViewProps} from 'TVViewPropTypes';
import type {
AccessibilityComponentType,
AccessibilityTrait,
AccessibilityRole,
- AccessibilityState,
+ AccessibilityStates,
} from 'ViewAccessibility';
-import type {EdgeInsetsProp} from 'EdgeInsetsPropType';
-import type {TVViewProps} from 'TVViewPropTypes';
-import type {Layout, LayoutEvent} from 'CoreEventTypes';
-
-const stylePropType = StyleSheetPropType(ViewStylePropTypes);
export type ViewLayout = Layout;
export type ViewLayoutEvent = LayoutEvent;
type DirectEventProps = $ReadOnly<{|
- onAccessibilityAction?: Function,
- onAccessibilityTap?: Function,
- onLayout?: ?(event: LayoutEvent) => void,
- onMagicTap?: Function,
-|}>;
-
-type TouchEventProps = $ReadOnly<{|
- onTouchCancel?: ?Function,
- onTouchCancelCapture?: ?Function,
- onTouchEnd?: ?Function,
- onTouchEndCapture?: ?Function,
- onTouchMove?: ?Function,
- onTouchMoveCapture?: ?Function,
- onTouchStart?: ?Function,
- onTouchStartCapture?: ?Function,
-|}>;
-
-type GestureResponderEventProps = $ReadOnly<{|
- onMoveShouldSetResponder?: ?Function,
- onMoveShouldSetResponderCapture?: ?Function,
- onResponderGrant?: ?Function,
- onResponderMove?: ?Function,
- onResponderReject?: ?Function,
- onResponderRelease?: ?Function,
- onResponderStart?: ?Function,
- onResponderTerminate?: ?Function,
- onResponderTerminationRequest?: ?Function,
- onStartShouldSetResponder?: ?Function,
- onStartShouldSetResponderCapture?: ?Function,
-|}>;
-
-type AndroidViewProps = $ReadOnly<{|
- nativeBackgroundAndroid?: ?Object,
- nativeForegroundAndroid?: ?Object,
-
- /* Deprecated transform prop. Use the transform style prop instead */
- rotation?: empty,
- /* Deprecated transform prop. Use the transform style prop instead */
- scaleX?: empty,
- /* Deprecated transform prop. Use the transform style prop instead */
- scaleY?: empty,
- /* Deprecated transform prop. Use the transform style prop instead */
- translateX?: empty,
- /* Deprecated transform prop. Use the transform style prop instead */
- translateY?: empty,
-|}>;
-
-export type ViewProps = $ReadOnly<{|
- ...DirectEventProps,
- ...GestureResponderEventProps,
- ...TouchEventProps,
- ...AndroidViewProps,
-
- // There's no easy way to create a different type if (Platform.isTV):
- // so we must include TVViewProps
- ...TVViewProps,
-
- accessible?: boolean,
- accessibilityLabel?:
- | null
- | React$PropType$Primitive<any>
- | string
- | Array<any>
- | any,
- accessibilityHint?: string,
- accessibilityActions?: Array<string>,
- accessibilityComponentType?: AccessibilityComponentType,
- accessibilityLiveRegion?: 'none' | 'polite' | 'assertive',
- importantForAccessibility?: 'auto' | 'yes' | 'no' | 'no-hide-descendants',
- accessibilityIgnoresInvertColors?: boolean,
- accessibilityTraits?: AccessibilityTrait | Array<AccessibilityTrait>,
- accessibilityRole?: AccessibilityRole,
- accessibilityStates?: Array<AccessibilityState>,
- accessibilityViewIsModal?: boolean,
- accessibilityElementsHidden?: boolean,
- children?: ?React.Node,
- testID?: ?string,
- nativeID?: string,
- hitSlop?: ?EdgeInsetsProp,
- pointerEvents?: null | 'box-none' | 'none' | 'box-only' | 'auto',
- style?: stylePropType,
- removeClippedSubviews?: boolean,
- renderToHardwareTextureAndroid?: boolean,
- shouldRasterizeIOS?: boolean,
- collapsable?: boolean,
- needsOffscreenAlphaCompositing?: boolean,
-|}>;
-
-module.exports = {
- /**
- * When `true`, indicates that the view is an accessibility element.
- * By default, all the touchable elements are accessible.
- *
- * See http://facebook.github.io/react-native/docs/view.html#accessible
- */
- accessible: PropTypes.bool,
-
- /**
- * Overrides the text that's read by the screen reader when the user interacts
- * with the element. By default, the label is constructed by traversing all
- * the children and accumulating all the `Text` nodes separated by space.
- *
- * See http://facebook.github.io/react-native/docs/view.html#accessibilitylabel
- */
- accessibilityLabel: PropTypes.node,
-
- /**
- * An accessibility hint helps users understand what will happen when they perform
- * an action on the accessibility element when that result is not obvious from the
- * accessibility label.
- *
- *
- * See http://facebook.github.io/react-native/docs/view.html#accessibilityHint
- */
- accessibilityHint: PropTypes.string,
-
- /**
- * Provides an array of custom actions available for accessibility.
- *
- * @platform ios
- */
- accessibilityActions: PropTypes.arrayOf(PropTypes.string),
-
/**
- * Prevents view from being inverted if set to true and color inversion is turned on.
+ * When `accessible` is true, the system will try to invoke this function
+ * when the user performs an accessibility custom action.
*
* @platform ios
*/
- accessibilityIgnoresInvertColors: PropTypes.bool,
+ onAccessibilityAction?: ?(string) => void,
/**
- * Indicates to accessibility services to treat UI component like a
- * native one. Works for Android only.
- *
- * @platform android
- *
- * See http://facebook.github.io/react-native/docs/view.html#accessibilitycomponenttype
- */
- accessibilityComponentType: PropTypes.oneOf(AccessibilityComponentTypes),
-
- /**
- * Indicates to accessibility services to treat UI component like a specific role.
- */
- accessibilityRole: PropTypes.oneOf(AccessibilityRoles),
-
- /**
- * Indicates to accessibility services that UI Component is in a specific State.
- */
- accessibilityStates: PropTypes.arrayOf(PropTypes.oneOf(AccessibilityStates)),
- /**
- * Indicates to accessibility services whether the user should be notified
- * when this view changes. Works for Android API >= 19 only.
- *
- * @platform android
- *
- * See http://facebook.github.io/react-native/docs/view.html#accessibilityliveregion
- */
- accessibilityLiveRegion: PropTypes.oneOf(['none', 'polite', 'assertive']),
-
- /**
- * Controls how view is important for accessibility which is if it
- * fires accessibility events and if it is reported to accessibility services
- * that query the screen. Works for Android only.
- *
- * @platform android
+ * When `accessible` is true, the system will try to invoke this function
+ * when the user performs accessibility tap gesture.
*
- * See http://facebook.github.io/react-native/docs/view.html#importantforaccessibility
+ * See http://facebook.github.io/react-native/docs/view.html#onaccessibilitytap
*/
- importantForAccessibility: PropTypes.oneOf([
- 'auto',
- 'yes',
- 'no',
- 'no-hide-descendants',
- ]),
+ onAccessibilityTap?: ?() => void,
/**
- * Provides additional traits to screen reader. By default no traits are
- * provided unless specified otherwise in element.
- *
- * You can provide one trait or an array of many traits.
- *
- * @platform ios
+ * Invoked on mount and layout changes with:
*
- * See http://facebook.github.io/react-native/docs/view.html#accessibilitytraits
- */
- accessibilityTraits: PropTypes.oneOfType([
- PropTypes.oneOf(AccessibilityTraits),
- PropTypes.arrayOf(PropTypes.oneOf(AccessibilityTraits)),
- ]),
-
- /**
- * A value indicating whether VoiceOver should ignore the elements
- * within views that are siblings of the receiver.
- * Default is `false`.
+ * `{nativeEvent: { layout: {x, y, width, height}}}`
*
- * @platform ios
+ * This event is fired immediately once the layout has been calculated, but
+ * the new layout may not yet be reflected on the screen at the time the
+ * event is received, especially if a layout animation is in progress.
*
- * See http://facebook.github.io/react-native/docs/view.html#accessibilityviewismodal
+ * See http://facebook.github.io/react-native/docs/view.html#onlayout
*/
- accessibilityViewIsModal: PropTypes.bool,
+ onLayout?: ?(event: LayoutEvent) => mixed,
/**
- * A value indicating whether the accessibility elements contained within
- * this accessibility element are hidden.
- *
- * @platform ios
+ * When `accessible` is `true`, the system will invoke this function when the
+ * user performs the magic tap gesture.
*
- * See http://facebook.github.io/react-native/docs/view.html#accessibilityElementsHidden
+ * See http://facebook.github.io/react-native/docs/view.html#onmagictap
*/
- accessibilityElementsHidden: PropTypes.bool,
+ onMagicTap?: ?() => void,
/**
- * When `accessible` is true, the system will try to invoke this function
- * when the user performs an accessibility custom action.
+ * When `accessible` is `true`, the system will invoke this function when the
+ * user performs the escape gesture.
*
- * @platform ios
+ * See http://facebook.github.io/react-native/docs/view.html#onaccessibilityescape
*/
- onAccessibilityAction: PropTypes.func,
+ onAccessibilityEscape?: ?() => void,
+|}>;
- /**
- * When `accessible` is true, the system will try to invoke this function
- * when the user performs accessibility tap gesture.
- *
- * See http://facebook.github.io/react-native/docs/view.html#onaccessibilitytap
- */
- onAccessibilityTap: PropTypes.func,
+type TouchEventProps = $ReadOnly<{|
+ onTouchCancel?: ?(e: PressEvent) => void,
+ onTouchCancelCapture?: ?(e: PressEvent) => void,
+ onTouchEnd?: ?(e: PressEvent) => void,
+ onTouchEndCapture?: ?(e: PressEvent) => void,
+ onTouchMove?: ?(e: PressEvent) => void,
+ onTouchMoveCapture?: ?(e: PressEvent) => void,
+ onTouchStart?: ?(e: PressEvent) => void,
+ onTouchStartCapture?: ?(e: PressEvent) => void,
+|}>;
- /**
- * When `accessible` is `true`, the system will invoke this function when the
- * user performs the magic tap gesture.
- *
- * See http://facebook.github.io/react-native/docs/view.html#onmagictap
+/**
+ * For most touch interactions, you'll simply want to wrap your component in
+ * `TouchableHighlight` or `TouchableOpacity`. Check out `Touchable.js`,
+ * `ScrollResponder.js` and `ResponderEventPlugin.js` for more discussion.
*/
- onMagicTap: PropTypes.func,
-
+type GestureResponderEventProps = $ReadOnly<{|
/**
- * Used to locate this view in end-to-end tests.
+ * Does this view want to "claim" touch responsiveness? This is called for
+ * every touch move on the `View` when it is not the responder.
*
- * > This disables the 'layout-only view removal' optimization for this view!
+ * `View.props.onMoveShouldSetResponder: (event) => [true | false]`, where
+ * `event` is a synthetic touch event as described above.
*
- * See http://facebook.github.io/react-native/docs/view.html#testid
+ * See http://facebook.github.io/react-native/docs/view.html#onmoveshouldsetresponder
*/
- testID: PropTypes.string,
+ onMoveShouldSetResponder?: ?(e: PressEvent) => boolean,
/**
- * Used to locate this view from native classes.
+ * If a parent `View` wants to prevent a child `View` from becoming responder
+ * on a move, it should have this handler which returns `true`.
*
- * > This disables the 'layout-only view removal' optimization for this view!
+ * `View.props.onMoveShouldSetResponderCapture: (event) => [true | false]`,
+ * where `event` is a synthetic touch event as described above.
*
- * See http://facebook.github.io/react-native/docs/view.html#nativeid
- */
- nativeID: PropTypes.string,
-
- /**
- * For most touch interactions, you'll simply want to wrap your component in
- * `TouchableHighlight` or `TouchableOpacity`. Check out `Touchable.js`,
- * `ScrollResponder.js` and `ResponderEventPlugin.js` for more discussion.
+ * See http://facebook.github.io/react-native/docs/view.html#onMoveShouldsetrespondercapture
*/
+ onMoveShouldSetResponderCapture?: ?(e: PressEvent) => boolean,
/**
* The View is now responding for touch events. This is the time to highlight
@@ -306,9 +118,12 @@
* `View.props.onResponderGrant: (event) => {}`, where `event` is a synthetic
* touch event as described above.
*
+ * PanResponder includes a note `// TODO: t7467124 investigate if this can be removed` that
+ * should help fixing this return type.
+ *
* See http://facebook.github.io/react-native/docs/view.html#onrespondergrant
*/
- onResponderGrant: PropTypes.func,
+ onResponderGrant?: ?(e: PressEvent) => void | boolean,
/**
* The user is moving their finger.
@@ -318,7 +133,7 @@
*
* See http://facebook.github.io/react-native/docs/view.html#onrespondermove
*/
- onResponderMove: PropTypes.func,
+ onResponderMove?: ?(e: PressEvent) => void,
/**
* Another responder is already active and will not release it to that `View`
@@ -329,7 +144,7 @@
*
* See http://facebook.github.io/react-native/docs/view.html#onresponderreject
*/
- onResponderReject: PropTypes.func,
+ onResponderReject?: ?(e: PressEvent) => void,
/**
* Fired at the end of the touch.
@@ -339,7 +154,10 @@
*
* See http://facebook.github.io/react-native/docs/view.html#onresponderrelease
*/
- onResponderRelease: PropTypes.func,
+ onResponderRelease?: ?(e: PressEvent) => void,
+
+ onResponderStart?: ?(e: PressEvent) => void,
+ onResponderEnd?: ?(e: PressEvent) => void,
/**
* The responder has been taken from the `View`. Might be taken by other
@@ -352,7 +170,7 @@
*
* See http://facebook.github.io/react-native/docs/view.html#onresponderterminate
*/
- onResponderTerminate: PropTypes.func,
+ onResponderTerminate?: ?(e: PressEvent) => void,
/**
* Some other `View` wants to become responder and is asking this `View` to
@@ -363,7 +181,7 @@
*
* See http://facebook.github.io/react-native/docs/view.html#onresponderterminationrequest
*/
- onResponderTerminationRequest: PropTypes.func,
+ onResponderTerminationRequest?: ?(e: PressEvent) => boolean,
/**
* Does this view want to become responder on the start of a touch?
@@ -373,7 +191,7 @@
*
* See http://facebook.github.io/react-native/docs/view.html#onstartshouldsetresponder
*/
- onStartShouldSetResponder: PropTypes.func,
+ onStartShouldSetResponder?: ?(e: PressEvent) => boolean,
/**
* If a parent `View` wants to prevent a child `View` from becoming responder
@@ -384,89 +202,140 @@
*
* See http://facebook.github.io/react-native/docs/view.html#onstartshouldsetrespondercapture
*/
- onStartShouldSetResponderCapture: PropTypes.func,
+ onStartShouldSetResponderCapture?: ?(e: PressEvent) => boolean,
+|}>;
+
+type AndroidDrawableThemeAttr = $ReadOnly<{|
+ type: 'ThemeAttrAndroid',
+ attribute: string,
+|}>;
+
+type AndroidDrawableRipple = $ReadOnly<{|
+ type: 'RippleAndroid',
+ color?: ?number,
+ borderless?: ?boolean,
+|}>;
+
+type AndroidDrawable = AndroidDrawableThemeAttr | AndroidDrawableRipple;
+
+type AndroidViewProps = $ReadOnly<{|
+ nativeBackgroundAndroid?: ?AndroidDrawable,
+ nativeForegroundAndroid?: ?AndroidDrawable,
/**
- * Does this view want to "claim" touch responsiveness? This is called for
- * every touch move on the `View` when it is not the responder.
+ * Whether this `View` should render itself (and all of its children) into a
+ * single hardware texture on the GPU.
*
- * `View.props.onMoveShouldSetResponder: (event) => [true | false]`, where
- * `event` is a synthetic touch event as described above.
+ * @platform android
*
- * See http://facebook.github.io/react-native/docs/view.html#onmoveshouldsetresponder
+ * See http://facebook.github.io/react-native/docs/view.html#rendertohardwaretextureandroid
*/
- onMoveShouldSetResponder: PropTypes.func,
+ renderToHardwareTextureAndroid?: ?boolean,
/**
- * If a parent `View` wants to prevent a child `View` from becoming responder
- * on a move, it should have this handler which returns `true`.
+ * Views that are only used to layout their children or otherwise don't draw
+ * anything may be automatically removed from the native hierarchy as an
+ * optimization. Set this property to `false` to disable this optimization and
+ * ensure that this `View` exists in the native view hierarchy.
*
- * `View.props.onMoveShouldSetResponderCapture: (event) => [true | false]`,
- * where `event` is a synthetic touch event as described above.
+ * @platform android
*
- * See http://facebook.github.io/react-native/docs/view.html#onMoveShouldsetrespondercapture
+ * See http://facebook.github.io/react-native/docs/view.html#collapsable
*/
- onMoveShouldSetResponderCapture: PropTypes.func,
+ collapsable?: ?boolean,
/**
- * This defines how far a touch event can start away from the view.
- * Typical interface guidelines recommend touch targets that are at least
- * 30 - 40 points/density-independent pixels.
+ * Whether this `View` needs to rendered offscreen and composited with an
+ * alpha in order to preserve 100% correct colors and blending behavior.
*
- * > The touch area never extends past the parent view bounds and the Z-index
- * > of sibling views always takes precedence if a touch hits two overlapping
- * > views.
+ * @platform android
*
- * See http://facebook.github.io/react-native/docs/view.html#hitslop
+ * See http://facebook.github.io/react-native/docs/view.html#needsoffscreenalphacompositing
*/
- hitSlop: EdgeInsetsPropType,
+ needsOffscreenAlphaCompositing?: ?boolean,
/**
- * Invoked on mount and layout changes with:
+ * Indicates to accessibility services to treat UI component like a
+ * native one. Works for Android only.
*
- * `{nativeEvent: { layout: {x, y, width, height}}}`
+ * @platform android
*
- * This event is fired immediately once the layout has been calculated, but
- * the new layout may not yet be reflected on the screen at the time the
- * event is received, especially if a layout animation is in progress.
+ * See http://facebook.github.io/react-native/docs/view.html#accessibilitycomponenttype
+ */
+ accessibilityComponentType?: ?AccessibilityComponentType,
+
+ /**
+ * Indicates to accessibility services whether the user should be notified
+ * when this view changes. Works for Android API >= 19 only.
*
- * See http://facebook.github.io/react-native/docs/view.html#onlayout
+ * @platform android
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#accessibilityliveregion
*/
- onLayout: PropTypes.func,
+ accessibilityLiveRegion?: ?('none' | 'polite' | 'assertive'),
/**
- * Controls whether the `View` can be the target of touch events.
+ * Controls how view is important for accessibility which is if it
+ * fires accessibility events and if it is reported to accessibility services
+ * that query the screen. Works for Android only.
*
- * See http://facebook.github.io/react-native/docs/view.html#pointerevents
+ * @platform android
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#importantforaccessibility
*/
- pointerEvents: PropTypes.oneOf(['box-none', 'none', 'box-only', 'auto']),
+ importantForAccessibility?: ?('auto' | 'yes' | 'no' | 'no-hide-descendants'),
+|}>;
+type IOSViewProps = $ReadOnly<{|
/**
- * See http://facebook.github.io/react-native/docs/style.html
+ * Provides an array of custom actions available for accessibility.
+ *
+ * @platform ios
*/
- style: stylePropType,
+ accessibilityActions?: ?$ReadOnlyArray<string>,
/**
- * This is a special performance property exposed by `RCTView` and is useful
- * for scrolling content when there are many subviews, most of which are
- * offscreen. For this property to be effective, it must be applied to a
- * view that contains many subviews that extend outside its bound. The
- * subviews must also have `overflow: hidden`, as should the containing view
- * (or one of its superviews).
+ * Prevents view from being inverted if set to true and color inversion is turned on.
*
- * See http://facebook.github.io/react-native/docs/view.html#removeclippedsubviews
+ * @platform ios
*/
- removeClippedSubviews: PropTypes.bool,
+ accessibilityIgnoresInvertColors?: ?boolean,
/**
- * Whether this `View` should render itself (and all of its children) into a
- * single hardware texture on the GPU.
+ * Provides additional traits to screen reader. By default no traits are
+ * provided unless specified otherwise in element.
*
- * @platform android
+ * You can provide one trait or an array of many traits.
*
- * See http://facebook.github.io/react-native/docs/view.html#rendertohardwaretextureandroid
+ * @platform ios
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#accessibilitytraits
*/
- renderToHardwareTextureAndroid: PropTypes.bool,
+ accessibilityTraits?: ?(
+ | AccessibilityTrait
+ | $ReadOnlyArray<AccessibilityTrait>
+ ),
+
+ /**
+ * A value indicating whether VoiceOver should ignore the elements
+ * within views that are siblings of the receiver.
+ * Default is `false`.
+ *
+ * @platform ios
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#accessibilityviewismodal
+ */
+ accessibilityViewIsModal?: ?boolean,
+
+ /**
+ * A value indicating whether the accessibility elements contained within
+ * this accessibility element are hidden.
+ *
+ * @platform ios
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#accessibilityElementsHidden
+ */
+ accessibilityElementsHidden?: ?boolean,
/**
* Whether this `View` should be rendered as a bitmap before compositing.
@@ -475,32 +344,107 @@
*
* See http://facebook.github.io/react-native/docs/view.html#shouldrasterizeios
*/
- shouldRasterizeIOS: PropTypes.bool,
+ shouldRasterizeIOS?: ?boolean,
+|}>;
+
+export type ViewProps = $ReadOnly<{|
+ ...DirectEventProps,
+ ...GestureResponderEventProps,
+ ...TouchEventProps,
+ ...AndroidViewProps,
+ ...IOSViewProps,
+
+ // There's no easy way to create a different type if (Platform.isTV):
+ // so we must include TVViewProps
+ ...TVViewProps,
+
+ children?: React.Node,
+ style?: ?ViewStyleProp,
/**
- * Views that are only used to layout their children or otherwise don't draw
- * anything may be automatically removed from the native hierarchy as an
- * optimization. Set this property to `false` to disable this optimization and
- * ensure that this `View` exists in the native view hierarchy.
+ * When `true`, indicates that the view is an accessibility element.
+ * By default, all the touchable elements are accessible.
*
- * @platform android
+ * See http://facebook.github.io/react-native/docs/view.html#accessible
+ */
+ accessible?: ?boolean,
+
+ /**
+ * Overrides the text that's read by the screen reader when the user interacts
+ * with the element. By default, the label is constructed by traversing all
+ * the children and accumulating all the `Text` nodes separated by space.
*
- * See http://facebook.github.io/react-native/docs/view.html#collapsable
+ * See http://facebook.github.io/react-native/docs/view.html#accessibilitylabel
*/
- collapsable: PropTypes.bool,
+ accessibilityLabel?: ?Stringish,
/**
- * Whether this `View` needs to rendered offscreen and composited with an
- * alpha in order to preserve 100% correct colors and blending behavior.
+ * An accessibility hint helps users understand what will happen when they perform
+ * an action on the accessibility element when that result is not obvious from the
+ * accessibility label.
*
- * @platform android
*
- * See http://facebook.github.io/react-native/docs/view.html#needsoffscreenalphacompositing
+ * See http://facebook.github.io/react-native/docs/view.html#accessibilityHint
*/
- needsOffscreenAlphaCompositing: PropTypes.bool,
+ accessibilityHint?: ?Stringish,
/**
- * Any additional platform-specific view prop types, or prop type overrides.
+ * Indicates to accessibility services to treat UI component like a specific role.
*/
- ...PlatformViewPropTypes,
-};
+ accessibilityRole?: ?AccessibilityRole,
+
+ /**
+ * Indicates to accessibility services that UI Component is in a specific State.
+ */
+ accessibilityStates?: ?AccessibilityStates,
+
+ /**
+ * Used to locate this view in end-to-end tests.
+ *
+ * > This disables the 'layout-only view removal' optimization for this view!
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#testid
+ */
+ testID?: ?string,
+
+ /**
+ * Used to locate this view from native classes.
+ *
+ * > This disables the 'layout-only view removal' optimization for this view!
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#nativeid
+ */
+ nativeID?: ?string,
+
+ /**
+ * This defines how far a touch event can start away from the view.
+ * Typical interface guidelines recommend touch targets that are at least
+ * 30 - 40 points/density-independent pixels.
+ *
+ * > The touch area never extends past the parent view bounds and the Z-index
+ * > of sibling views always takes precedence if a touch hits two overlapping
+ * > views.
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#hitslop
+ */
+ hitSlop?: ?EdgeInsetsProp,
+
+ /**
+ * Controls whether the `View` can be the target of touch events.
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#pointerevents
+ */
+ pointerEvents?: ?('auto' | 'box-none' | 'box-only' | 'none'),
+
+ /**
+ * This is a special performance property exposed by `RCTView` and is useful
+ * for scrolling content when there are many subviews, most of which are
+ * offscreen. For this property to be effective, it must be applied to a
+ * view that contains many subviews that extend outside its bound. The
+ * subviews must also have `overflow: hidden`, as should the containing view
+ * (or one of its superviews).
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#removeclippedsubviews
+ */
+ removeClippedSubviews?: ?boolean,
+|}>;

Libraries/Components/View/ViewStylePropTypes.js

@@ -1,61 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow
- */
-
-'use strict';
-
-const ColorPropType = require('ColorPropType');
-const LayoutPropTypes = require('LayoutPropTypes');
-const ReactPropTypes = require('prop-types');
-const ShadowPropTypesIOS = require('ShadowPropTypesIOS');
-const TransformPropTypes = require('TransformPropTypes');
-
-/**
- * Warning: Some of these properties may not be supported in all releases.
- */
-const ViewStylePropTypes = {
- ...LayoutPropTypes,
- ...ShadowPropTypesIOS,
- ...TransformPropTypes,
- backfaceVisibility: ReactPropTypes.oneOf(['visible', 'hidden']),
- backgroundColor: ColorPropType,
- borderColor: ColorPropType,
- borderTopColor: ColorPropType,
- borderRightColor: ColorPropType,
- borderBottomColor: ColorPropType,
- borderLeftColor: ColorPropType,
- borderStartColor: ColorPropType,
- borderEndColor: ColorPropType,
- borderRadius: ReactPropTypes.number,
- borderTopLeftRadius: ReactPropTypes.number,
- borderTopRightRadius: ReactPropTypes.number,
- borderTopStartRadius: ReactPropTypes.number,
- borderTopEndRadius: ReactPropTypes.number,
- borderBottomLeftRadius: ReactPropTypes.number,
- borderBottomRightRadius: ReactPropTypes.number,
- borderBottomStartRadius: ReactPropTypes.number,
- borderBottomEndRadius: ReactPropTypes.number,
- borderStyle: ReactPropTypes.oneOf(['solid', 'dotted', 'dashed']),
- borderWidth: ReactPropTypes.number,
- borderTopWidth: ReactPropTypes.number,
- borderRightWidth: ReactPropTypes.number,
- borderBottomWidth: ReactPropTypes.number,
- borderLeftWidth: ReactPropTypes.number,
- opacity: ReactPropTypes.number,
- /**
- * (Android-only) Sets the elevation of a view, using Android's underlying
- * [elevation API](https://developer.android.com/training/material/shadows-clipping.html#Elevation).
- * This adds a drop shadow to the item and affects z-order for overlapping views.
- * Only supported on Android 5.0+, has no effect on earlier versions.
- * @platform android
- */
- elevation: ReactPropTypes.number,
-};
-
-module.exports = ViewStylePropTypes;

Libraries/Components/ViewPager/AndroidViewPagerNativeComponent.js

@@ -0,0 +1,112 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow
+ */
+
+'use strict';
+
+const requireNativeComponent = require('requireNativeComponent');
+
+import type {SyntheticEvent} from 'CoreEventTypes';
+import type {NativeComponent} from 'ReactNative';
+import type {Node} from 'React';
+import type {ViewStyleProp} from 'StyleSheet';
+
+type PageScrollState = 'idle' | 'dragging' | 'settling';
+
+type PageScrollEvent = SyntheticEvent<
+ $ReadOnly<{|
+ position: number,
+ offset: number,
+ |}>,
+>;
+
+type PageScrollStateChangedEvent = SyntheticEvent<
+ $ReadOnly<{|
+ pageScrollState: PageScrollState,
+ |}>,
+>;
+
+type PageSelectedEvent = SyntheticEvent<
+ $ReadOnly<{|
+ position: number,
+ |}>,
+>;
+
+type NativeProps = $ReadOnly<{|
+ /**
+ * Index of initial page that should be selected. Use `setPage` method to
+ * update the page, and `onPageSelected` to monitor page changes
+ */
+ initialPage?: ?number,
+
+ /**
+ * Executed when transitioning between pages (ether because of animation for
+ * the requested page change or when user is swiping/dragging between pages)
+ * The `event.nativeEvent` object for this callback will carry following data:
+ * - position - index of first page from the left that is currently visible
+ * - offset - value from range [0,1) describing stage between page transitions.
+ * Value x means that (1 - x) fraction of the page at "position" index is
+ * visible, and x fraction of the next page is visible.
+ */
+ onPageScroll?: ?(e: PageScrollEvent) => void,
+
+ /**
+ * Function called when the page scrolling state has changed.
+ * The page scrolling state can be in 3 states:
+ * - idle, meaning there is no interaction with the page scroller happening at the time
+ * - dragging, meaning there is currently an interaction with the page scroller
+ * - settling, meaning that there was an interaction with the page scroller, and the
+ * page scroller is now finishing it's closing or opening animation
+ */
+ onPageScrollStateChanged?: ?(e: PageScrollStateChangedEvent) => void,
+
+ /**
+ * This callback will be called once ViewPager finish navigating to selected page
+ * (when user swipes between pages). The `event.nativeEvent` object passed to this
+ * callback will have following fields:
+ * - position - index of page that has been selected
+ */
+ onPageSelected?: ?(e: PageSelectedEvent) => void,
+
+ /**
+ * Blank space to show between pages. This is only visible while scrolling, pages are still
+ * edge-to-edge.
+ */
+ pageMargin?: ?number,
+
+ /**
+ * Whether enable showing peekFraction or not. If this is true, the preview of
+ * last and next page will show in current screen. Defaults to false.
+ */
+
+ peekEnabled?: ?boolean,
+
+ /**
+ * Determines whether the keyboard gets dismissed in response to a drag.
+ * - 'none' (the default), drags do not dismiss the keyboard.
+ * - 'on-drag', the keyboard is dismissed when a drag begins.
+ */
+ keyboardDismissMode?: ?('none' | 'on-drag'),
+
+ /**
+ * When false, the content does not scroll.
+ * The default value is true.
+ */
+ scrollEnabled?: ?boolean,
+
+ children?: Node,
+
+ style?: ?ViewStyleProp,
+|}>;
+
+type ViewPagerNativeType = Class<NativeComponent<NativeProps>>;
+
+module.exports = ((requireNativeComponent(
+ 'AndroidViewPager',
+): any): ViewPagerNativeType);

Libraries/Components/ViewPager/ViewPagerAndroid.android.js

@@ -1,29 +1,48 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
- * @flow
+ * @flow strict-local
*/
'use strict';
const React = require('React');
-const PropTypes = require('prop-types');
const ReactNative = require('ReactNative');
const UIManager = require('UIManager');
-const ViewPropTypes = require('ViewPropTypes');
const dismissKeyboard = require('dismissKeyboard');
-const requireNativeComponent = require('requireNativeComponent');
-const NativeAndroidViewPager = requireNativeComponent('AndroidViewPager');
+const NativeAndroidViewPager = require('AndroidViewPagerNativeComponent');
+
+import type {SyntheticEvent} from 'CoreEventTypes';
+import type {ViewStyleProp} from 'StyleSheet';
const VIEWPAGER_REF = 'viewPager';
-type Event = Object;
+type PageScrollState = 'idle' | 'dragging' | 'settling';
+
+type PageScrollEvent = SyntheticEvent<
+ $ReadOnly<{|
+ position: number,
+ offset: number,
+ |}>,
+>;
+
+type PageScrollStateChangedEvent = SyntheticEvent<
+ $ReadOnly<{|
+ pageScrollState: PageScrollState,
+ |}>,
+>;
+
+type PageSelectedEvent = SyntheticEvent<
+ $ReadOnly<{|
+ position: number,
+ |}>,
+>;
export type ViewPagerScrollState = $Enum<{
idle: string,
@@ -31,66 +50,12 @@
settling: string,
}>;
-/**
- * Container that allows to flip left and right between child views. Each
- * child view of the `ViewPagerAndroid` will be treated as a separate page
- * and will be stretched to fill the `ViewPagerAndroid`.
- *
- * It is important all children are `<View>`s and not composite components.
- * You can set style properties like `padding` or `backgroundColor` for each
- * child. It is also important that each child have a `key` prop.
- *
- * Example:
- *
- * ```
- * render: function() {
- * return (
- * <ViewPagerAndroid
- * style={styles.viewPager}
- * initialPage={0}>
- * <View style={styles.pageStyle} key="1">
- * <Text>First page</Text>
- * </View>
- * <View style={styles.pageStyle} key="2">
- * <Text>Second page</Text>
- * </View>
- * </ViewPagerAndroid>
- * );
- * }
- *
- * ...
- *
- * var styles = {
- * ...
- * viewPager: {
- * flex: 1
- * },
- * pageStyle: {
- * alignItems: 'center',
- * padding: 20,
- * }
- * }
- * ```
- */
-class ViewPagerAndroid extends React.Component<{
- initialPage?: number,
- onPageScroll?: Function,
- onPageScrollStateChanged?: Function,
- onPageSelected?: Function,
- pageMargin?: number,
- peekEnabled?: boolean,
- keyboardDismissMode?: 'none' | 'on-drag',
- scrollEnabled?: boolean,
-}> {
- /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
- * when making Flow check .android.js files. */
- static propTypes = {
- ...ViewPropTypes,
+type Props = $ReadOnly<{|
/**
* Index of initial page that should be selected. Use `setPage` method to
* update the page, and `onPageSelected` to monitor page changes
*/
- initialPage: PropTypes.number,
+ initialPage?: ?number,
/**
* Executed when transitioning between pages (ether because of animation for
@@ -101,7 +66,7 @@
* Value x means that (1 - x) fraction of the page at "position" index is
* visible, and x fraction of the next page is visible.
*/
- onPageScroll: PropTypes.func,
+ onPageScroll?: ?(e: PageScrollEvent) => void,
/**
* Function called when the page scrolling state has changed.
@@ -111,7 +76,7 @@
* - settling, meaning that there was an interaction with the page scroller, and the
* page scroller is now finishing it's closing or opening animation
*/
- onPageScrollStateChanged: PropTypes.func,
+ onPageScrollStateChanged?: ?(e: PageScrollStateChangedEvent) => void,
/**
* This callback will be called once ViewPager finish navigating to selected page
@@ -119,37 +84,82 @@
* callback will have following fields:
* - position - index of page that has been selected
*/
- onPageSelected: PropTypes.func,
+ onPageSelected?: ?(e: PageSelectedEvent) => void,
/**
* Blank space to show between pages. This is only visible while scrolling, pages are still
* edge-to-edge.
*/
- pageMargin: PropTypes.number,
+ pageMargin?: ?number,
+
+ /**
+ * Whether enable showing peekFraction or not. If this is true, the preview of
+ * last and next page will show in current screen. Defaults to false.
+ */
+
+ peekEnabled?: ?boolean,
/**
* Determines whether the keyboard gets dismissed in response to a drag.
* - 'none' (the default), drags do not dismiss the keyboard.
* - 'on-drag', the keyboard is dismissed when a drag begins.
*/
- keyboardDismissMode: PropTypes.oneOf([
- 'none', // default
- 'on-drag',
- ]),
+ keyboardDismissMode?: ?('none' | 'on-drag'),
/**
* When false, the content does not scroll.
* The default value is true.
*/
- scrollEnabled: PropTypes.bool,
+ scrollEnabled?: ?boolean,
- /**
- * Whether enable showing peekFraction or not. If this is true, the preview of
- * last and next page will show in current screen. Defaults to false.
+ children?: React.Node,
+
+ style?: ?ViewStyleProp,
+|}>;
+
+/**
+ * Container that allows to flip left and right between child views. Each
+ * child view of the `ViewPagerAndroid` will be treated as a separate page
+ * and will be stretched to fill the `ViewPagerAndroid`.
+ *
+ * It is important all children are `<View>`s and not composite components.
+ * You can set style properties like `padding` or `backgroundColor` for each
+ * child. It is also important that each child have a `key` prop.
+ *
+ * Example:
+ *
+ * ```
+ * render: function() {
+ * return (
+ * <ViewPagerAndroid
+ * style={styles.viewPager}
+ * initialPage={0}>
+ * <View style={styles.pageStyle} key="1">
+ * <Text>First page</Text>
+ * </View>
+ * <View style={styles.pageStyle} key="2">
+ * <Text>Second page</Text>
+ * </View>
+ * </ViewPagerAndroid>
+ * );
+ * }
+ *
+ * ...
+ *
+ * var styles = {
+ * ...
+ * viewPager: {
+ * flex: 1
+ * },
+ * pageStyle: {
+ * alignItems: 'center',
+ * padding: 20,
+ * }
+ * }
+ * ```
*/
- peekEnabled: PropTypes.bool,
- };
+class ViewPagerAndroid extends React.Component<Props> {
componentDidMount() {
if (this.props.initialPage != null) {
this.setPageWithoutAnimation(this.props.initialPage);
@@ -168,8 +178,6 @@
// Override styles so that each page will fill the parent. Native component
// will handle positioning of elements, so it's not important to offset
// them correctly.
- /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
- * when making Flow check .android.js files. */
return React.Children.map(this.props.children, function(child) {
if (!child) {
return null;
@@ -205,7 +213,7 @@
});
};
- _onPageScroll = (e: Event) => {
+ _onPageScroll = (e: PageScrollEvent) => {
if (this.props.onPageScroll) {
this.props.onPageScroll(e);
}
@@ -214,13 +222,13 @@
}
};
- _onPageScrollStateChanged = (e: Event) => {
+ _onPageScrollStateChanged = (e: PageScrollStateChangedEvent) => {
if (this.props.onPageScrollStateChanged) {
- this.props.onPageScrollStateChanged(e.nativeEvent.pageScrollState);
+ this.props.onPageScrollStateChanged(e);
}
};
- _onPageSelected = (e: Event) => {
+ _onPageSelected = (e: PageSelectedEvent) => {
if (this.props.onPageSelected) {
this.props.onPageSelected(e);
}
@@ -233,7 +241,7 @@
setPage = (selectedPage: number) => {
UIManager.dispatchViewManagerCommand(
ReactNative.findNodeHandle(this),
- UIManager.AndroidViewPager.Commands.setPage,
+ UIManager.getViewManagerConfig('AndroidViewPager').Commands.setPage,
[selectedPage],
);
};
@@ -245,7 +253,8 @@
setPageWithoutAnimation = (selectedPage: number) => {
UIManager.dispatchViewManagerCommand(
ReactNative.findNodeHandle(this),
- UIManager.AndroidViewPager.Commands.setPageWithoutAnimation,
+ UIManager.getViewManagerConfig('AndroidViewPager').Commands
+ .setPageWithoutAnimation,
[selectedPage],
);
};
@@ -255,8 +264,6 @@
<NativeAndroidViewPager
{...this.props}
ref={VIEWPAGER_REF}
- /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was
- * found when making Flow check .android.js files. */
style={this.props.style}
onPageScroll={this._onPageScroll}
onPageScrollStateChanged={this._onPageScrollStateChanged}

Libraries/Components/ViewPager/ViewPagerAndroid.ios.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/WebView/WebView.android.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,15 +9,15 @@
'use strict';
-const EdgeInsetsPropType = require('EdgeInsetsPropType');
const ActivityIndicator = require('ActivityIndicator');
-const React = require('React');
+const DeprecatedViewPropTypes = require('DeprecatedViewPropTypes');
+const DeprecatedEdgeInsetsPropType = require('DeprecatedEdgeInsetsPropType');
const PropTypes = require('prop-types');
+const React = require('React');
const ReactNative = require('ReactNative');
const StyleSheet = require('StyleSheet');
const UIManager = require('UIManager');
const View = require('View');
-const ViewPropTypes = require('ViewPropTypes');
const WebViewShared = require('WebViewShared');
const deprecatedPropType = require('deprecatedPropType');
@@ -44,7 +44,7 @@
*/
class WebView extends React.Component {
static propTypes = {
- ...ViewPropTypes,
+ ...DeprecatedViewPropTypes,
renderError: PropTypes.func,
renderLoading: PropTypes.func,
onLoad: PropTypes.func,
@@ -52,12 +52,12 @@
onLoadStart: PropTypes.func,
onError: PropTypes.func,
automaticallyAdjustContentInsets: PropTypes.bool,
- contentInset: EdgeInsetsPropType,
+ contentInset: DeprecatedEdgeInsetsPropType,
onNavigationStateChange: PropTypes.func,
onMessage: PropTypes.func,
onContentSizeChange: PropTypes.func,
startInLoadingState: PropTypes.bool, // force WebView to show loadingView on first load
- style: ViewPropTypes.style,
+ style: DeprecatedViewPropTypes.style,
html: deprecatedPropType(
PropTypes.string,
@@ -116,6 +116,16 @@
useWebKit: PropTypes.bool,
/**
+ * Used on Android only to disable Hardware Acceleration if needed
+ * Hardware acceleration can not be enabled at view level but it can be
+ * disabled see:
+ * https://developer.android.com/guide/topics/graphics/hardware-accel
+ *
+ * @platform android
+ */
+ hardwareAccelerationEnabledExperimental: PropTypes.bool,
+
+ /**
* Used on Android only, JS is enabled by default for WebView on iOS
* @platform android
*/
@@ -248,6 +258,7 @@
javaScriptEnabled: true,
thirdPartyCookiesEnabled: true,
scalesPageToFit: true,
+ hardwareAccelerationEnabledExperimental: true,
saveFormDataDisabled: false,
originWhitelist: WebViewShared.defaultOriginWhitelist,
};
@@ -327,6 +338,9 @@
injectedJavaScript={this.props.injectedJavaScript}
userAgent={this.props.userAgent}
javaScriptEnabled={this.props.javaScriptEnabled}
+ hardwareAccelerationEnabledExperimental={
+ this.props.hardwareAccelerationEnabledExperimental
+ }
thirdPartyCookiesEnabled={this.props.thirdPartyCookiesEnabled}
domStorageEnabled={this.props.domStorageEnabled}
messagingEnabled={typeof this.props.onMessage === 'function'}
@@ -366,7 +380,7 @@
goForward = () => {
UIManager.dispatchViewManagerCommand(
this.getWebViewHandle(),
- UIManager.RCTWebView.Commands.goForward,
+ UIManager.getViewManagerConfig('RCTWebView').Commands.goForward,
null,
);
};
@@ -374,7 +388,7 @@
goBack = () => {
UIManager.dispatchViewManagerCommand(
this.getWebViewHandle(),
- UIManager.RCTWebView.Commands.goBack,
+ UIManager.getViewManagerConfig('RCTWebView').Commands.goBack,
null,
);
};
@@ -385,7 +399,7 @@
});
UIManager.dispatchViewManagerCommand(
this.getWebViewHandle(),
- UIManager.RCTWebView.Commands.reload,
+ UIManager.getViewManagerConfig('RCTWebView').Commands.reload,
null,
);
};
@@ -393,7 +407,7 @@
stopLoading = () => {
UIManager.dispatchViewManagerCommand(
this.getWebViewHandle(),
- UIManager.RCTWebView.Commands.stopLoading,
+ UIManager.getViewManagerConfig('RCTWebView').Commands.stopLoading,
null,
);
};
@@ -401,7 +415,7 @@
postMessage = data => {
UIManager.dispatchViewManagerCommand(
this.getWebViewHandle(),
- UIManager.RCTWebView.Commands.postMessage,
+ UIManager.getViewManagerConfig('RCTWebView').Commands.postMessage,
[String(data)],
);
};
@@ -415,7 +429,7 @@
injectJavaScript = data => {
UIManager.dispatchViewManagerCommand(
this.getWebViewHandle(),
- UIManager.RCTWebView.Commands.injectJavaScript,
+ UIManager.getViewManagerConfig('RCTWebView').Commands.injectJavaScript,
[data],
);
};

Libraries/Components/WebView/WebView.ios.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,21 +11,20 @@
'use strict';
const ActivityIndicator = require('ActivityIndicator');
-const EdgeInsetsPropType = require('EdgeInsetsPropType');
+const DeprecatedViewPropTypes = require('DeprecatedViewPropTypes');
+const DeprecatedEdgeInsetsPropType = require('DeprecatedEdgeInsetsPropType');
const Linking = require('Linking');
const PropTypes = require('prop-types');
const React = require('React');
const ReactNative = require('ReactNative');
-const ScrollView = require('ScrollView');
const StyleSheet = require('StyleSheet');
const Text = require('Text');
const UIManager = require('UIManager');
const View = require('View');
-const ViewPropTypes = require('ViewPropTypes');
const WebViewShared = require('WebViewShared');
const deprecatedPropType = require('deprecatedPropType');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
const keyMirror = require('fbjs/lib/keyMirror');
const processDecelerationRate = require('processDecelerationRate');
const requireNativeComponent = require('requireNativeComponent');
@@ -114,7 +113,7 @@
static JSNavigationScheme = JSNavigationScheme;
static NavigationType = NavigationType;
static propTypes = {
- ...ViewPropTypes,
+ ...DeprecatedViewPropTypes,
html: deprecatedPropType(
PropTypes.string,
@@ -234,7 +233,7 @@
* the scroll view. Defaults to {top: 0, left: 0, bottom: 0, right: 0}.
* @platform ios
*/
- contentInset: EdgeInsetsPropType,
+ contentInset: DeprecatedEdgeInsetsPropType,
/**
* Function that is invoked when the `WebView` loading starts or ends.
*/
@@ -257,7 +256,7 @@
/**
* The style to apply to the `WebView`.
*/
- style: ViewPropTypes.style,
+ style: DeprecatedViewPropTypes.style,
/**
* Determines the types of data converted to clickable URLs in the web view's content.
@@ -287,6 +286,16 @@
]),
/**
+ * Used on Android only to disable Hardware Acceleration if needed
+ * Hardware acceleration can not be enabled at view level but it can be
+ * disabled see:
+ * https://developer.android.com/guide/topics/graphics/hardware-accel
+ *
+ * @platform android
+ */
+ hardwareAccelerationEnabledExperimental: PropTypes.bool,
+
+ /**
* Boolean value to enable JavaScript in the `WebView`. Used on Android only
* as JavaScript is enabled by default on iOS. The default value is `true`.
* @platform android
@@ -561,10 +570,10 @@
_getCommands() {
if (!this.props.useWebKit) {
- return UIManager.RCTWebView.Commands;
+ return UIManager.getViewManagerConfig('RCTWebView').Commands;
}
- return UIManager.RCTWKWebView.Commands;
+ return UIManager.getViewManagerConfig('RCTWKWebView').Commands;
}
/**

Libraries/Components/WebView/WebViewShared.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Components/WKWebView/WKWebView.ios.js

@@ -1,42 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow
- * @providesModule WKWebView
- */
-
-const React = require('react');
-
-const requireNativeComponent = require('requireNativeComponent');
-
-const RCTWKWebView = requireNativeComponent('RCTWKWebView');
-
-type RCTWKWebViewProps = {
- allowsInlineMediaPlayback?: boolean,
- mediaPlaybackRequiresUserAction?: boolean,
- dataDetectorTypes?: boolean,
-};
-
-class WKWebView extends React.Component<RCTWKWebViewProps> {
- componentWillReceiveProps(nextProps: RCTWKWebViewProps) {
- this.showRedboxOnPropChanges(nextProps, 'allowsInlineMediaPlayback');
- this.showRedboxOnPropChanges(nextProps, 'mediaPlaybackRequiresUserAction');
- this.showRedboxOnPropChanges(nextProps, 'dataDetectorTypes');
- }
-
- showRedboxOnPropChanges(nextProps: RCTWKWebViewProps, propName: string) {
- if (this.props[propName] !== nextProps[propName]) {
- console.error(`Changes to property ${propName} do nothing after the initial render.`);
- }
- }
-
- render() {
- return <RCTWKWebView {...this.props}/>;
- }
-}
-
-module.exports = WKWebView;

Libraries/Core/checkNativeVersion.js

@@ -0,0 +1,17 @@
+/**
+ * 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.
+ *
+ * @flow strict-local
+ * @format
+ */
+'use strict';
+
+/**
+ * Check for compatibility between the JS and native code.
+ * You can use this module directly, or just require InitializeCore.
+ */
+const ReactNativeVersionCheck = require('ReactNativeVersionCheck');
+ReactNativeVersionCheck.checkVersions();

Libraries/Core/Devtools/getDevServer.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Core/Devtools/openFileInEditor.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Core/Devtools/parseErrorStack.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -19,6 +19,7 @@
export type ExtendedError = Error & {
framesToPop?: number,
+ jsEngine?: string,
};
function parseErrorStack(e: ExtendedError): Array<StackFrame> {

Libraries/Core/Devtools/setupDevtools.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,16 +10,6 @@
'use strict';
-type DevToolsPluginConnection = {
- isAppActive: () => boolean,
- host: string,
- port: number,
-};
-
-type DevToolsPlugin = {
- connectToDevTools: (connection: DevToolsPluginConnection) => void,
-};
-
let register = function() {
// noop
};

Libraries/Core/Devtools/symbolicateStackTrace.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Core/ExceptionsManager.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -22,18 +22,16 @@
const parseErrorStack = require('parseErrorStack');
const stack = parseErrorStack(e);
const currentExceptionID = ++exceptionID;
+ const message =
+ e.jsEngine == null ? e.message : `${e.message}, js engine: ${e.jsEngine}`;
if (isFatal) {
ExceptionsManager.reportFatalException(
- e.message,
+ message,
stack,
currentExceptionID,
);
} else {
- ExceptionsManager.reportSoftException(
- e.message,
- stack,
- currentExceptionID,
- );
+ ExceptionsManager.reportSoftException(message, stack, currentExceptionID);
}
if (__DEV__) {
const symbolicateStackTrace = require('symbolicateStackTrace');

Libraries/Core/InitializeCore.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -25,194 +25,31 @@
*/
'use strict';
-const {polyfillObjectProperty, polyfillGlobal} = require('PolyfillFunctions');
+const start = Date.now();
-if (global.GLOBAL === undefined) {
- global.GLOBAL = global;
-}
-
-if (global.window === undefined) {
- global.window = global;
-}
-
-// Set up collections
-const _shouldPolyfillCollection = require('_shouldPolyfillES6Collection');
-if (_shouldPolyfillCollection('Map')) {
- polyfillGlobal('Map', () => require('Map'));
-}
-if (_shouldPolyfillCollection('Set')) {
- polyfillGlobal('Set', () => require('Set'));
-}
-
-// Set up process
-global.process = global.process || {};
-global.process.env = global.process.env || {};
-if (!global.process.env.NODE_ENV) {
- global.process.env.NODE_ENV = __DEV__ ? 'development' : 'production';
-}
-
-// Setup the Systrace profiling hooks if necessary
-if (global.__RCTProfileIsProfiling) {
- const Systrace = require('Systrace');
- Systrace.installReactHook();
- Systrace.setEnabled(true);
-}
-
-// Set up console
-const ExceptionsManager = require('ExceptionsManager');
-ExceptionsManager.installConsoleErrorReporter();
-
-// Set up error handler
-if (!global.__fbDisableExceptionsManager) {
- const handleError = (e, isFatal) => {
- try {
- ExceptionsManager.handleException(e, isFatal);
- } catch (ee) {
- console.log('Failed to print error: ', ee.message);
- throw e;
- }
- };
-
- const ErrorUtils = require('ErrorUtils');
- ErrorUtils.setGlobalHandler(handleError);
-}
-
-// Check for compatibility between the JS and native code
-const ReactNativeVersionCheck = require('ReactNativeVersionCheck');
-ReactNativeVersionCheck.checkVersions();
-
-// Set up Promise
-// The native Promise implementation throws the following error:
-// ERROR: Event loop not supported.
-polyfillGlobal('Promise', () => require('Promise'));
-
-// Set up regenerator.
-polyfillGlobal('regeneratorRuntime', () => {
- // The require just sets up the global, so make sure when we first
- // invoke it the global does not exist
- delete global.regeneratorRuntime;
-
- // regenerator-runtime/runtime exports the regeneratorRuntime object, so we
- // can return it safely.
- return require('regenerator-runtime/runtime');
-});
-
-// Set up timers
-const defineLazyTimer = name => {
- polyfillGlobal(name, () => require('JSTimers')[name]);
-};
-defineLazyTimer('setTimeout');
-defineLazyTimer('setInterval');
-defineLazyTimer('setImmediate');
-defineLazyTimer('clearTimeout');
-defineLazyTimer('clearInterval');
-defineLazyTimer('clearImmediate');
-defineLazyTimer('requestAnimationFrame');
-defineLazyTimer('cancelAnimationFrame');
-defineLazyTimer('requestIdleCallback');
-defineLazyTimer('cancelIdleCallback');
-
-// Set up XHR
-// The native XMLHttpRequest in Chrome dev tools is CORS aware and won't
-// let you fetch anything from the internet
-polyfillGlobal('XMLHttpRequest', () => require('XMLHttpRequest'));
-polyfillGlobal('FormData', () => require('FormData'));
-
-polyfillGlobal('fetch', () => require('fetch').fetch);
-polyfillGlobal('Headers', () => require('fetch').Headers);
-polyfillGlobal('Request', () => require('fetch').Request);
-polyfillGlobal('Response', () => require('fetch').Response);
-polyfillGlobal('WebSocket', () => require('WebSocket'));
-polyfillGlobal('Blob', () => require('Blob'));
-polyfillGlobal('File', () => require('File'));
-polyfillGlobal('FileReader', () => require('FileReader'));
-polyfillGlobal('URL', () => require('URL'));
-
-// Set up alert
-if (!global.alert) {
- global.alert = function(text) {
- // Require Alert on demand. Requiring it too early can lead to issues
- // with things like Platform not being fully initialized.
- require('Alert').alert('Alert', '' + text);
- };
-}
-
-// Set up Geolocation
-let navigator = global.navigator;
-if (navigator === undefined) {
- global.navigator = navigator = {};
+require('setUpGlobals');
+require('polyfillES6Collections');
+require('setUpSystrace');
+require('setUpErrorHandling');
+require('checkNativeVersion');
+require('polyfillPromise');
+require('setUpRegeneratorRuntime');
+require('setUpTimers');
+require('setUpXHR');
+require('setUpAlert');
+require('setUpGeolocation');
+require('setUpBatchedBridge');
+require('setUpSegmentFetcher');
+if (__DEV__) {
+ require('setUpDeveloperTools');
}
-// see https://github.com/facebook/react-native/issues/10881
-polyfillObjectProperty(navigator, 'product', () => 'ReactNative');
-polyfillObjectProperty(navigator, 'geolocation', () => require('Geolocation'));
-
-// Just to make sure the JS gets packaged up. Wait until the JS environment has
-// been initialized before requiring them.
-const BatchedBridge = require('BatchedBridge');
-BatchedBridge.registerLazyCallableModule('Systrace', () => require('Systrace'));
-BatchedBridge.registerLazyCallableModule('JSTimers', () => require('JSTimers'));
-BatchedBridge.registerLazyCallableModule('HeapCapture', () =>
- require('HeapCapture'),
-);
-BatchedBridge.registerLazyCallableModule('SamplingProfiler', () =>
- require('SamplingProfiler'),
-);
-BatchedBridge.registerLazyCallableModule('RCTLog', () => require('RCTLog'));
-BatchedBridge.registerLazyCallableModule('RCTDeviceEventEmitter', () =>
- require('RCTDeviceEventEmitter'),
-);
-BatchedBridge.registerLazyCallableModule('RCTNativeAppEventEmitter', () =>
- require('RCTNativeAppEventEmitter'),
-);
-BatchedBridge.registerLazyCallableModule('PerformanceLogger', () =>
- require('PerformanceLogger'),
+const PerformanceLogger = require('PerformanceLogger');
+// We could just call PerformanceLogger.markPoint at the top of the file,
+// but then we'd be excluding the time it took to require PerformanceLogger.
+// Instead, we just use Date.now and backdate the timestamp.
+PerformanceLogger.markPoint(
+ 'initializeCore_start',
+ PerformanceLogger.currentTimestamp() - (Date.now() - start),
);
-BatchedBridge.registerLazyCallableModule('JSDevSupportModule', () =>
- require('JSDevSupportModule'),
-);
-
-global.__fetchSegment = function(
- segmentId: number,
- options: {|+otaBuildNumber: ?string|},
- callback: (?Error) => void,
-) {
- const {SegmentFetcher} = require('NativeModules');
- if (!SegmentFetcher) {
- throw new Error(
- 'SegmentFetcher is missing. Please ensure that it is ' +
- 'included as a NativeModule.',
- );
- }
-
- SegmentFetcher.fetchSegment(
- segmentId,
- options,
- (errorObject: ?{message: string, code: string}) => {
- if (errorObject) {
- const error = new Error(errorObject.message);
- (error: any).code = errorObject.code;
- callback(error);
- }
-
- callback(null);
- },
- );
-};
-
-// Set up devtools
-if (__DEV__) {
- if (!global.__RCTProfileIsProfiling) {
- BatchedBridge.registerCallableModule('HMRClient', require('HMRClient'));
-
- // not when debugging in chrome
- // TODO(t12832058) This check is broken
- if (!window.document) {
- require('setupDevtools');
- }
-
- // Set up inspector
- const JSInspector = require('JSInspector');
- JSInspector.registerAgent(require('NetworkAgent'));
- }
-}
+PerformanceLogger.markPoint('initializeCore_end');

Libraries/Core/__mocks__/ErrorUtils.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

Libraries/Core/polyfillES6Collections.js

@@ -0,0 +1,27 @@
+/**
+ * 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.
+ *
+ * @flow strict-local
+ * @format
+ */
+'use strict';
+
+const {polyfillGlobal} = require('PolyfillFunctions');
+
+/**
+ * Polyfill ES6 collections (Map and Set).
+ * If you don't need these polyfills, don't use InitializeCore; just directly
+ * require the modules you need from InitializeCore for setup.
+ */
+const _shouldPolyfillCollection = require('_shouldPolyfillES6Collection');
+if (_shouldPolyfillCollection('Map')) {
+ require('_wrapObjectFreezeAndFriends');
+ polyfillGlobal('Map', () => require('Map'));
+}
+if (_shouldPolyfillCollection('Set')) {
+ require('_wrapObjectFreezeAndFriends');
+ polyfillGlobal('Set', () => require('Set'));
+}

Libraries/Core/polyfillPromise.js

@@ -0,0 +1,21 @@
+/**
+ * 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.
+ *
+ * @flow
+ * @format
+ */
+'use strict';
+
+const {polyfillGlobal} = require('PolyfillFunctions');
+
+/**
+ * Set up Promise. The native Promise implementation throws the following error:
+ * ERROR: Event loop not supported.
+ *
+ * If you don't need these polyfills, don't use InitializeCore; just directly
+ * require the modules you need from InitializeCore for setup.
+ */
+polyfillGlobal('Promise', () => require('Promise'));

Libraries/Core/ReactNativeVersionCheck.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2017-present, Facebook, Inc.
+ * 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.

Libraries/Core/ReactNativeVersion.js

@@ -1,7 +1,7 @@
/**
* @generated by scripts/bump-oss-version.js
*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,7 +11,7 @@
exports.version = {
major: 0,
- minor: 57,
- patch: 8,
+ minor: 59,
+ patch: 4,
prerelease: null,
};

Libraries/Core/setUpAlert.js

@@ -0,0 +1,22 @@
+/**
+ * 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.
+ *
+ * @flow strict-local
+ * @format
+ */
+'use strict';
+
+/**
+ * Set up alert().
+ * You can use this module directly, or just require InitializeCore.
+ */
+if (!global.alert) {
+ global.alert = function(text) {
+ // Require Alert on demand. Requiring it too early can lead to issues
+ // with things like Platform not being fully initialized.
+ require('Alert').alert('Alert', '' + text);
+ };
+}

Libraries/Core/setUpBatchedBridge.js

@@ -0,0 +1,42 @@
+/**
+ * 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.
+ *
+ * @flow strict-local
+ * @format
+ */
+'use strict';
+
+/**
+ * Set up the BatchedBridge. This must be done after the other steps in
+ * InitializeCore to ensure that the JS environment has been initialized.
+ * You can use this module directly, or just require InitializeCore.
+ */
+const BatchedBridge = require('BatchedBridge');
+BatchedBridge.registerLazyCallableModule('Systrace', () => require('Systrace'));
+BatchedBridge.registerLazyCallableModule('JSTimers', () => require('JSTimers'));
+BatchedBridge.registerLazyCallableModule('HeapCapture', () =>
+ require('HeapCapture'),
+);
+BatchedBridge.registerLazyCallableModule('SamplingProfiler', () =>
+ require('SamplingProfiler'),
+);
+BatchedBridge.registerLazyCallableModule('RCTLog', () => require('RCTLog'));
+BatchedBridge.registerLazyCallableModule('RCTDeviceEventEmitter', () =>
+ require('RCTDeviceEventEmitter'),
+);
+BatchedBridge.registerLazyCallableModule('RCTNativeAppEventEmitter', () =>
+ require('RCTNativeAppEventEmitter'),
+);
+BatchedBridge.registerLazyCallableModule('PerformanceLogger', () =>
+ require('PerformanceLogger'),
+);
+BatchedBridge.registerLazyCallableModule('JSDevSupportModule', () =>
+ require('JSDevSupportModule'),
+);
+
+if (__DEV__ && !global.__RCTProfileIsProfiling) {
+ BatchedBridge.registerCallableModule('HMRClient', require('HMRClient'));
+}

Libraries/Core/setUpDeveloperTools.js

@@ -0,0 +1,28 @@
+/**
+ * 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.
+ *
+ * @flow strict-local
+ * @format
+ */
+'use strict';
+
+/**
+ * Sets up developer tools for React Native.
+ * You can use this module directly, or just require InitializeCore.
+ */
+if (__DEV__) {
+ if (!global.__RCTProfileIsProfiling) {
+ // not when debugging in chrome
+ // TODO(t12832058) This check is broken
+ if (!window.document) {
+ require('setupDevtools');
+ }
+
+ // Set up inspector
+ const JSInspector = require('JSInspector');
+ JSInspector.registerAgent(require('NetworkAgent'));
+ }
+}

Libraries/Core/setUpErrorHandling.js

@@ -0,0 +1,32 @@
+/**
+ * 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.
+ *
+ * @flow strict-local
+ * @format
+ */
+'use strict';
+
+/**
+ * Sets up the console and exception handling (redbox) for React Native.
+ * You can use this module directly, or just require InitializeCore.
+ */
+const ExceptionsManager = require('ExceptionsManager');
+ExceptionsManager.installConsoleErrorReporter();
+
+// Set up error handler
+if (!global.__fbDisableExceptionsManager) {
+ const handleError = (e, isFatal) => {
+ try {
+ ExceptionsManager.handleException(e, isFatal);
+ } catch (ee) {
+ console.log('Failed to print error: ', ee.message);
+ throw e;
+ }
+ };
+
+ const ErrorUtils = require('ErrorUtils');
+ ErrorUtils.setGlobalHandler(handleError);
+}

Libraries/Core/setUpGeolocation.js

@@ -0,0 +1,25 @@
+/**
+ * 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.
+ *
+ * @flow strict-local
+ * @format
+ */
+'use strict';
+
+const {polyfillObjectProperty} = require('PolyfillFunctions');
+
+/**
+ * Set up Geolocation.
+ * You can use this module directly, or just require InitializeCore.
+ */
+let navigator = global.navigator;
+if (navigator === undefined) {
+ global.navigator = navigator = {};
+}
+
+// see https://github.com/facebook/react-native/issues/10881
+polyfillObjectProperty(navigator, 'product', () => 'ReactNative');
+polyfillObjectProperty(navigator, 'geolocation', () => require('Geolocation'));

Libraries/Core/setUpGlobals.js

@@ -0,0 +1,29 @@
+/**
+ * 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.
+ *
+ * @flow strict-local
+ * @format
+ */
+'use strict';
+
+/**
+ * Sets up global variables for React Native.
+ * You can use this module directly, or just require InitializeCore.
+ */
+if (global.GLOBAL === undefined) {
+ global.GLOBAL = global;
+}
+
+if (global.window === undefined) {
+ global.window = global;
+}
+
+// Set up process
+global.process = global.process || {};
+global.process.env = global.process.env || {};
+if (!global.process.env.NODE_ENV) {
+ global.process.env.NODE_ENV = __DEV__ ? 'development' : 'production';
+}

Libraries/Core/setUpRegeneratorRuntime.js

@@ -0,0 +1,26 @@
+/**
+ * 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.
+ *
+ * @flow strict-local
+ * @format
+ */
+'use strict';
+
+const {polyfillGlobal} = require('PolyfillFunctions');
+
+/**
+ * Set up regenerator.
+ * You can use this module directly, or just require InitializeCore.
+ */
+polyfillGlobal('regeneratorRuntime', () => {
+ // The require just sets up the global, so make sure when we first
+ // invoke it the global does not exist
+ delete global.regeneratorRuntime;
+
+ // regenerator-runtime/runtime exports the regeneratorRuntime object, so we
+ // can return it safely.
+ return require('regenerator-runtime/runtime'); // flowlint-line untyped-import:off
+});

Libraries/Core/setUpSegmentFetcher.js

@@ -0,0 +1,42 @@
+/**
+ * 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.
+ *
+ * @flow strict-local
+ * @format
+ */
+'use strict';
+
+/**
+ * Set up SegmentFetcher.
+ * You can use this module directly, or just require InitializeCore.
+ */
+global.__fetchSegment = function(
+ segmentId: number,
+ options: {|+otaBuildNumber: ?string|},
+ callback: (?Error) => void,
+) {
+ const {SegmentFetcher} = require('NativeModules');
+ if (!SegmentFetcher) {
+ throw new Error(
+ 'SegmentFetcher is missing. Please ensure that it is ' +
+ 'included as a NativeModule.',
+ );
+ }
+
+ SegmentFetcher.fetchSegment(
+ segmentId,
+ options,
+ (errorObject: ?{message: string, code: string}) => {
+ if (errorObject) {
+ const error = new Error(errorObject.message);
+ (error: any).code = errorObject.code; // flowlint-line unclear-type: off
+ callback(error);
+ }
+
+ callback(null);
+ },
+ );
+};

Libraries/Core/setUpSystrace.js

@@ -0,0 +1,20 @@
+/**
+ * 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.
+ *
+ * @flow strict-local
+ * @format
+ */
+'use strict';
+
+/**
+ * Set up Systrace profiling hooks if necessary.
+ * You can use this module directly, or just require InitializeCore.
+ */
+if (global.__RCTProfileIsProfiling) {
+ const Systrace = require('Systrace');
+ Systrace.installReactHook();
+ Systrace.setEnabled(true);
+}

Libraries/Core/setUpTimers.js

@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @flow strict-local
+ * @format
+ */
+'use strict';
+
+const {polyfillGlobal} = require('PolyfillFunctions');
+
+/**
+ * Set up timers.
+ * You can use this module directly, or just require InitializeCore.
+ */
+const defineLazyTimer = name => {
+ polyfillGlobal(name, () => require('JSTimers')[name]);
+};
+defineLazyTimer('setTimeout');
+defineLazyTimer('setInterval');
+defineLazyTimer('setImmediate');
+defineLazyTimer('clearTimeout');
+defineLazyTimer('clearInterval');
+defineLazyTimer('clearImmediate');
+defineLazyTimer('requestAnimationFrame');
+defineLazyTimer('cancelAnimationFrame');
+defineLazyTimer('requestIdleCallback');
+defineLazyTimer('cancelIdleCallback');

Libraries/Core/setUpXHR.js

@@ -0,0 +1,32 @@
+/**
+ * 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.
+ *
+ * @flow strict-local
+ * @format
+ */
+'use strict';
+
+const {polyfillGlobal} = require('PolyfillFunctions');
+
+/**
+ * Set up XMLHttpRequest. The native XMLHttpRequest in Chrome dev tools is CORS
+ * aware and won't let you fetch anything from the internet.
+ *
+ * You can use this module directly, or just require InitializeCore.
+ */
+polyfillGlobal('XMLHttpRequest', () => require('XMLHttpRequest'));
+polyfillGlobal('FormData', () => require('FormData'));
+
+polyfillGlobal('fetch', () => require('fetch').fetch); // flowlint-line untyped-import:off
+polyfillGlobal('Headers', () => require('fetch').Headers); // flowlint-line untyped-import:off
+polyfillGlobal('Request', () => require('fetch').Request); // flowlint-line untyped-import:off
+polyfillGlobal('Response', () => require('fetch').Response); // flowlint-line untyped-import:off
+polyfillGlobal('WebSocket', () => require('WebSocket'));
+polyfillGlobal('Blob', () => require('Blob'));
+polyfillGlobal('File', () => require('File'));
+polyfillGlobal('FileReader', () => require('FileReader'));
+polyfillGlobal('URL', () => require('URL').URL); // flowlint-line untyped-import:off
+polyfillGlobal('URLSearchParams', () => require('URL').URLSearchParams); // flowlint-line untyped-import:off

Libraries/Core/Timers/JSTimers.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -12,7 +12,7 @@
const Platform = require('Platform');
const Systrace = require('Systrace');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
const {Timing} = require('NativeModules');
const BatchedBridge = require('BatchedBridge');
@@ -290,6 +290,9 @@
* @param {function} func Callback to be invoked before the end of the
* current JavaScript execution loop.
*/
+ /* $FlowFixMe(>=0.79.1 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.79 was deployed. To see the error delete this
+ * comment and run Flow. */
setImmediate: function(func: Function, ...args: any) {
const id = _allocateCallback(
() => func.apply(undefined, args),
@@ -302,6 +305,9 @@
/**
* @param {function} func Callback to be invoked every frame.
*/
+ /* $FlowFixMe(>=0.79.1 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.79 was deployed. To see the error delete this
+ * comment and run Flow. */
requestAnimationFrame: function(func: Function) {
const id = _allocateCallback(func, 'requestAnimationFrame');
Timing.createTimer(id, 1, Date.now(), /* recurring */ false);
@@ -313,6 +319,9 @@
* with time remaining in frame.
* @param {?object} options
*/
+ /* $FlowFixMe(>=0.79.1 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.79 was deployed. To see the error delete this
+ * comment and run Flow. */
requestIdleCallback: function(func: Function, options: ?Object) {
if (requestIdleCallbacks.length === 0) {
Timing.setSendIdleEvents(true);

Libraries/DeprecatedPropTypes/DeprecatedColorPropType.js

@@ -0,0 +1,76 @@
+/**
+ * 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
+ */
+
+'use strict';
+
+const normalizeColor = require('normalizeColor');
+
+const colorPropType = function(
+ isRequired,
+ props,
+ propName,
+ componentName,
+ location,
+ propFullName,
+) {
+ const color = props[propName];
+ if (color === undefined || color === null) {
+ if (isRequired) {
+ return new Error(
+ 'Required ' +
+ location +
+ ' `' +
+ (propFullName || propName) +
+ '` was not specified in `' +
+ componentName +
+ '`.',
+ );
+ }
+ return;
+ }
+
+ if (typeof color === 'number') {
+ // Developers should not use a number, but we are using the prop type
+ // both for user provided colors and for transformed ones. This isn't ideal
+ // and should be fixed but will do for now...
+ return;
+ }
+
+ if (normalizeColor(color) === null) {
+ return new Error(
+ 'Invalid ' +
+ location +
+ ' `' +
+ (propFullName || propName) +
+ '` supplied to `' +
+ componentName +
+ '`: ' +
+ color +
+ '\n' +
+ `Valid color formats are
+ - '#f0f' (#rgb)
+ - '#f0fc' (#rgba)
+ - '#ff00ff' (#rrggbb)
+ - '#ff00ff00' (#rrggbbaa)
+ - 'rgb(255, 255, 255)'
+ - 'rgba(255, 255, 255, 1.0)'
+ - 'hsl(360, 100%, 100%)'
+ - 'hsla(360, 100%, 100%, 1.0)'
+ - 'transparent'
+ - 'red'
+ - 0xff00ff00 (0xrrggbbaa)
+`,
+ );
+ }
+};
+
+const ColorPropType = colorPropType.bind(null, false /* isRequired */);
+ColorPropType.isRequired = colorPropType.bind(null, true /* isRequired */);
+
+module.exports = ColorPropType;

Libraries/DeprecatedPropTypes/deprecatedCreateStrictShapeTypeChecker.js

@@ -0,0 +1,86 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow
+ */
+
+'use strict';
+
+const invariant = require('invariant');
+const merge = require('merge');
+
+function deprecatedCreateStrictShapeTypeChecker(shapeTypes: {
+ [key: string]: ReactPropsCheckType,
+}): ReactPropsChainableTypeChecker {
+ function checkType(
+ isRequired,
+ props,
+ propName,
+ componentName,
+ location?,
+ ...rest
+ ) {
+ if (!props[propName]) {
+ if (isRequired) {
+ invariant(
+ false,
+ `Required object \`${propName}\` was not specified in ` +
+ `\`${componentName}\`.`,
+ );
+ }
+ return;
+ }
+ const propValue = props[propName];
+ const propType = typeof propValue;
+ const locationName = location || '(unknown)';
+ if (propType !== 'object') {
+ invariant(
+ false,
+ `Invalid ${locationName} \`${propName}\` of type \`${propType}\` ` +
+ `supplied to \`${componentName}\`, expected \`object\`.`,
+ );
+ }
+ // We need to check all keys in case some are required but missing from
+ // props.
+ const allKeys = merge(props[propName], shapeTypes);
+ for (const key in allKeys) {
+ const checker = shapeTypes[key];
+ if (!checker) {
+ invariant(
+ false,
+ `Invalid props.${propName} key \`${key}\` supplied to \`${componentName}\`.` +
+ '\nBad object: ' +
+ JSON.stringify(props[propName], null, ' ') +
+ '\nValid keys: ' +
+ JSON.stringify(Object.keys(shapeTypes), null, ' '),
+ );
+ }
+ const error = checker(propValue, key, componentName, location, ...rest);
+ if (error) {
+ invariant(
+ false,
+ error.message +
+ '\nBad object: ' +
+ JSON.stringify(props[propName], null, ' '),
+ );
+ }
+ }
+ }
+ function chainedCheckType(
+ props: {[key: string]: any},
+ propName: string,
+ componentName: string,
+ location?: string,
+ ...rest
+ ): ?Error {
+ return checkType(false, props, propName, componentName, location, ...rest);
+ }
+ chainedCheckType.isRequired = checkType.bind(null, true);
+ return chainedCheckType;
+}
+
+module.exports = deprecatedCreateStrictShapeTypeChecker;

Libraries/DeprecatedPropTypes/DeprecatedEdgeInsetsPropType.js

@@ -0,0 +1,22 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow strict
+ */
+
+'use strict';
+
+const PropTypes = require('prop-types');
+
+const DeprecatedEdgeInsetsPropType = PropTypes.shape({
+ top: PropTypes.number,
+ left: PropTypes.number,
+ bottom: PropTypes.number,
+ right: PropTypes.number,
+});
+
+module.exports = DeprecatedEdgeInsetsPropType;

Libraries/DeprecatedPropTypes/DeprecatedImagePropType.js

@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @flow
+ * @format
+ */
+
+'use strict';
+
+const DeprecatedEdgeInsetsPropType = require('DeprecatedEdgeInsetsPropType');
+const DeprecatedImageSourcePropType = require('DeprecatedImageSourcePropType');
+const DeprecatedImageStylePropTypes = require('DeprecatedImageStylePropTypes');
+const DeprecatedStyleSheetPropType = require('DeprecatedStyleSheetPropType');
+const PropTypes = require('prop-types');
+
+module.exports = {
+ style: DeprecatedStyleSheetPropType(DeprecatedImageStylePropTypes),
+ source: DeprecatedImageSourcePropType,
+ defaultSource: PropTypes.oneOfType([
+ PropTypes.shape({
+ uri: PropTypes.string,
+ width: PropTypes.number,
+ height: PropTypes.number,
+ scale: PropTypes.number,
+ }),
+ PropTypes.number,
+ ]),
+
+ accessible: PropTypes.bool,
+
+ accessibilityLabel: PropTypes.node,
+
+ blurRadius: PropTypes.number,
+
+ capInsets: DeprecatedEdgeInsetsPropType,
+
+ resizeMethod: PropTypes.oneOf(['auto', 'resize', 'scale']),
+
+ resizeMode: PropTypes.oneOf([
+ 'cover',
+ 'contain',
+ 'stretch',
+ 'repeat',
+ 'center',
+ ]),
+
+ testID: PropTypes.string,
+
+ onLayout: PropTypes.func,
+
+ onLoadStart: PropTypes.func,
+
+ onProgress: PropTypes.func,
+
+ onError: PropTypes.func,
+
+ onPartialLoad: PropTypes.func,
+
+ onLoad: PropTypes.func,
+
+ onLoadEnd: PropTypes.func,
+};

Libraries/DeprecatedPropTypes/DeprecatedImageSourcePropType.js

@@ -0,0 +1,39 @@
+/**
+ * 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.
+ *
+ * @no-flow
+ * @format
+ */
+'use strict';
+
+const PropTypes = require('prop-types');
+
+const ImageURISourcePropType = PropTypes.shape({
+ uri: PropTypes.string,
+ bundle: PropTypes.string,
+ method: PropTypes.string,
+ headers: PropTypes.objectOf(PropTypes.string),
+ body: PropTypes.string,
+ cache: PropTypes.oneOf([
+ 'default',
+ 'reload',
+ 'force-cache',
+ 'only-if-cached',
+ ]),
+ width: PropTypes.number,
+ height: PropTypes.number,
+ scale: PropTypes.number,
+});
+
+const ImageSourcePropType = PropTypes.oneOfType([
+ ImageURISourcePropType,
+ // Opaque type returned by require('./image.jpg')
+ PropTypes.number,
+ // Multiple sources
+ PropTypes.arrayOf(ImageURISourcePropType),
+]);
+
+module.exports = ImageSourcePropType;

Libraries/DeprecatedPropTypes/DeprecatedImageStylePropTypes.js

@@ -0,0 +1,67 @@
+/**
+ * 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.
+ *
+ * @flow
+ * @format
+ */
+'use strict';
+
+const DeprecatedColorPropType = require('DeprecatedColorPropType');
+const DeprecatedLayoutPropTypes = require('DeprecatedLayoutPropTypes');
+const ReactPropTypes = require('prop-types');
+const DeprecatedShadowPropTypesIOS = require('DeprecatedShadowPropTypesIOS');
+const DeprecatedTransformPropTypes = require('DeprecatedTransformPropTypes');
+
+const ImageStylePropTypes = {
+ ...DeprecatedLayoutPropTypes,
+ ...DeprecatedShadowPropTypesIOS,
+ ...DeprecatedTransformPropTypes,
+ resizeMode: ReactPropTypes.oneOf([
+ 'center',
+ 'contain',
+ 'cover',
+ 'repeat',
+ 'stretch',
+ ]),
+ backfaceVisibility: ReactPropTypes.oneOf(['visible', 'hidden']),
+ backgroundColor: DeprecatedColorPropType,
+ borderColor: DeprecatedColorPropType,
+ borderWidth: ReactPropTypes.number,
+ borderRadius: ReactPropTypes.number,
+ overflow: ReactPropTypes.oneOf(['visible', 'hidden']),
+
+ /**
+ * Changes the color of all the non-transparent pixels to the tintColor.
+ */
+ tintColor: DeprecatedColorPropType,
+ opacity: ReactPropTypes.number,
+ /**
+ * When the image has rounded corners, specifying an overlayColor will
+ * cause the remaining space in the corners to be filled with a solid color.
+ * This is useful in cases which are not supported by the Android
+ * implementation of rounded corners:
+ * - Certain resize modes, such as 'contain'
+ * - Animated GIFs
+ *
+ * A typical way to use this prop is with images displayed on a solid
+ * background and setting the `overlayColor` to the same color
+ * as the background.
+ *
+ * For details of how this works under the hood, see
+ * http://frescolib.org/docs/rounded-corners-and-circles.html
+ *
+ * @platform android
+ */
+ overlayColor: ReactPropTypes.string,
+
+ // Android-Specific styles
+ borderTopLeftRadius: ReactPropTypes.number,
+ borderTopRightRadius: ReactPropTypes.number,
+ borderBottomLeftRadius: ReactPropTypes.number,
+ borderBottomRightRadius: ReactPropTypes.number,
+};
+
+module.exports = ImageStylePropTypes;

Libraries/DeprecatedPropTypes/DeprecatedLayoutPropTypes.js

@@ -0,0 +1,190 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow strict
+ */
+
+'use strict';
+
+const ReactPropTypes = require('prop-types');
+
+const LayoutPropTypes = {
+ display: ReactPropTypes.oneOf(['none', 'flex']),
+ width: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ height: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ start: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ end: ReactPropTypes.oneOfType([ReactPropTypes.number, ReactPropTypes.string]),
+ top: ReactPropTypes.oneOfType([ReactPropTypes.number, ReactPropTypes.string]),
+ left: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ right: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ bottom: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ minWidth: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ maxWidth: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ minHeight: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ maxHeight: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ margin: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ marginVertical: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ marginHorizontal: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ marginTop: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ marginBottom: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ marginLeft: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ marginRight: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ marginStart: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ marginEnd: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ padding: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ paddingVertical: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ paddingHorizontal: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ paddingTop: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ paddingBottom: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ paddingLeft: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ paddingRight: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ paddingStart: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ paddingEnd: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ borderWidth: ReactPropTypes.number,
+ borderTopWidth: ReactPropTypes.number,
+ borderStartWidth: ReactPropTypes.number,
+ borderEndWidth: ReactPropTypes.number,
+ borderRightWidth: ReactPropTypes.number,
+ borderBottomWidth: ReactPropTypes.number,
+ borderLeftWidth: ReactPropTypes.number,
+ position: ReactPropTypes.oneOf(['absolute', 'relative']),
+ flexDirection: ReactPropTypes.oneOf([
+ 'row',
+ 'row-reverse',
+ 'column',
+ 'column-reverse',
+ ]),
+ flexWrap: ReactPropTypes.oneOf(['wrap', 'nowrap', 'wrap-reverse']),
+ justifyContent: ReactPropTypes.oneOf([
+ 'flex-start',
+ 'flex-end',
+ 'center',
+ 'space-between',
+ 'space-around',
+ 'space-evenly',
+ ]),
+ alignItems: ReactPropTypes.oneOf([
+ 'flex-start',
+ 'flex-end',
+ 'center',
+ 'stretch',
+ 'baseline',
+ ]),
+ alignSelf: ReactPropTypes.oneOf([
+ 'auto',
+ 'flex-start',
+ 'flex-end',
+ 'center',
+ 'stretch',
+ 'baseline',
+ ]),
+ alignContent: ReactPropTypes.oneOf([
+ 'flex-start',
+ 'flex-end',
+ 'center',
+ 'stretch',
+ 'space-between',
+ 'space-around',
+ ]),
+ overflow: ReactPropTypes.oneOf(['visible', 'hidden', 'scroll']),
+ flex: ReactPropTypes.number,
+ flexGrow: ReactPropTypes.number,
+ flexShrink: ReactPropTypes.number,
+ flexBasis: ReactPropTypes.oneOfType([
+ ReactPropTypes.number,
+ ReactPropTypes.string,
+ ]),
+ aspectRatio: ReactPropTypes.number,
+ zIndex: ReactPropTypes.number,
+ direction: ReactPropTypes.oneOf(['inherit', 'ltr', 'rtl']),
+};
+
+module.exports = LayoutPropTypes;

Libraries/DeprecatedPropTypes/DeprecatedPointPropType.js

@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow strict
+ */
+
+'use strict';
+
+const PropTypes = require('prop-types');
+
+const PointPropType = PropTypes.shape({
+ x: PropTypes.number,
+ y: PropTypes.number,
+});
+
+module.exports = PointPropType;

Libraries/DeprecatedPropTypes/DeprecatedShadowPropTypesIOS.js

@@ -0,0 +1,25 @@
+/**
+ * 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.
+ *
+ * @flow
+ * @format
+ */
+'use strict';
+
+const DeprecatedColorPropType = require('DeprecatedColorPropType');
+const ReactPropTypes = require('prop-types');
+
+const DeprecatedShadowPropTypesIOS = {
+ shadowColor: DeprecatedColorPropType,
+ shadowOffset: ReactPropTypes.shape({
+ width: ReactPropTypes.number,
+ height: ReactPropTypes.number,
+ }),
+ shadowOpacity: ReactPropTypes.number,
+ shadowRadius: ReactPropTypes.number,
+};
+
+module.exports = DeprecatedShadowPropTypesIOS;

Libraries/DeprecatedPropTypes/DeprecatedStyleSheetPropType.js

@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow strict-local
+ */
+
+'use strict';
+
+const deprecatedCreateStrictShapeTypeChecker = require('deprecatedCreateStrictShapeTypeChecker');
+const flattenStyle = require('flattenStyle');
+
+function DeprecatedStyleSheetPropType(shape: {
+ [key: string]: ReactPropsCheckType,
+}): ReactPropsCheckType {
+ const shapePropType = deprecatedCreateStrictShapeTypeChecker(shape);
+ return function(props, propName, componentName, location?, ...rest) {
+ let newProps = props;
+ if (props[propName]) {
+ // Just make a dummy prop object with only the flattened style
+ newProps = {};
+ newProps[propName] = flattenStyle(props[propName]);
+ }
+ return shapePropType(newProps, propName, componentName, location, ...rest);
+ };
+}
+
+module.exports = DeprecatedStyleSheetPropType;

Libraries/DeprecatedPropTypes/DeprecatedTextPropTypes.js

@@ -0,0 +1,41 @@
+/**
+ * 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.
+ *
+ * @flow
+ * @format
+ */
+
+'use strict';
+
+const DeprecatedColorPropType = require('DeprecatedColorPropType');
+const DeprecatedEdgeInsetsPropType = require('DeprecatedEdgeInsetsPropType');
+const DeprecatedStyleSheetPropType = require('DeprecatedStyleSheetPropType');
+const PropTypes = require('prop-types');
+const TextStylePropTypes = require('TextStylePropTypes');
+
+const stylePropType = DeprecatedStyleSheetPropType(TextStylePropTypes);
+
+module.exports = {
+ ellipsizeMode: PropTypes.oneOf(['head', 'middle', 'tail', 'clip']),
+ numberOfLines: PropTypes.number,
+ textBreakStrategy: PropTypes.oneOf(['simple', 'highQuality', 'balanced']),
+ onLayout: PropTypes.func,
+ onPress: PropTypes.func,
+ onLongPress: PropTypes.func,
+ pressRetentionOffset: DeprecatedEdgeInsetsPropType,
+ selectable: PropTypes.bool,
+ selectionColor: DeprecatedColorPropType,
+ suppressHighlighting: PropTypes.bool,
+ style: stylePropType,
+ testID: PropTypes.string,
+ nativeID: PropTypes.string,
+ allowFontScaling: PropTypes.bool,
+ maxFontSizeMultiplier: PropTypes.number,
+ accessible: PropTypes.bool,
+ adjustsFontSizeToFit: PropTypes.bool,
+ minimumFontScale: PropTypes.number,
+ disabled: PropTypes.bool,
+};

Libraries/DeprecatedPropTypes/DeprecatedTransformPropTypes.js

@@ -0,0 +1,84 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow
+ */
+
+'use strict';
+
+const ReactPropTypes = require('prop-types');
+
+const deprecatedPropType = require('deprecatedPropType');
+
+const TransformMatrixPropType = function(
+ props: Object,
+ propName: string,
+ componentName: string,
+): ?Error {
+ if (props[propName]) {
+ return new Error(
+ 'The transformMatrix style property is deprecated. ' +
+ 'Use `transform: [{ matrix: ... }]` instead.',
+ );
+ }
+};
+
+const DecomposedMatrixPropType = function(
+ props: Object,
+ propName: string,
+ componentName: string,
+): ?Error {
+ if (props[propName]) {
+ return new Error(
+ 'The decomposedMatrix style property is deprecated. ' +
+ 'Use `transform: [...]` instead.',
+ );
+ }
+};
+
+const DeprecatedTransformPropTypes = {
+ transform: ReactPropTypes.arrayOf(
+ ReactPropTypes.oneOfType([
+ ReactPropTypes.shape({perspective: ReactPropTypes.number}),
+ ReactPropTypes.shape({rotate: ReactPropTypes.string}),
+ ReactPropTypes.shape({rotateX: ReactPropTypes.string}),
+ ReactPropTypes.shape({rotateY: ReactPropTypes.string}),
+ ReactPropTypes.shape({rotateZ: ReactPropTypes.string}),
+ ReactPropTypes.shape({scale: ReactPropTypes.number}),
+ ReactPropTypes.shape({scaleX: ReactPropTypes.number}),
+ ReactPropTypes.shape({scaleY: ReactPropTypes.number}),
+ ReactPropTypes.shape({translateX: ReactPropTypes.number}),
+ ReactPropTypes.shape({translateY: ReactPropTypes.number}),
+ ReactPropTypes.shape({skewX: ReactPropTypes.string}),
+ ReactPropTypes.shape({skewY: ReactPropTypes.string}),
+ ]),
+ ),
+ transformMatrix: TransformMatrixPropType,
+ decomposedMatrix: DecomposedMatrixPropType,
+ scaleX: deprecatedPropType(
+ ReactPropTypes.number,
+ 'Use the transform prop instead.',
+ ),
+ scaleY: deprecatedPropType(
+ ReactPropTypes.number,
+ 'Use the transform prop instead.',
+ ),
+ rotation: deprecatedPropType(
+ ReactPropTypes.number,
+ 'Use the transform prop instead.',
+ ),
+ translateX: deprecatedPropType(
+ ReactPropTypes.number,
+ 'Use the transform prop instead.',
+ ),
+ translateY: deprecatedPropType(
+ ReactPropTypes.number,
+ 'Use the transform prop instead.',
+ ),
+};
+
+module.exports = DeprecatedTransformPropTypes;

Libraries/DeprecatedPropTypes/DeprecatedTVViewPropTypes.js

@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow
+ */
+
+'use strict';
+
+const PropTypes = require('prop-types');
+
+const DeprecatedTVViewPropTypes = {
+ isTVSelectable: PropTypes.bool,
+ hasTVPreferredFocus: PropTypes.bool,
+ tvParallaxProperties: PropTypes.object,
+ tvParallaxShiftDistanceX: PropTypes.number,
+ tvParallaxShiftDistanceY: PropTypes.number,
+ tvParallaxTiltAngle: PropTypes.number,
+ tvParallaxMagnification: PropTypes.number,
+};
+
+module.exports = DeprecatedTVViewPropTypes;

Libraries/DeprecatedPropTypes/DeprecatedViewAccessibility.js

@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow strict
+ */
+
+'use strict';
+
+module.exports = {
+ DeprecatedAccessibilityTraits: [
+ 'none',
+ 'button',
+ 'link',
+ 'header',
+ 'search',
+ 'image',
+ 'selected',
+ 'plays',
+ 'key',
+ 'text',
+ 'summary',
+ 'disabled',
+ 'frequentUpdates',
+ 'startsMedia',
+ 'adjustable',
+ 'allowsDirectInteraction',
+ 'pageTurn',
+ ],
+ DeprecatedAccessibilityComponentTypes: [
+ 'none',
+ 'button',
+ 'radiobutton_checked',
+ 'radiobutton_unchecked',
+ ],
+ // This must be kept in sync with the AccessibilityRolesMask in RCTViewManager.m
+ DeprecatedAccessibilityRoles: [
+ 'none',
+ 'button',
+ 'link',
+ 'search',
+ 'image',
+ 'keyboardkey',
+ 'text',
+ 'adjustable',
+ 'imagebutton',
+ 'header',
+ 'summary',
+ ],
+ // This must be kept in sync with the AccessibilityStatesMask in RCTViewManager.m
+ DeprecatedAccessibilityStates: ['selected', 'disabled'],
+};

Libraries/DeprecatedPropTypes/DeprecatedViewPropTypes.js

@@ -0,0 +1,409 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow
+ */
+
+'use strict';
+
+const DeprecatedEdgeInsetsPropType = require('DeprecatedEdgeInsetsPropType');
+const PlatformViewPropTypes = require('PlatformViewPropTypes');
+const PropTypes = require('prop-types');
+const DeprecatedStyleSheetPropType = require('DeprecatedStyleSheetPropType');
+const DeprecatedViewStylePropTypes = require('DeprecatedViewStylePropTypes');
+
+const {
+ DeprecatedAccessibilityComponentTypes,
+ DeprecatedAccessibilityTraits,
+ DeprecatedAccessibilityRoles,
+ DeprecatedAccessibilityStates,
+} = require('DeprecatedViewAccessibility');
+
+const stylePropType = DeprecatedStyleSheetPropType(
+ DeprecatedViewStylePropTypes,
+);
+
+module.exports = {
+ /**
+ * When `true`, indicates that the view is an accessibility element.
+ * By default, all the touchable elements are accessible.
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#accessible
+ */
+ accessible: PropTypes.bool,
+
+ /**
+ * Overrides the text that's read by the screen reader when the user interacts
+ * with the element. By default, the label is constructed by traversing all
+ * the children and accumulating all the `Text` nodes separated by space.
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#accessibilitylabel
+ */
+ accessibilityLabel: PropTypes.node,
+
+ /**
+ * An accessibility hint helps users understand what will happen when they perform
+ * an action on the accessibility element when that result is not obvious from the
+ * accessibility label.
+ *
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#accessibilityHint
+ */
+ accessibilityHint: PropTypes.string,
+
+ /**
+ * Provides an array of custom actions available for accessibility.
+ *
+ * @platform ios
+ */
+ accessibilityActions: PropTypes.arrayOf(PropTypes.string),
+
+ /**
+ * Prevents view from being inverted if set to true and color inversion is turned on.
+ *
+ * @platform ios
+ */
+ accessibilityIgnoresInvertColors: PropTypes.bool,
+
+ /**
+ * Indicates to accessibility services to treat UI component like a
+ * native one. Works for Android only.
+ *
+ * @platform android
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#accessibilitycomponenttype
+ */
+ accessibilityComponentType: PropTypes.oneOf(
+ DeprecatedAccessibilityComponentTypes,
+ ),
+
+ /**
+ * Indicates to accessibility services to treat UI component like a specific role.
+ */
+ accessibilityRole: PropTypes.oneOf(DeprecatedAccessibilityRoles),
+
+ /**
+ * Indicates to accessibility services that UI Component is in a specific State.
+ */
+ accessibilityStates: PropTypes.arrayOf(
+ PropTypes.oneOf(DeprecatedAccessibilityStates),
+ ),
+ /**
+ * Indicates to accessibility services whether the user should be notified
+ * when this view changes. Works for Android API >= 19 only.
+ *
+ * @platform android
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#accessibilityliveregion
+ */
+ accessibilityLiveRegion: PropTypes.oneOf(['none', 'polite', 'assertive']),
+
+ /**
+ * Controls how view is important for accessibility which is if it
+ * fires accessibility events and if it is reported to accessibility services
+ * that query the screen. Works for Android only.
+ *
+ * @platform android
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#importantforaccessibility
+ */
+ importantForAccessibility: PropTypes.oneOf([
+ 'auto',
+ 'yes',
+ 'no',
+ 'no-hide-descendants',
+ ]),
+
+ /**
+ * Provides additional traits to screen reader. By default no traits are
+ * provided unless specified otherwise in element.
+ *
+ * You can provide one trait or an array of many traits.
+ *
+ * @platform ios
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#accessibilitytraits
+ */
+ accessibilityTraits: PropTypes.oneOfType([
+ PropTypes.oneOf(DeprecatedAccessibilityTraits),
+ PropTypes.arrayOf(PropTypes.oneOf(DeprecatedAccessibilityTraits)),
+ ]),
+
+ /**
+ * A value indicating whether VoiceOver should ignore the elements
+ * within views that are siblings of the receiver.
+ * Default is `false`.
+ *
+ * @platform ios
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#accessibilityviewismodal
+ */
+ accessibilityViewIsModal: PropTypes.bool,
+
+ /**
+ * A value indicating whether the accessibility elements contained within
+ * this accessibility element are hidden.
+ *
+ * @platform ios
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#accessibilityElementsHidden
+ */
+ accessibilityElementsHidden: PropTypes.bool,
+
+ /**
+ * When `accessible` is true, the system will try to invoke this function
+ * when the user performs an accessibility custom action.
+ *
+ * @platform ios
+ */
+ onAccessibilityAction: PropTypes.func,
+
+ /**
+ * When `accessible` is true, the system will try to invoke this function
+ * when the user performs accessibility tap gesture.
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#onaccessibilitytap
+ */
+ onAccessibilityTap: PropTypes.func,
+
+ /**
+ * When `accessible` is `true`, the system will invoke this function when the
+ * user performs the magic tap gesture.
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#onmagictap
+ */
+ onMagicTap: PropTypes.func,
+
+ /**
+ * Used to locate this view in end-to-end tests.
+ *
+ * > This disables the 'layout-only view removal' optimization for this view!
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#testid
+ */
+ testID: PropTypes.string,
+
+ /**
+ * Used to locate this view from native classes.
+ *
+ * > This disables the 'layout-only view removal' optimization for this view!
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#nativeid
+ */
+ nativeID: PropTypes.string,
+
+ /**
+ * For most touch interactions, you'll simply want to wrap your component in
+ * `TouchableHighlight` or `TouchableOpacity`. Check out `Touchable.js`,
+ * `ScrollResponder.js` and `ResponderEventPlugin.js` for more discussion.
+ */
+
+ /**
+ * The View is now responding for touch events. This is the time to highlight
+ * and show the user what is happening.
+ *
+ * `View.props.onResponderGrant: (event) => {}`, where `event` is a synthetic
+ * touch event as described above.
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#onrespondergrant
+ */
+ onResponderGrant: PropTypes.func,
+
+ /**
+ * The user is moving their finger.
+ *
+ * `View.props.onResponderMove: (event) => {}`, where `event` is a synthetic
+ * touch event as described above.
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#onrespondermove
+ */
+ onResponderMove: PropTypes.func,
+
+ /**
+ * Another responder is already active and will not release it to that `View`
+ * asking to be the responder.
+ *
+ * `View.props.onResponderReject: (event) => {}`, where `event` is a
+ * synthetic touch event as described above.
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#onresponderreject
+ */
+ onResponderReject: PropTypes.func,
+
+ /**
+ * Fired at the end of the touch.
+ *
+ * `View.props.onResponderRelease: (event) => {}`, where `event` is a
+ * synthetic touch event as described above.
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#onresponderrelease
+ */
+ onResponderRelease: PropTypes.func,
+
+ /**
+ * The responder has been taken from the `View`. Might be taken by other
+ * views after a call to `onResponderTerminationRequest`, or might be taken
+ * by the OS without asking (e.g., happens with control center/ notification
+ * center on iOS)
+ *
+ * `View.props.onResponderTerminate: (event) => {}`, where `event` is a
+ * synthetic touch event as described above.
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#onresponderterminate
+ */
+ onResponderTerminate: PropTypes.func,
+
+ /**
+ * Some other `View` wants to become responder and is asking this `View` to
+ * release its responder. Returning `true` allows its release.
+ *
+ * `View.props.onResponderTerminationRequest: (event) => {}`, where `event`
+ * is a synthetic touch event as described above.
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#onresponderterminationrequest
+ */
+ onResponderTerminationRequest: PropTypes.func,
+
+ /**
+ * Does this view want to become responder on the start of a touch?
+ *
+ * `View.props.onStartShouldSetResponder: (event) => [true | false]`, where
+ * `event` is a synthetic touch event as described above.
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#onstartshouldsetresponder
+ */
+ onStartShouldSetResponder: PropTypes.func,
+
+ /**
+ * If a parent `View` wants to prevent a child `View` from becoming responder
+ * on a touch start, it should have this handler which returns `true`.
+ *
+ * `View.props.onStartShouldSetResponderCapture: (event) => [true | false]`,
+ * where `event` is a synthetic touch event as described above.
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#onstartshouldsetrespondercapture
+ */
+ onStartShouldSetResponderCapture: PropTypes.func,
+
+ /**
+ * Does this view want to "claim" touch responsiveness? This is called for
+ * every touch move on the `View` when it is not the responder.
+ *
+ * `View.props.onMoveShouldSetResponder: (event) => [true | false]`, where
+ * `event` is a synthetic touch event as described above.
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#onmoveshouldsetresponder
+ */
+ onMoveShouldSetResponder: PropTypes.func,
+
+ /**
+ * If a parent `View` wants to prevent a child `View` from becoming responder
+ * on a move, it should have this handler which returns `true`.
+ *
+ * `View.props.onMoveShouldSetResponderCapture: (event) => [true | false]`,
+ * where `event` is a synthetic touch event as described above.
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#onMoveShouldsetrespondercapture
+ */
+ onMoveShouldSetResponderCapture: PropTypes.func,
+
+ /**
+ * This defines how far a touch event can start away from the view.
+ * Typical interface guidelines recommend touch targets that are at least
+ * 30 - 40 points/density-independent pixels.
+ *
+ * > The touch area never extends past the parent view bounds and the Z-index
+ * > of sibling views always takes precedence if a touch hits two overlapping
+ * > views.
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#hitslop
+ */
+ hitSlop: DeprecatedEdgeInsetsPropType,
+
+ /**
+ * Invoked on mount and layout changes with:
+ *
+ * `{nativeEvent: { layout: {x, y, width, height}}}`
+ *
+ * This event is fired immediately once the layout has been calculated, but
+ * the new layout may not yet be reflected on the screen at the time the
+ * event is received, especially if a layout animation is in progress.
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#onlayout
+ */
+ onLayout: PropTypes.func,
+
+ /**
+ * Controls whether the `View` can be the target of touch events.
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#pointerevents
+ */
+ pointerEvents: PropTypes.oneOf(['box-none', 'none', 'box-only', 'auto']),
+
+ /**
+ * See http://facebook.github.io/react-native/docs/style.html
+ */
+ style: stylePropType,
+
+ /**
+ * This is a special performance property exposed by `RCTView` and is useful
+ * for scrolling content when there are many subviews, most of which are
+ * offscreen. For this property to be effective, it must be applied to a
+ * view that contains many subviews that extend outside its bound. The
+ * subviews must also have `overflow: hidden`, as should the containing view
+ * (or one of its superviews).
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#removeclippedsubviews
+ */
+ removeClippedSubviews: PropTypes.bool,
+
+ /**
+ * Whether this `View` should render itself (and all of its children) into a
+ * single hardware texture on the GPU.
+ *
+ * @platform android
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#rendertohardwaretextureandroid
+ */
+ renderToHardwareTextureAndroid: PropTypes.bool,
+
+ /**
+ * Whether this `View` should be rendered as a bitmap before compositing.
+ *
+ * @platform ios
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#shouldrasterizeios
+ */
+ shouldRasterizeIOS: PropTypes.bool,
+
+ /**
+ * Views that are only used to layout their children or otherwise don't draw
+ * anything may be automatically removed from the native hierarchy as an
+ * optimization. Set this property to `false` to disable this optimization and
+ * ensure that this `View` exists in the native view hierarchy.
+ *
+ * @platform android
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#collapsable
+ */
+ collapsable: PropTypes.bool,
+
+ /**
+ * Whether this `View` needs to rendered offscreen and composited with an
+ * alpha in order to preserve 100% correct colors and blending behavior.
+ *
+ * @platform android
+ *
+ * See http://facebook.github.io/react-native/docs/view.html#needsoffscreenalphacompositing
+ */
+ needsOffscreenAlphaCompositing: PropTypes.bool,
+
+ /**
+ * Any additional platform-specific view prop types, or prop type overrides.
+ */
+ ...PlatformViewPropTypes,
+};

Libraries/DeprecatedPropTypes/DeprecatedViewStylePropTypes.js

@@ -0,0 +1,61 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow
+ */
+
+'use strict';
+
+const DeprecatedColorPropType = require('DeprecatedColorPropType');
+const DeprecatedLayoutPropTypes = require('DeprecatedLayoutPropTypes');
+const ReactPropTypes = require('prop-types');
+const DeprecatedShadowPropTypesIOS = require('DeprecatedShadowPropTypesIOS');
+const DeprecatedTransformPropTypes = require('DeprecatedTransformPropTypes');
+
+/**
+ * Warning: Some of these properties may not be supported in all releases.
+ */
+const DeprecatedViewStylePropTypes = {
+ ...DeprecatedLayoutPropTypes,
+ ...DeprecatedShadowPropTypesIOS,
+ ...DeprecatedTransformPropTypes,
+ backfaceVisibility: ReactPropTypes.oneOf(['visible', 'hidden']),
+ backgroundColor: DeprecatedColorPropType,
+ borderColor: DeprecatedColorPropType,
+ borderTopColor: DeprecatedColorPropType,
+ borderRightColor: DeprecatedColorPropType,
+ borderBottomColor: DeprecatedColorPropType,
+ borderLeftColor: DeprecatedColorPropType,
+ borderStartColor: DeprecatedColorPropType,
+ borderEndColor: DeprecatedColorPropType,
+ borderRadius: ReactPropTypes.number,
+ borderTopLeftRadius: ReactPropTypes.number,
+ borderTopRightRadius: ReactPropTypes.number,
+ borderTopStartRadius: ReactPropTypes.number,
+ borderTopEndRadius: ReactPropTypes.number,
+ borderBottomLeftRadius: ReactPropTypes.number,
+ borderBottomRightRadius: ReactPropTypes.number,
+ borderBottomStartRadius: ReactPropTypes.number,
+ borderBottomEndRadius: ReactPropTypes.number,
+ borderStyle: ReactPropTypes.oneOf(['solid', 'dotted', 'dashed']),
+ borderWidth: ReactPropTypes.number,
+ borderTopWidth: ReactPropTypes.number,
+ borderRightWidth: ReactPropTypes.number,
+ borderBottomWidth: ReactPropTypes.number,
+ borderLeftWidth: ReactPropTypes.number,
+ opacity: ReactPropTypes.number,
+ /**
+ * (Android-only) Sets the elevation of a view, using Android's underlying
+ * [elevation API](https://developer.android.com/training/material/shadows-clipping.html#Elevation).
+ * This adds a drop shadow to the item and affects z-order for overlapping views.
+ * Only supported on Android 5.0+, has no effect on earlier versions.
+ * @platform android
+ */
+ elevation: ReactPropTypes.number,
+};
+
+module.exports = DeprecatedViewStylePropTypes;

Libraries/EventEmitter/MissingNativeEventEmitterShim.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -13,7 +13,7 @@
const EmitterSubscription = require('EmitterSubscription');
const EventEmitter = require('EventEmitter');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
class MissingNativeEventEmitterShim extends EventEmitter {
isAvailable: boolean = false;

Libraries/EventEmitter/__mocks__/NativeEventEmitter.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/EventEmitter/NativeEventEmitter.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -14,7 +14,7 @@
const Platform = require('Platform');
const RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
import type EmitterSubscription from 'EmitterSubscription';

Libraries/EventEmitter/RCTDeviceEventEmitter.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/EventEmitter/RCTEventEmitter.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/EventEmitter/RCTNativeAppEventEmitter.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Experimental/IncrementalExample.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Experimental/IncrementalGroup.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Experimental/Incremental.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -90,10 +90,7 @@
* Tags instances and associated tasks for easier debugging.
*/
name: string,
- children?: any,
-};
-type DefaultProps = {
- name: string,
+ children: React.Node,
};
type State = {
doIncrementalRender: boolean,

Libraries/Experimental/IncrementalPresenter.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,13 +11,13 @@
'use strict';
const IncrementalGroup = require('IncrementalGroup');
-const React = require('React');
const PropTypes = require('prop-types');
+const React = require('React');
const View = require('View');
-const ViewPropTypes = require('ViewPropTypes');
-
import type {Context} from 'Incremental';
+import type {ViewStyleProp} from 'StyleSheet';
+import type {LayoutEvent} from 'CoreEventTypes';
/**
* WARNING: EXPERIMENTAL. Breaking changes will probably happen a lot and will
@@ -31,25 +31,19 @@
*
* See Incremental.js for more info.
*/
-type Props = {
+type Props = $ReadOnly<{|
name: string,
disabled?: boolean,
- onDone?: () => void,
- onLayout?: (event: Object) => void,
- style?: mixed,
- children?: any,
-};
+ onDone?: () => mixed,
+ onLayout?: (event: LayoutEvent) => mixed,
+ style?: ViewStyleProp,
+ children?: React.Node,
+|}>;
+
class IncrementalPresenter extends React.Component<Props> {
context: Context;
_isDone: boolean;
- static propTypes = {
- name: PropTypes.string,
- disabled: PropTypes.bool,
- onDone: PropTypes.func,
- onLayout: PropTypes.func,
- style: ViewPropTypes.style,
- };
static contextTypes = {
incrementalGroup: PropTypes.object,
incrementalGroupEnabled: PropTypes.bool,
@@ -74,14 +68,15 @@
this.props.onDone && this.props.onDone();
}
render() {
+ let style: ViewStyleProp;
if (
this.props.disabled !== true &&
this.context.incrementalGroupEnabled !== false &&
!this._isDone
) {
- var style = [this.props.style, {opacity: 0, position: 'absolute'}];
+ style = [this.props.style, {opacity: 0, position: 'absolute'}];
} else {
- var style = this.props.style;
+ style = this.props.style;
}
return (
<IncrementalGroup

Libraries/Experimental/SwipeableRow/SwipeableFlatList.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -12,28 +12,35 @@
import type {Props as FlatListProps} from 'FlatList';
import type {renderItemType} from 'VirtualizedList';
-const PropTypes = require('prop-types');
const React = require('React');
const SwipeableRow = require('SwipeableRow');
const FlatList = require('FlatList');
+// TODO: Make this $ReadOnly and Exact. Will require doing the same to the props in
+// Libraries/Lists/*
type SwipableListProps = {
/**
* To alert the user that swiping is possible, the first row can bounce
* on component mount.
*/
bounceFirstRowOnMount: boolean,
- // Maximum distance to open to after a swipe
+
+ /**
+ * Maximum distance to open to after a swipe
+ */
maxSwipeDistance: number | (Object => number),
- // Callback method to render the view that will be unveiled on swipe
+
+ /**
+ * Callback method to render the view that will be unveiled on swipe
+ */
renderQuickActions: renderItemType,
};
type Props<ItemT> = SwipableListProps & FlatListProps<ItemT>;
-type State = {
+type State = {|
openRowKey: ?string,
-};
+|};
/**
* A container component that renders multiple SwipeableRow's in a FlatList
@@ -53,29 +60,9 @@
*/
class SwipeableFlatList<ItemT> extends React.Component<Props<ItemT>, State> {
- props: Props<ItemT>;
- state: State;
-
_flatListRef: ?FlatList<ItemT> = null;
_shouldBounceFirstRowOnMount: boolean = false;
- static propTypes = {
- ...FlatList.propTypes,
-
- /**
- * To alert the user that swiping is possible, the first row can bounce
- * on component mount.
- */
- bounceFirstRowOnMount: PropTypes.bool.isRequired,
-
- // Maximum distance to open to after a swipe
- maxSwipeDistance: PropTypes.oneOfType([PropTypes.number, PropTypes.func])
- .isRequired,
-
- // Callback method to render the view that will be unveiled on swipe
- renderQuickActions: PropTypes.func.isRequired,
- };
-
static defaultProps = {
...FlatList.defaultProps,
bounceFirstRowOnMount: true,

Libraries/Experimental/SwipeableRow/SwipeableListViewDataSource.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Experimental/SwipeableRow/SwipeableListView.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,30 +11,53 @@
'use strict';
const ListView = require('ListView');
-const PropTypes = require('prop-types');
const React = require('React');
const SwipeableListViewDataSource = require('SwipeableListViewDataSource');
const SwipeableRow = require('SwipeableRow');
-type DefaultProps = {
- bounceFirstRowOnMount: boolean,
- renderQuickActions: Function,
-};
+type ListViewProps = React.ElementConfig<typeof ListView>;
+
+type Props = $ReadOnly<{|
+ ...ListViewProps,
-type Props = {
+ /**
+ * To alert the user that swiping is possible, the first row can bounce
+ * on component mount.
+ */
bounceFirstRowOnMount: boolean,
+ /**
+ * Use `SwipeableListView.getNewDataSource()` to get a data source to use,
+ * then use it just like you would a normal ListView data source
+ */
dataSource: SwipeableListViewDataSource,
+ /**
+ * Maximum distance to open to after a swipe
+ */
maxSwipeDistance:
| number
- | ((rowData: any, sectionID: string, rowID: string) => number),
+ | ((rowData: Object, sectionID: string, rowID: string) => number),
onScroll?: ?Function,
- renderRow: Function,
- renderQuickActions: Function,
-};
+ /**
+ * Callback method to render the swipeable view
+ */
+ renderRow: (
+ rowData: Object,
+ sectionID: string,
+ rowID: string,
+ ) => React.Element<any>,
+ /**
+ * Callback method to render the view that will be unveiled on swipe
+ */
+ renderQuickActions: (
+ rowData: Object,
+ sectionID: string,
+ rowID: string,
+ ) => ?React.Element<any>,
+|}>;
-type State = {
+type State = {|
dataSource: Object,
-};
+|};
/**
* A container component that renders multiple SwipeableRow's in a ListView
@@ -70,26 +93,6 @@
});
}
- static propTypes = {
- /**
- * To alert the user that swiping is possible, the first row can bounce
- * on component mount.
- */
- bounceFirstRowOnMount: PropTypes.bool.isRequired,
- /**
- * Use `SwipeableListView.getNewDataSource()` to get a data source to use,
- * then use it just like you would a normal ListView data source
- */
- dataSource: PropTypes.instanceOf(SwipeableListViewDataSource).isRequired,
- // Maximum distance to open to after a swipe
- maxSwipeDistance: PropTypes.oneOfType([PropTypes.number, PropTypes.func])
- .isRequired,
- // Callback method to render the swipeable view
- renderRow: PropTypes.func.isRequired,
- // Callback method to render the view that will be unveiled on swipe
- renderQuickActions: PropTypes.func.isRequired,
- };
-
static defaultProps = {
bounceFirstRowOnMount: false,
renderQuickActions: () => null,

Libraries/Experimental/SwipeableRow/SwipeableQuickActionButton.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,12 +10,12 @@
'use strict';
+const DeprecatedViewPropTypes = require('DeprecatedViewPropTypes');
const Image = require('Image');
const React = require('React');
const Text = require('Text');
const TouchableHighlight = require('TouchableHighlight');
const View = require('View');
-const ViewPropTypes = require('ViewPropTypes');
import type {ImageSource} from 'ImageSource';
@@ -27,13 +27,26 @@
class SwipeableQuickActionButton extends React.Component<{
accessibilityLabel?: string,
imageSource?: ?(ImageSource | number),
- imageStyle?: ?ViewPropTypes.style,
+ /* $FlowFixMe(>=0.82.0 site=react_native_fb) This comment suppresses an error
+ * found when Flow v0.82 was deployed. To see the error delete this comment
+ * and run Flow. */
+ imageStyle?: ?DeprecatedViewPropTypes.style,
mainView?: ?React.Node,
onPress?: Function,
- style?: ?ViewPropTypes.style,
+ /* $FlowFixMe(>=0.82.0 site=react_native_fb) This comment suppresses an error
+ * found when Flow v0.82 was deployed. To see the error delete this comment
+ * and run Flow. */
+ style?: ?DeprecatedViewPropTypes.style,
+ /* $FlowFixMe(>=0.82.0 site=react_native_fb) This comment suppresses an error
+ * found when Flow v0.82 was deployed. To see the error delete this comment
+ * and run Flow. */
+ containerStyle?: ?DeprecatedViewPropTypes.style,
testID?: string,
text?: ?(string | Object | Array<string | Object>),
- textStyle?: ?ViewPropTypes.style,
+ /* $FlowFixMe(>=0.82.0 site=react_native_fb) This comment suppresses an error
+ * found when Flow v0.82 was deployed. To see the error delete this comment
+ * and run Flow. */
+ textStyle?: ?DeprecatedViewPropTypes.style,
}> {
render(): React.Node {
if (!this.props.imageSource && !this.props.text && !this.props.mainView) {
@@ -55,8 +68,9 @@
<TouchableHighlight
onPress={this.props.onPress}
testID={this.props.testID}
- underlayColor="transparent">
- <View style={this.props.style}>{mainView}</View>
+ underlayColor="transparent"
+ style={this.props.containerStyle}>
+ {mainView}
</TouchableHighlight>
);
}

Libraries/Experimental/SwipeableRow/SwipeableQuickActions.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -14,7 +14,12 @@
const StyleSheet = require('StyleSheet');
const View = require('View');
-const ViewPropTypes = require('ViewPropTypes');
+import type {ViewStyleProp} from 'StyleSheet';
+
+type Props = $ReadOnly<{|
+ style?: ?ViewStyleProp,
+ children: React.Node,
+|}>;
/**
* A thin wrapper around standard quick action buttons that can, if the user
@@ -26,13 +31,8 @@
* <SwipeableQuickActionButton {..props} />
* </SwipeableQuickActions>
*/
-class SwipeableQuickActions extends React.Component<{style?: $FlowFixMe}> {
- static propTypes = {
- style: ViewPropTypes.style,
- };
-
+class SwipeableQuickActions extends React.Component<Props> {
render(): React.Node {
- // $FlowFixMe found when converting React.createClass to ES6
const children = this.props.children;
let buttons = [];
@@ -41,8 +41,7 @@
for (let i = 0; i < children.length; i++) {
buttons.push(children[i]);
- // $FlowFixMe found when converting React.createClass to ES6
- if (i < this.props.children.length - 1) {
+ if (i < children.length - 1) {
// Not last button
buttons.push(<View key={i} style={styles.divider} />);
}

Libraries/Experimental/SwipeableRow/SwipeableRow.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -14,16 +14,11 @@
const I18nManager = require('I18nManager');
const PanResponder = require('PanResponder');
const React = require('React');
-const PropTypes = require('prop-types');
const StyleSheet = require('StyleSheet');
-/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
- * found when Flow v0.54 was deployed. To see the error delete this comment and
- * run Flow. */
-const TimerMixin = require('react-timer-mixin');
const View = require('View');
-const createReactClass = require('create-react-class');
-const emptyFunction = require('fbjs/lib/emptyFunction');
+import type {LayoutEvent, PressEvent} from 'CoreEventTypes';
+import type {GestureState} from 'PanResponder';
const IS_RTL = I18nManager.isRTL;
@@ -56,21 +51,30 @@
* how far the finger swipes, and not the actual animation distance.
*/
const RIGHT_SWIPE_THRESHOLD = 30 * SLOW_SPEED_SWIPE_FACTOR;
+const DEFAULT_SWIPE_THRESHOLD = 30;
+
+const emptyFunction = () => {};
type Props = $ReadOnly<{|
children?: ?React.Node,
isOpen?: ?boolean,
maxSwipeDistance?: ?number,
- onClose?: ?Function,
- onOpen?: ?Function,
- onSwipeEnd?: ?Function,
- onSwipeStart?: ?Function,
+ onClose?: ?() => void,
+ onOpen?: ?() => void,
+ onSwipeEnd?: ?() => void,
+ onSwipeStart?: ?() => void,
preventSwipeRight?: ?boolean,
shouldBounceOnMount?: ?boolean,
slideoutView?: ?React.Node,
swipeThreshold?: ?number,
|}>;
+type State = {
+ currentLeft: Animated.Value,
+ isSwipeableViewRendered: boolean,
+ rowHeight: ?number,
+};
+
/**
* Creates a swipable row that allows taps on the main item and a custom View
* on the item hidden behind the row. Typically this should be used in
@@ -78,65 +82,74 @@
* used in a normal ListView. See the renderRow for SwipeableListView to see how
* to use this component separately.
*/
-const SwipeableRow = createReactClass({
- displayName: 'SwipeableRow',
- _panResponder: {},
- _previousLeft: CLOSED_LEFT_POSITION,
-
- mixins: [TimerMixin],
-
- propTypes: {
- children: PropTypes.any,
- isOpen: PropTypes.bool,
- preventSwipeRight: PropTypes.bool,
- maxSwipeDistance: PropTypes.number.isRequired,
- onOpen: PropTypes.func.isRequired,
- onClose: PropTypes.func.isRequired,
- onSwipeEnd: PropTypes.func.isRequired,
- onSwipeStart: PropTypes.func.isRequired,
- // Should bounce the row on mount
- shouldBounceOnMount: PropTypes.bool,
- /**
- * A ReactElement that is unveiled when the user swipes
- */
- slideoutView: PropTypes.node.isRequired,
- /**
- * The minimum swipe distance required before fully animating the swipe. If
- * the user swipes less than this distance, the item will return to its
- * previous (open/close) position.
- */
- swipeThreshold: PropTypes.number.isRequired,
- },
+class SwipeableRow extends React.Component<Props, State> {
+ _handleMoveShouldSetPanResponderCapture = (
+ event: PressEvent,
+ gestureState: GestureState,
+ ): boolean => {
+ // Decides whether a swipe is responded to by this component or its child
+ return gestureState.dy < 10 && this._isValidSwipe(gestureState);
+ };
- getInitialState(): Object {
- return {
- currentLeft: new Animated.Value(this._previousLeft),
- /**
- * In order to render component A beneath component B, A must be rendered
- * before B. However, this will cause "flickering", aka we see A briefly
- * then B. To counter this, _isSwipeableViewRendered flag is used to set
- * component A to be transparent until component B is loaded.
- */
- isSwipeableViewRendered: false,
- rowHeight: (null: ?number),
+ _handlePanResponderGrant = (
+ event: PressEvent,
+ gestureState: GestureState,
+ ): void => {};
+
+ _handlePanResponderMove = (
+ event: PressEvent,
+ gestureState: GestureState,
+ ): void => {
+ if (this._isSwipingExcessivelyRightFromClosedPosition(gestureState)) {
+ return;
+ }
+
+ this.props.onSwipeStart && this.props.onSwipeStart();
+
+ if (this._isSwipingRightFromClosed(gestureState)) {
+ this._swipeSlowSpeed(gestureState);
+ } else {
+ this._swipeFullSpeed(gestureState);
+ }
};
- },
- getDefaultProps(): Object {
- return {
- isOpen: false,
- preventSwipeRight: false,
- maxSwipeDistance: 0,
- onOpen: emptyFunction,
- onClose: emptyFunction,
- onSwipeEnd: emptyFunction,
- onSwipeStart: emptyFunction,
- swipeThreshold: 30,
+ _onPanResponderTerminationRequest = (
+ event: PressEvent,
+ gestureState: GestureState,
+ ): boolean => {
+ return false;
+ };
+
+ _handlePanResponderEnd = (
+ event: PressEvent,
+ gestureState: GestureState,
+ ): void => {
+ const horizontalDistance = IS_RTL ? -gestureState.dx : gestureState.dx;
+ if (this._isSwipingRightFromClosed(gestureState)) {
+ this.props.onOpen && this.props.onOpen();
+ this._animateBounceBack(RIGHT_SWIPE_BOUNCE_BACK_DURATION);
+ } else if (this._shouldAnimateRemainder(gestureState)) {
+ if (horizontalDistance < 0) {
+ // Swiped left
+ this.props.onOpen && this.props.onOpen();
+ this._animateToOpenPositionWith(gestureState.vx, horizontalDistance);
+ } else {
+ // Swiped right
+ this.props.onClose && this.props.onClose();
+ this._animateToClosedPosition();
+ }
+ } else {
+ if (this._previousLeft === CLOSED_LEFT_POSITION) {
+ this._animateToClosedPosition();
+ } else {
+ this._animateToOpenPosition();
+ }
+ }
+
+ this.props.onSwipeEnd && this.props.onSwipeEnd();
};
- },
- UNSAFE_componentWillMount(): void {
- this._panResponder = PanResponder.create({
+ _panResponder = PanResponder.create({
onMoveShouldSetPanResponderCapture: this
._handleMoveShouldSetPanResponderCapture,
onPanResponderGrant: this._handlePanResponderGrant,
@@ -146,7 +159,21 @@
onPanResponderTerminate: this._handlePanResponderEnd,
onShouldBlockNativeResponder: (event, gestureState) => false,
});
- },
+
+ _previousLeft = CLOSED_LEFT_POSITION;
+ _timeoutID: ?TimeoutID = null;
+
+ state = {
+ currentLeft: new Animated.Value(this._previousLeft),
+ /**
+ * In order to render component A beneath component B, A must be rendered
+ * before B. However, this will cause "flickering", aka we see A briefly
+ * then B. To counter this, _isSwipeableViewRendered flag is used to set
+ * component A to be transparent until component B is loaded.
+ */
+ isSwipeableViewRendered: false,
+ rowHeight: null,
+ };
componentDidMount(): void {
if (this.props.shouldBounceOnMount) {
@@ -154,21 +181,30 @@
* Do the on mount bounce after a delay because if we animate when other
* components are loading, the animation will be laggy
*/
- this.setTimeout(() => {
+ this._timeoutID = setTimeout(() => {
this._animateBounceBack(ON_MOUNT_BOUNCE_DURATION);
}, ON_MOUNT_BOUNCE_DELAY);
}
- },
+ }
- UNSAFE_componentWillReceiveProps(nextProps: Object): void {
+ UNSAFE_componentWillReceiveProps(nextProps: $Shape<Props>): void {
/**
* We do not need an "animateOpen(noCallback)" because this animation is
* handled internally by this component.
*/
- if (this.props.isOpen && !nextProps.isOpen) {
+ const isOpen = this.props.isOpen ?? false;
+ const nextIsOpen = nextProps.isOpen ?? false;
+
+ if (isOpen && !nextIsOpen) {
this._animateToClosedPosition();
}
- },
+ }
+
+ componentWillUnmount() {
+ if (this._timeoutID != null) {
+ clearTimeout(this._timeoutID);
+ }
+ }
render(): React.Element<any> {
// The view hidden behind the main view
@@ -197,60 +233,38 @@
{swipeableView}
</View>
);
- },
+ }
close(): void {
- this.props.onClose();
+ this.props.onClose && this.props.onClose();
this._animateToClosedPosition();
- },
+ }
- _onSwipeableViewLayout(event: Object): void {
+ _onSwipeableViewLayout = (event: LayoutEvent): void => {
this.setState({
isSwipeableViewRendered: true,
rowHeight: event.nativeEvent.layout.height,
});
- },
-
- _handleMoveShouldSetPanResponderCapture(
- event: Object,
- gestureState: Object,
- ): boolean {
- // Decides whether a swipe is responded to by this component or its child
- return gestureState.dy < 10 && this._isValidSwipe(gestureState);
- },
-
- _handlePanResponderGrant(event: Object, gestureState: Object): void {},
-
- _handlePanResponderMove(event: Object, gestureState: Object): void {
- if (this._isSwipingExcessivelyRightFromClosedPosition(gestureState)) {
- return;
- }
-
- this.props.onSwipeStart();
-
- if (this._isSwipingRightFromClosed(gestureState)) {
- this._swipeSlowSpeed(gestureState);
- } else {
- this._swipeFullSpeed(gestureState);
- }
- },
+ };
- _isSwipingRightFromClosed(gestureState: Object): boolean {
+ _isSwipingRightFromClosed(gestureState: GestureState): boolean {
const gestureStateDx = IS_RTL ? -gestureState.dx : gestureState.dx;
return this._previousLeft === CLOSED_LEFT_POSITION && gestureStateDx > 0;
- },
+ }
- _swipeFullSpeed(gestureState: Object): void {
+ _swipeFullSpeed(gestureState: GestureState): void {
this.state.currentLeft.setValue(this._previousLeft + gestureState.dx);
- },
+ }
- _swipeSlowSpeed(gestureState: Object): void {
+ _swipeSlowSpeed(gestureState: GestureState): void {
this.state.currentLeft.setValue(
this._previousLeft + gestureState.dx / SLOW_SPEED_SWIPE_FACTOR,
);
- },
+ }
- _isSwipingExcessivelyRightFromClosedPosition(gestureState: Object): boolean {
+ _isSwipingExcessivelyRightFromClosedPosition(
+ gestureState: GestureState,
+ ): boolean {
/**
* We want to allow a BIT of right swipe, to allow users to know that
* swiping is available, but swiping right does not do anything
@@ -261,14 +275,7 @@
this._isSwipingRightFromClosed(gestureState) &&
gestureStateDx > RIGHT_SWIPE_THRESHOLD
);
- },
-
- _onPanResponderTerminationRequest(
- event: Object,
- gestureState: Object,
- ): boolean {
- return false;
- },
+ }
_animateTo(
toValue: number,
@@ -283,14 +290,15 @@
this._previousLeft = toValue;
callback();
});
- },
+ }
_animateToOpenPosition(): void {
- const maxSwipeDistance = IS_RTL
- ? -this.props.maxSwipeDistance
- : this.props.maxSwipeDistance;
- this._animateTo(-maxSwipeDistance);
- },
+ const maxSwipeDistance = this.props.maxSwipeDistance ?? 0;
+ const directionAwareMaxSwipeDistance = IS_RTL
+ ? -maxSwipeDistance
+ : maxSwipeDistance;
+ this._animateTo(-directionAwareMaxSwipeDistance);
+ }
_animateToOpenPositionWith(speed: number, distMoved: number): void {
/**
@@ -301,26 +309,25 @@
speed > HORIZONTAL_FULL_SWIPE_SPEED_THRESHOLD
? speed
: HORIZONTAL_FULL_SWIPE_SPEED_THRESHOLD;
+ const maxSwipeDistance = this.props.maxSwipeDistance ?? 0;
/**
* Calculate the duration the row should take to swipe the remaining distance
* at the same speed the user swiped (or the speed threshold)
*/
- const duration = Math.abs(
- (this.props.maxSwipeDistance - Math.abs(distMoved)) / speed,
- );
- const maxSwipeDistance = IS_RTL
- ? -this.props.maxSwipeDistance
- : this.props.maxSwipeDistance;
- this._animateTo(-maxSwipeDistance, duration);
- },
+ const duration = Math.abs((maxSwipeDistance - Math.abs(distMoved)) / speed);
+ const directionAwareMaxSwipeDistance = IS_RTL
+ ? -maxSwipeDistance
+ : maxSwipeDistance;
+ this._animateTo(-directionAwareMaxSwipeDistance, duration);
+ }
_animateToClosedPosition(duration: number = SWIPE_DURATION): void {
this._animateTo(CLOSED_LEFT_POSITION, duration);
- },
+ }
- _animateToClosedPositionDuringBounce(): void {
+ _animateToClosedPositionDuringBounce = (): void => {
this._animateToClosedPosition(RIGHT_SWIPE_BOUNCE_BACK_DURATION);
- },
+ };
_animateBounceBack(duration: number): void {
/**
@@ -335,12 +342,13 @@
duration,
this._animateToClosedPositionDuringBounce,
);
- },
+ }
// Ignore swipes due to user's finger moving slightly when tapping
- _isValidSwipe(gestureState: Object): boolean {
+ _isValidSwipe(gestureState: GestureState): boolean {
+ const preventSwipeRight = this.props.preventSwipeRight ?? false;
if (
- this.props.preventSwipeRight &&
+ preventSwipeRight &&
this._previousLeft === CLOSED_LEFT_POSITION &&
gestureState.dx > 0
) {
@@ -348,49 +356,19 @@
}
return Math.abs(gestureState.dx) > HORIZONTAL_SWIPE_DISTANCE_THRESHOLD;
- },
+ }
- _shouldAnimateRemainder(gestureState: Object): boolean {
+ _shouldAnimateRemainder(gestureState: GestureState): boolean {
/**
* If user has swiped past a certain distance, animate the rest of the way
* if they let go
*/
+ const swipeThreshold = this.props.swipeThreshold ?? DEFAULT_SWIPE_THRESHOLD;
return (
- Math.abs(gestureState.dx) > this.props.swipeThreshold ||
+ Math.abs(gestureState.dx) > swipeThreshold ||
gestureState.vx > HORIZONTAL_FULL_SWIPE_SPEED_THRESHOLD
);
- },
-
- _handlePanResponderEnd(event: Object, gestureState: Object): void {
- const horizontalDistance = IS_RTL ? -gestureState.dx : gestureState.dx;
- if (this._isSwipingRightFromClosed(gestureState)) {
- this.props.onOpen();
- this._animateBounceBack(RIGHT_SWIPE_BOUNCE_BACK_DURATION);
- } else if (this._shouldAnimateRemainder(gestureState)) {
- if (horizontalDistance < 0) {
- // Swiped left
- this.props.onOpen();
- this._animateToOpenPositionWith(gestureState.vx, horizontalDistance);
- } else {
- // Swiped right
- this.props.onClose();
- this._animateToClosedPosition();
- }
- } else {
- if (this._previousLeft === CLOSED_LEFT_POSITION) {
- this._animateToClosedPosition();
- } else {
- this._animateToOpenPosition();
- }
}
-
- this.props.onSwipeEnd();
- },
-});
-
-// TODO: Delete this when `SwipeableRow` uses class syntax.
-class TypedSwipeableRow extends React.Component<Props> {
- close() {}
}
const styles = StyleSheet.create({
@@ -403,4 +381,4 @@
},
});
-module.exports = ((SwipeableRow: any): Class<TypedSwipeableRow>);
+module.exports = SwipeableRow;

Libraries/Experimental/WindowedListView.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -14,7 +14,6 @@
const IncrementalGroup = require('IncrementalGroup');
const React = require('React');
const ScrollView = require('ScrollView');
-const Set = require('Set');
const StyleSheet = require('StyleSheet');
const Systrace = require('Systrace');
const View = require('View');
@@ -23,8 +22,8 @@
const clamp = require('clamp');
const deepDiffer = require('deepDiffer');
const infoLog = require('infoLog');
-const invariant = require('fbjs/lib/invariant');
-const nullthrows = require('fbjs/lib/nullthrows');
+const invariant = require('invariant');
+const nullthrows = require('nullthrows');
import type {NativeMethodsMixinType} from 'ReactNativeTypes';
@@ -778,11 +777,7 @@
if (DEBUG) {
infoLog('render cell ' + this.props.rowIndex);
const Text = require('Text');
- debug = (
- <Text style={{backgroundColor: 'lightblue'}}>
- Row: {this.props.rowIndex}
- </Text>
- );
+ debug = <Text style={styles.debug}>Row: {this.props.rowIndex}</Text>;
}
const style = this._includeInLayoutLatch ? styles.include : styles.remove;
return (
@@ -820,6 +815,9 @@
right: -removedXOffset,
opacity: DEBUG ? 0.1 : 0,
},
+ debug: {
+ backgroundColor: 'lightblue',
+ },
});
module.exports = WindowedListView;

Libraries/Geolocation/Geolocation.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -13,7 +13,7 @@
const NativeEventEmitter = require('NativeEventEmitter');
const RCTLocationObserver = require('NativeModules').LocationObserver;
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
const logError = require('logError');
/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
* found when Flow v0.54 was deployed. To see the error delete this comment and

Libraries/Geolocation/RCTLocationObserver.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Geolocation/RCTLocationObserver.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -353,11 +353,6 @@
[_locationManager stopUpdatingLocation];
}
- // Reset location accuracy if desiredAccuracy is changed.
- // Otherwise update accuracy will force triggering didUpdateLocations, watchPosition would keeping receiving location updates, even there's no location changes.
- if (ABS(_locationManager.desiredAccuracy - RCT_DEFAULT_LOCATION_ACCURACY) > 0.000001) {
- _locationManager.desiredAccuracy = RCT_DEFAULT_LOCATION_ACCURACY;
- }
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
@@ -389,11 +384,6 @@
}
[_pendingRequests removeAllObjects];
- // Reset location accuracy if desiredAccuracy is changed.
- // Otherwise update accuracy will force triggering didUpdateLocations, watchPosition would keeping receiving location updates, even there's no location changes.
- if (ABS(_locationManager.desiredAccuracy - RCT_DEFAULT_LOCATION_ACCURACY) > 0.000001) {
- _locationManager.desiredAccuracy = RCT_DEFAULT_LOCATION_ACCURACY;
- }
}
static void checkLocationConfig()

Libraries/Image/assetPathUtils.js

@@ -0,0 +1,88 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow strict
+ */
+
+'use strict';
+
+import type {PackagerAsset} from './AssetRegistry';
+
+const androidScaleSuffix = {
+ '0.75': 'ldpi',
+ '1': 'mdpi',
+ '1.5': 'hdpi',
+ '2': 'xhdpi',
+ '3': 'xxhdpi',
+ '4': 'xxxhdpi',
+};
+
+/**
+ * FIXME: using number to represent discrete scale numbers is fragile in essence because of
+ * floating point numbers imprecision.
+ */
+function getAndroidAssetSuffix(scale: number): string {
+ if (scale.toString() in androidScaleSuffix) {
+ return androidScaleSuffix[scale.toString()];
+ }
+
+ throw new Error('no such scale ' + scale.toString());
+}
+
+// See https://developer.android.com/guide/topics/resources/drawable-resource.html
+const drawableFileTypes = new Set([
+ 'gif',
+ 'jpeg',
+ 'jpg',
+ 'png',
+ 'svg',
+ 'webp',
+ 'xml',
+]);
+
+function getAndroidResourceFolderName(asset: PackagerAsset, scale: number) {
+ if (!drawableFileTypes.has(asset.type)) {
+ return 'raw';
+ }
+ var suffix = getAndroidAssetSuffix(scale);
+ if (!suffix) {
+ throw new Error(
+ "Don't know which android drawable suffix to use for scale: " +
+ scale +
+ '\nAsset: ' +
+ JSON.stringify(asset, null, '\t') +
+ '\nPossible scales are:' +
+ JSON.stringify(androidScaleSuffix, null, '\t'),
+ );
+ }
+ const androidFolder = 'drawable-' + suffix;
+ return androidFolder;
+}
+
+function getAndroidResourceIdentifier(asset: PackagerAsset) {
+ var folderPath = getBasePath(asset);
+ return (folderPath + '/' + asset.name)
+ .toLowerCase()
+ .replace(/\//g, '_') // Encode folder structure in file name
+ .replace(/([^a-z0-9_])/g, '') // Remove illegal chars
+ .replace(/^assets_/, ''); // Remove "assets_" prefix
+}
+
+function getBasePath(asset: PackagerAsset) {
+ var basePath = asset.httpServerLocation;
+ if (basePath[0] === '/') {
+ basePath = basePath.substr(1);
+ }
+ return basePath;
+}
+
+module.exports = {
+ getAndroidAssetSuffix: getAndroidAssetSuffix,
+ getAndroidResourceFolderName: getAndroidResourceFolderName,
+ getAndroidResourceIdentifier: getAndroidResourceIdentifier,
+ getBasePath: getBasePath,
+};

Libraries/Image/AssetRegistry.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Image/AssetSourceResolver.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -22,8 +22,8 @@
const PixelRatio = require('PixelRatio');
const Platform = require('Platform');
-const assetPathUtils = require('../../local-cli/bundle/assetPathUtils');
-const invariant = require('fbjs/lib/invariant');
+const assetPathUtils = require('./assetPathUtils');
+const invariant = require('invariant');
/**
* Returns a path like 'assets/AwesomeModule/icon@2x.png'

Libraries/Image/Image.android.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,25 +10,24 @@
'use strict';
-const ImageStylePropTypes = require('ImageStylePropTypes');
+const DeprecatedImageStylePropTypes = require('DeprecatedImageStylePropTypes');
+const DeprecatedStyleSheetPropType = require('DeprecatedStyleSheetPropType');
+const DeprecatedViewPropTypes = require('DeprecatedViewPropTypes');
+const ImageViewNativeComponent = require('ImageViewNativeComponent');
const NativeModules = require('NativeModules');
-const React = require('React');
-const ReactNative = require('ReactNative');
const PropTypes = require('prop-types');
+const React = require('React');
+const ReactNative = require('ReactNative'); // eslint-disable-line no-unused-vars
const StyleSheet = require('StyleSheet');
-const StyleSheetPropType = require('StyleSheetPropType');
const TextAncestor = require('TextAncestor');
-const ViewPropTypes = require('ViewPropTypes');
const flattenStyle = require('flattenStyle');
const merge = require('merge');
-const requireNativeComponent = require('requireNativeComponent');
const resolveAssetSource = require('resolveAssetSource');
const {ImageLoader} = NativeModules;
-const RKImage = requireNativeComponent('RCTImageView');
-const RCTTextInlineImage = requireNativeComponent('RCTTextInlineImage');
+const TextInlineImageNativeComponent = require('TextInlineImageNativeComponent');
import type {ImageProps as ImagePropsType} from 'ImageProps';
@@ -38,8 +37,8 @@
}
const ImageProps = {
- ...ViewPropTypes,
- style: StyleSheetPropType(ImageStylePropTypes),
+ ...DeprecatedViewPropTypes,
+ style: DeprecatedStyleSheetPropType(DeprecatedImageStylePropTypes),
/**
* See https://facebook.github.io/react-native/docs/image.html#source
*/
@@ -182,7 +181,7 @@
*/
let Image = (
props: ImagePropsType,
- forwardedRef: ?React.Ref<'RCTTextInlineImage' | 'RKImage'>,
+ forwardedRef: ?React.Ref<'RCTTextInlineImage' | 'ImageViewNativeComponent'>,
) => {
let source = resolveAssetSource(props.source);
const defaultSource = resolveAssetSource(props.defaultSource);
@@ -250,24 +249,26 @@
<TextAncestor.Consumer>
{hasTextAncestor =>
hasTextAncestor ? (
- <RCTTextInlineImage {...nativeProps} />
+ <TextInlineImageNativeComponent {...nativeProps} />
) : (
- <RKImage {...nativeProps} />
+ <ImageViewNativeComponent {...nativeProps} />
)
}
</TextAncestor.Consumer>
);
};
-// $FlowFixMe - TODO T29156721 `React.forwardRef` is not defined in Flow, yet.
Image = React.forwardRef(Image);
+Image.displayName = 'Image';
/**
- * Prefetches a remote image for later use by downloading it to the disk
- * cache
+ * Retrieve the width and height (in pixels) of an image prior to displaying it
*
- * See https://facebook.github.io/react-native/docs/image.html#prefetch
+ * See https://facebook.github.io/react-native/docs/image.html#getsize
*/
+/* $FlowFixMe(>=0.89.0 site=react_native_android_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
Image.getSize = getSize;
/**
@@ -276,6 +277,9 @@
*
* See https://facebook.github.io/react-native/docs/image.html#prefetch
*/
+/* $FlowFixMe(>=0.89.0 site=react_native_android_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
Image.prefetch = prefetch;
/**
@@ -283,6 +287,9 @@
*
* See https://facebook.github.io/react-native/docs/image.html#abortprefetch
*/
+/* $FlowFixMe(>=0.89.0 site=react_native_android_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
Image.abortPrefetch = abortPrefetch;
/**
@@ -290,6 +297,9 @@
*
* See https://facebook.github.io/react-native/docs/image.html#querycache
*/
+/* $FlowFixMe(>=0.89.0 site=react_native_android_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
Image.queryCache = queryCache;
/**
@@ -297,8 +307,14 @@
*
* See https://facebook.github.io/react-native/docs/image.html#resolveassetsource
*/
+/* $FlowFixMe(>=0.89.0 site=react_native_android_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
Image.resolveAssetSource = resolveAssetSource;
+/* $FlowFixMe(>=0.89.0 site=react_native_android_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
Image.propTypes = ImageProps;
const styles = StyleSheet.create({
@@ -307,4 +323,7 @@
},
});
+/* $FlowFixMe(>=0.89.0 site=react_native_android_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
module.exports = (Image: Class<ImageComponentType>);

Libraries/Image/ImageBackground.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Image/ImageEditor.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -16,25 +16,25 @@
* The top-left corner of the cropped image, specified in the original
* image's coordinate space.
*/
- offset: {
+ offset: {|
x: number,
y: number,
- },
+ |},
/**
* The size (dimensions) of the cropped image, specified in the original
* image's coordinate space.
*/
- size: {
+ size: {|
width: number,
height: number,
- },
+ |},
/**
* (Optional) size to scale the cropped image to.
*/
- displaySize?: ?{
+ displaySize?: ?{|
width: number,
height: number,
- },
+ |},
/**
* (Optional) the resizing mode to use when scaling the image. If the
* `displaySize` param is not specified, this has no effect.

Libraries/Image/Image.ios.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,10 +9,10 @@
*/
'use strict';
-const ImageProps = require('ImageProps');
+const DeprecatedImagePropType = require('DeprecatedImagePropType');
const NativeModules = require('NativeModules');
const React = require('React');
-const ReactNative = require('ReactNative');
+const ReactNative = require('ReactNative'); // eslint-disable-line no-unused-vars
const StyleSheet = require('StyleSheet');
const flattenStyle = require('flattenStyle');
@@ -25,6 +25,8 @@
import type {ImageProps as ImagePropsType} from 'ImageProps';
+import type {ImageStyleProp} from 'StyleSheet';
+
function getSize(
uri: string,
success: (width: number, height: number) => void,
@@ -44,13 +46,20 @@
return ImageViewManager.prefetchImage(url);
}
+async function queryCache(
+ urls: Array<string>,
+): Promise<Map<string, 'memory' | 'disk'>> {
+ return await ImageViewManager.queryCache(urls);
+}
+
declare class ImageComponentType extends ReactNative.NativeComponent<
ImagePropsType,
> {
static getSize: typeof getSize;
static prefetch: typeof prefetch;
+ static queryCache: typeof queryCache;
static resolveAssetSource: typeof resolveAssetSource;
- static propTypes: typeof ImageProps;
+ static propTypes: typeof DeprecatedImagePropType;
}
/**
@@ -71,12 +80,14 @@
};
let sources;
- let style;
+ let style: ImageStyleProp;
if (Array.isArray(source)) {
+ // $FlowFixMe flattenStyle is not strong enough
style = flattenStyle([styles.base, props.style]) || {};
sources = source;
} else {
const {width, height, uri} = source;
+ // $FlowFixMe flattenStyle is not strong enough
style = flattenStyle([{width, height}, styles.base, props.style]) || {};
sources = [source];
@@ -112,14 +123,17 @@
);
};
-// $FlowFixMe - TODO T29156721 `React.forwardRef` is not defined in Flow, yet.
Image = React.forwardRef(Image);
+Image.displayName = 'Image';
/**
* Retrieve the width and height (in pixels) of an image prior to displaying it.
*
* See https://facebook.github.io/react-native/docs/image.html#getsize
*/
+/* $FlowFixMe(>=0.89.0 site=react_native_ios_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
Image.getSize = getSize;
/**
@@ -128,16 +142,35 @@
*
* See https://facebook.github.io/react-native/docs/image.html#prefetch
*/
+/* $FlowFixMe(>=0.89.0 site=react_native_ios_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
Image.prefetch = prefetch;
/**
+ * Performs cache interrogation.
+ *
+ * See https://facebook.github.io/react-native/docs/image.html#querycache
+ */
+/* $FlowFixMe(>=0.89.0 site=react_native_ios_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
+Image.queryCache = queryCache;
+
+/**
* Resolves an asset reference into an object.
*
* See https://facebook.github.io/react-native/docs/image.html#resolveassetsource
*/
+/* $FlowFixMe(>=0.89.0 site=react_native_ios_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
Image.resolveAssetSource = resolveAssetSource;
-Image.propTypes = ImageProps;
+/* $FlowFixMe(>=0.89.0 site=react_native_ios_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
+Image.propTypes = DeprecatedImagePropType;
const styles = StyleSheet.create({
base: {
@@ -145,4 +178,7 @@
},
});
+/* $FlowFixMe(>=0.89.0 site=react_native_ios_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete this
+ * comment and run Flow. */
module.exports = (Image: Class<ImageComponentType>);

Libraries/Image/ImageProps.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,35 +10,42 @@
'use strict';
-const EdgeInsetsPropType = require('EdgeInsetsPropType');
-const ImageSourcePropType = require('ImageSourcePropType');
-const ImageStylePropTypes = require('ImageStylePropTypes');
-const PropTypes = require('prop-types');
-const StyleSheetPropType = require('StyleSheetPropType');
-
+import type {SyntheticEvent, LayoutEvent} from 'CoreEventTypes';
+import type {EdgeInsetsProp} from 'EdgeInsetsPropType';
+import type {ImageSource} from 'ImageSource';
+import type {ViewStyleProp, ImageStyleProp} from 'StyleSheet';
import type {DimensionValue} from 'StyleSheetTypes';
import type {ViewProps} from 'ViewPropTypes';
-import type {ImageSource} from 'ImageSource';
-import type {EdgeInsetsProp} from 'EdgeInsetsPropType';
-import type {SyntheticEvent} from 'CoreEventTypes';
-import type {ImageStyleProp} from 'StyleSheet';
-type OnLoadEvent = SyntheticEvent<
+export type ImageLoadEvent = SyntheticEvent<
$ReadOnly<{|
- // Only on Android
- uri?: string,
-
source: $ReadOnly<{|
width: number,
height: number,
url: string,
|}>,
+ uri?: string, // Only on Android
|}>,
>;
type IOSImageProps = $ReadOnly<{|
+ /**
+ * A static image to display while loading the image source.
+ *
+ * See https://facebook.github.io/react-native/docs/image.html#defaultsource
+ */
defaultSource?: ?ImageSource,
+ /**
+ * Invoked when a partial load of the image is complete.
+ *
+ * See https://facebook.github.io/react-native/docs/image.html#onpartialload
+ */
onPartialLoad?: ?() => void,
+ /**
+ * Invoked on download progress with `{nativeEvent: {loaded, total}}`.
+ *
+ * See https://facebook.github.io/react-native/docs/image.html#onprogress
+ */
onProgress?: ?(
event: SyntheticEvent<$ReadOnly<{|loaded: number, total: number|}>>,
) => void,
@@ -51,142 +58,111 @@
|}>;
export type ImageProps = {|
- ...ViewProps,
+ ...$Diff<ViewProps, $ReadOnly<{|style: ?ViewStyleProp|}>>,
...IOSImageProps,
...AndroidImageProps,
- blurRadius?: number,
- capInsets?: ?EdgeInsetsProp,
- onError?: ?(event: SyntheticEvent<$ReadOnly<{||}>>) => void,
- onLoad?: ?(event: OnLoadEvent) => void,
- onLoadEnd?: ?() => void,
- onLoadStart?: ?() => void,
- resizeMethod?: ?('auto' | 'resize' | 'scale'),
- source?: ?ImageSource,
- style?: ImageStyleProp,
-
- // Can be set via props or style, for now
- height?: DimensionValue,
- width?: DimensionValue,
- resizeMode?: ?('cover' | 'contain' | 'stretch' | 'repeat' | 'center'),
-
- src?: empty,
- children?: empty,
-|};
-
-module.exports = {
- /**
- * See https://facebook.github.io/react-native/docs/image.html#style
- */
- style: StyleSheetPropType(ImageStylePropTypes),
- /**
- * The image source (either a remote URL or a local file resource).
- *
- * See https://facebook.github.io/react-native/docs/image.html#source
- */
- source: ImageSourcePropType,
- /**
- * A static image to display while loading the image source.
- *
- * See https://facebook.github.io/react-native/docs/image.html#defaultsource
- */
- defaultSource: PropTypes.oneOfType([
- PropTypes.shape({
- uri: PropTypes.string,
- width: PropTypes.number,
- height: PropTypes.number,
- scale: PropTypes.number,
- }),
- PropTypes.number,
- ]),
/**
* When true, indicates the image is an accessibility element.
*
* See https://facebook.github.io/react-native/docs/image.html#accessible
*/
- accessible: PropTypes.bool,
+ accessible?: ?boolean,
+
/**
* The text that's read by the screen reader when the user interacts with
* the image.
*
* See https://facebook.github.io/react-native/docs/image.html#accessibilitylabel
*/
- accessibilityLabel: PropTypes.node,
+ accessibilityLabel?: ?Stringish,
+
/**
* blurRadius: the blur radius of the blur filter added to the image
*
* See https://facebook.github.io/react-native/docs/image.html#blurradius
*/
- blurRadius: PropTypes.number,
+ blurRadius?: ?number,
+
/**
* See https://facebook.github.io/react-native/docs/image.html#capinsets
*/
- capInsets: EdgeInsetsPropType,
+ capInsets?: ?EdgeInsetsProp,
+
/**
- * See https://facebook.github.io/react-native/docs/image.html#resizemethod
+ * Invoked on load error with `{nativeEvent: {error}}`.
+ *
+ * See https://facebook.github.io/react-native/docs/image.html#onerror
*/
- resizeMethod: PropTypes.oneOf(['auto', 'resize', 'scale']),
+ onError?: ?(event: SyntheticEvent<$ReadOnly<{||}>>) => void,
+
/**
- * Determines how to resize the image when the frame doesn't match the raw
- * image dimensions.
+ * Invoked on mount and layout changes with
+ * `{nativeEvent: {layout: {x, y, width, height}}}`.
*
- * See https://facebook.github.io/react-native/docs/image.html#resizemode
+ * See https://facebook.github.io/react-native/docs/image.html#onlayout
*/
- resizeMode: PropTypes.oneOf([
- 'cover',
- 'contain',
- 'stretch',
- 'repeat',
- 'center',
- ]),
+
+ onLayout?: ?(event: LayoutEvent) => mixed,
+
/**
- * A unique identifier for this element to be used in UI Automation
- * testing scripts.
+ * Invoked when load completes successfully.
*
- * See https://facebook.github.io/react-native/docs/image.html#testid
+ * See https://facebook.github.io/react-native/docs/image.html#onload
*/
- testID: PropTypes.string,
+ onLoad?: ?(event: ImageLoadEvent) => void,
+
/**
- * Invoked on mount and layout changes with
- * `{nativeEvent: {layout: {x, y, width, height}}}`.
+ * Invoked when load either succeeds or fails.
*
- * See https://facebook.github.io/react-native/docs/image.html#onlayout
+ * See https://facebook.github.io/react-native/docs/image.html#onloadend
*/
- onLayout: PropTypes.func,
+ onLoadEnd?: ?() => void,
+
/**
* Invoked on load start.
*
* See https://facebook.github.io/react-native/docs/image.html#onloadstart
*/
- onLoadStart: PropTypes.func,
+ onLoadStart?: ?() => void,
+
/**
- * Invoked on download progress with `{nativeEvent: {loaded, total}}`.
- *
- * See https://facebook.github.io/react-native/docs/image.html#onprogress
+ * See https://facebook.github.io/react-native/docs/image.html#resizemethod
*/
- onProgress: PropTypes.func,
+ resizeMethod?: ?('auto' | 'resize' | 'scale'),
+
/**
- * Invoked on load error with `{nativeEvent: {error}}`.
+ * The image source (either a remote URL or a local file resource).
*
- * See https://facebook.github.io/react-native/docs/image.html#onerror
+ * See https://facebook.github.io/react-native/docs/image.html#source
*/
- onError: PropTypes.func,
+ source?: ?ImageSource,
+
/**
- * Invoked when a partial load of the image is complete.
- *
- * See https://facebook.github.io/react-native/docs/image.html#onpartialload
+ * See https://facebook.github.io/react-native/docs/image.html#style
*/
- onPartialLoad: PropTypes.func,
+ style?: ?ImageStyleProp,
+
+ // Can be set via props or style, for now
+ height?: ?DimensionValue,
+ width?: ?DimensionValue,
+
/**
- * Invoked when load completes successfully.
+ * Determines how to resize the image when the frame doesn't match the raw
+ * image dimensions.
*
- * See https://facebook.github.io/react-native/docs/image.html#onload
+ * See https://facebook.github.io/react-native/docs/image.html#resizemode
*/
- onLoad: PropTypes.func,
+ resizeMode?: ?('cover' | 'contain' | 'stretch' | 'repeat' | 'center'),
+
/**
- * Invoked when load either succeeds or fails.
+ * A unique identifier for this element to be used in UI Automation
+ * testing scripts.
*
- * See https://facebook.github.io/react-native/docs/image.html#onloadend
+ * See https://facebook.github.io/react-native/docs/image.html#testid
*/
- onLoadEnd: PropTypes.func,
-};
+ testID?: ?string,
+
+ src?: empty,
+ children?: empty,
+|};

Libraries/Image/ImageResizeMode.js

@@ -1,52 +1,36 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
*
- * @flow
+ * @flow strict
* @format
*/
-'use strict';
-/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
- * found when Flow v0.54 was deployed. To see the error delete this comment and
- * run Flow. */
-const keyMirror = require('fbjs/lib/keyMirror');
+'use strict';
/**
- * ImageResizeMode - Enum for different image resizing modes, set via
- * `resizeMode` style property on `<Image>` components.
- */
-const ImageResizeMode = keyMirror({
- /**
- * contain - The image will be resized such that it will be completely
- * visible, contained within the frame of the View.
- */
- contain: null,
- /**
- * cover - The image will be resized such that the entire area of the view
- * is covered by the image, potentially clipping parts of the image.
- */
- cover: null,
- /**
- * stretch - The image will be stretched to fill the entire frame of the
- * view without clipping. This may change the aspect ratio of the image,
- * distorting it.
+ * ImageResizeMode defines valid values for different image resizing modes set
+ * via the `resizeMode` style property on `<Image>`.
*/
- stretch: null,
- /**
- * center - The image will be scaled down such that it is completely visible,
- * if bigger than the area of the view.
- * The image will not be scaled up.
- */
- center: null,
+export type ImageResizeMode =
+ // Resize by scaling down such that it is completely visible, if bigger than
+ // the area of the view. The image will not be scaled up.
+ | 'center'
- /**
- * repeat - The image will be repeated to cover the frame of the View. The
- * image will keep it's size and aspect ratio.
- */
- repeat: null,
-});
+ // Resize such that it will be completely visible, contained within the frame
+ // of the View.
+ | 'contain'
+
+ // Resize such that the entire area of the view is covered by the image,
+ // potentially clipping parts of the image.
+ | 'cover'
+
+ // Resize by repeating to cover the frame of the View. The image will keep its
+ // size and aspect ratio.
+ | 'repeat'
-module.exports = ImageResizeMode;
+ // Resize by stretching it to fill the entire frame of the view without
+ // clipping. This may change the aspect ratio of the image, distorting it.
+ | 'stretch';

Libraries/Image/ImageSource.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -14,15 +14,73 @@
// that might have more keys. This also has to be inexact to support taking
// instances of classes like FBIcon.
// https://fburl.com/8lynhvtw
-type ImageURISource = $ReadOnly<{
+export type ImageURISource = $ReadOnly<{
+ /**
+ * `uri` is a string representing the resource identifier for the image, which
+ * could be an http address, a local file path, or the name of a static image
+ * resource (which should be wrapped in the `require('./path/to/image.png')`
+ * function).
+ */
uri?: ?string,
+
+ /**
+ * `bundle` is the iOS asset bundle which the image is included in. This
+ * will default to [NSBundle mainBundle] if not set.
+ * @platform ios
+ */
bundle?: ?string,
+
+ /**
+ * `method` is the HTTP Method to use. Defaults to GET if not specified.
+ */
method?: ?string,
+
+ /**
+ * `headers` is an object representing the HTTP headers to send along with the
+ * request for a remote image.
+ */
headers?: ?Object,
+
+ /**
+ * `body` is the HTTP body to send with the request. This must be a valid
+ * UTF-8 string, and will be sent exactly as specified, with no
+ * additional encoding (e.g. URL-escaping or base64) applied.
+ */
body?: ?string,
+
+ /**
+ * `cache` determines how the requests handles potentially cached
+ * responses.
+ *
+ * - `default`: Use the native platforms default strategy. `useProtocolCachePolicy` on iOS.
+ *
+ * - `reload`: The data for the URL will be loaded from the originating source.
+ * No existing cache data should be used to satisfy a URL load request.
+ *
+ * - `force-cache`: The existing cached data will be used to satisfy the request,
+ * regardless of its age or expiration date. If there is no existing data in the cache
+ * corresponding the request, the data is loaded from the originating source.
+ *
+ * - `only-if-cached`: The existing cache data will be used to satisfy a request, regardless of
+ * its age or expiration date. If there is no existing data in the cache corresponding
+ * to a URL load request, no attempt is made to load the data from the originating source,
+ * and the load is considered to have failed.
+ *
+ * @platform ios
+ */
cache?: ?('default' | 'reload' | 'force-cache' | 'only-if-cached'),
+
+ /**
+ * `width` and `height` can be specified if known at build time, in which case
+ * these will be used to set the default `<Image/>` component dimensions.
+ */
width?: ?number,
height?: ?number,
+
+ /**
+ * `scale` is used to indicate the scale factor of the image. Defaults to 1.0 if
+ * unspecified, meaning that one image pixel equates to one display point / DIP.
+ */
scale?: ?number,
}>;

Libraries/Image/ImageSourcePropType.js

@@ -1,90 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @no-flow
- * @format
- */
-'use strict';
-
-const PropTypes = require('prop-types');
-
-const ImageURISourcePropType = PropTypes.shape({
- /**
- * `uri` is a string representing the resource identifier for the image, which
- * could be an http address, a local file path, or the name of a static image
- * resource (which should be wrapped in the `require('./path/to/image.png')`
- * function).
- */
- uri: PropTypes.string,
- /**
- * `bundle` is the iOS asset bundle which the image is included in. This
- * will default to [NSBundle mainBundle] if not set.
- * @platform ios
- */
- bundle: PropTypes.string,
- /**
- * `method` is the HTTP Method to use. Defaults to GET if not specified.
- */
- method: PropTypes.string,
- /**
- * `headers` is an object representing the HTTP headers to send along with the
- * request for a remote image.
- */
- headers: PropTypes.objectOf(PropTypes.string),
- /**
- * `body` is the HTTP body to send with the request. This must be a valid
- * UTF-8 string, and will be sent exactly as specified, with no
- * additional encoding (e.g. URL-escaping or base64) applied.
- */
- body: PropTypes.string,
- /**
- * `cache` determines how the requests handles potentially cached
- * responses.
- *
- * - `default`: Use the native platforms default strategy. `useProtocolCachePolicy` on iOS.
- *
- * - `reload`: The data for the URL will be loaded from the originating source.
- * No existing cache data should be used to satisfy a URL load request.
- *
- * - `force-cache`: The existing cached data will be used to satisfy the request,
- * regardless of its age or expiration date. If there is no existing data in the cache
- * corresponding the request, the data is loaded from the originating source.
- *
- * - `only-if-cached`: The existing cache data will be used to satisfy a request, regardless of
- * its age or expiration date. If there is no existing data in the cache corresponding
- * to a URL load request, no attempt is made to load the data from the originating source,
- * and the load is considered to have failed.
- *
- * @platform ios
- */
- cache: PropTypes.oneOf([
- 'default',
- 'reload',
- 'force-cache',
- 'only-if-cached',
- ]),
- /**
- * `width` and `height` can be specified if known at build time, in which case
- * these will be used to set the default `<Image/>` component dimensions.
- */
- width: PropTypes.number,
- height: PropTypes.number,
- /**
- * `scale` is used to indicate the scale factor of the image. Defaults to 1.0 if
- * unspecified, meaning that one image pixel equates to one display point / DIP.
- */
- scale: PropTypes.number,
-});
-
-const ImageSourcePropType = PropTypes.oneOfType([
- ImageURISourcePropType,
- // Opaque type returned by require('./image.jpg')
- PropTypes.number,
- // Multiple sources
- PropTypes.arrayOf(ImageURISourcePropType),
-]);
-
-module.exports = ImageSourcePropType;

Libraries/Image/ImageStore.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,6 +11,19 @@
const RCTImageStoreManager = require('NativeModules').ImageStoreManager;
+const Platform = require('Platform');
+
+const warnOnce = require('warnOnce');
+
+function warnUnimplementedMethod(methodName: string): void {
+ warnOnce(
+ `imagestore-${methodName}`,
+ `react-native: ImageStore.${methodName}() is not implemented on ${
+ Platform.OS
+ }`,
+ );
+}
+
class ImageStore {
/**
* Check if the ImageStore contains image data for the specified URI.
@@ -20,7 +33,7 @@
if (RCTImageStoreManager.hasImageForTag) {
RCTImageStoreManager.hasImageForTag(uri, callback);
} else {
- console.warn('hasImageForTag() not implemented');
+ warnUnimplementedMethod('hasImageForTag');
}
}
@@ -36,7 +49,7 @@
if (RCTImageStoreManager.removeImageForTag) {
RCTImageStoreManager.removeImageForTag(uri);
} else {
- console.warn('removeImageForTag() not implemented');
+ warnUnimplementedMethod('removeImageForTag');
}
}
@@ -56,7 +69,15 @@
success: (uri: string) => void,
failure: (error: any) => void,
) {
- RCTImageStoreManager.addImageFromBase64(base64ImageData, success, failure);
+ if (RCTImageStoreManager.addImageFromBase64) {
+ RCTImageStoreManager.addImageFromBase64(
+ base64ImageData,
+ success,
+ failure,
+ );
+ } else {
+ warnUnimplementedMethod('addImageFromBase64');
+ }
}
/**
@@ -75,7 +96,11 @@
success: (base64ImageData: string) => void,
failure: (error: any) => void,
) {
+ if (RCTImageStoreManager.getBase64ForTag) {
RCTImageStoreManager.getBase64ForTag(uri, success, failure);
+ } else {
+ warnUnimplementedMethod('getBase64ForTag');
+ }
}
}

Libraries/Image/ImageStylePropTypes.js

@@ -1,62 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @flow
- * @format
- */
-'use strict';
-
-const ColorPropType = require('ColorPropType');
-const ImageResizeMode = require('ImageResizeMode');
-const LayoutPropTypes = require('LayoutPropTypes');
-const ReactPropTypes = require('prop-types');
-const ShadowPropTypesIOS = require('ShadowPropTypesIOS');
-const TransformPropTypes = require('TransformPropTypes');
-
-const ImageStylePropTypes = {
- ...LayoutPropTypes,
- ...ShadowPropTypesIOS,
- ...TransformPropTypes,
- resizeMode: ReactPropTypes.oneOf(Object.keys(ImageResizeMode)),
- backfaceVisibility: ReactPropTypes.oneOf(['visible', 'hidden']),
- backgroundColor: ColorPropType,
- borderColor: ColorPropType,
- borderWidth: ReactPropTypes.number,
- borderRadius: ReactPropTypes.number,
- overflow: ReactPropTypes.oneOf(['visible', 'hidden']),
-
- /**
- * Changes the color of all the non-transparent pixels to the tintColor.
- */
- tintColor: ColorPropType,
- opacity: ReactPropTypes.number,
- /**
- * When the image has rounded corners, specifying an overlayColor will
- * cause the remaining space in the corners to be filled with a solid color.
- * This is useful in cases which are not supported by the Android
- * implementation of rounded corners:
- * - Certain resize modes, such as 'contain'
- * - Animated GIFs
- *
- * A typical way to use this prop is with images displayed on a solid
- * background and setting the `overlayColor` to the same color
- * as the background.
- *
- * For details of how this works under the hood, see
- * http://frescolib.org/docs/rounded-corners-and-circles.html
- *
- * @platform android
- */
- overlayColor: ReactPropTypes.string,
-
- // Android-Specific styles
- borderTopLeftRadius: ReactPropTypes.number,
- borderTopRightRadius: ReactPropTypes.number,
- borderBottomLeftRadius: ReactPropTypes.number,
- borderBottomRightRadius: ReactPropTypes.number,
-};
-
-module.exports = ImageStylePropTypes;

Libraries/Image/ImageViewNativeComponent.js

@@ -0,0 +1,17 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow
+ */
+
+'use strict';
+
+const requireNativeComponent = require('requireNativeComponent');
+
+const ImageViewNativeComponent = requireNativeComponent('RCTImageView');
+
+module.exports = ImageViewNativeComponent;

Libraries/Image/nativeImageSource.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -23,6 +23,7 @@
type NativeImageSourceSpec = {|
+android?: string,
+ios?: string,
+ +default?: string,
// For more details on width and height, see
// http://facebook.github.io/react-native/docs/images.html#why-not-automatically-size-everything
@@ -47,7 +48,11 @@
*
*/
function nativeImageSource(spec: NativeImageSourceSpec): Object {
- let uri = Platform.select(spec);
+ let uri = Platform.select({
+ android: spec.android,
+ default: spec.default,
+ ios: spec.ios,
+ });
if (uri == null) {
console.warn(
'nativeImageSource(...): No image name supplied for `%s`:\n%s',

Libraries/Image/RCTGIFImageDecoder.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Image/RCTGIFImageDecoder.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -31,8 +31,12 @@
completionHandler:(RCTImageLoaderCompletionBlock)completionHandler
{
CGImageSourceRef imageSource = CGImageSourceCreateWithData((CFDataRef)imageData, NULL);
+ if (!imageSource) {
+ completionHandler(nil, nil);
+ return ^{};
+ }
NSDictionary<NSString *, id> *properties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties(imageSource, NULL);
- NSUInteger loopCount = 0;
+ CGFloat loopCount = 0;
if ([[properties[(id)kCGImagePropertyGIFDictionary] allKeys] containsObject:(id)kCGImagePropertyGIFLoopCount]) {
loopCount = [properties[(id)kCGImagePropertyGIFDictionary][(id)kCGImagePropertyGIFLoopCount] unsignedIntegerValue];
if (loopCount == 0) {
@@ -54,6 +58,9 @@
for (size_t i = 0; i < imageCount; i++) {
CGImageRef imageRef = CGImageSourceCreateImageAtIndex(imageSource, i, NULL);
+ if (!imageRef) {
+ continue;
+ }
if (!image) {
image = [UIImage imageWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp];
}
@@ -64,10 +71,10 @@
const NSTimeInterval kDelayTimeIntervalDefault = 0.1;
NSNumber *delayTime = frameGIFProperties[(id)kCGImagePropertyGIFUnclampedDelayTime] ?: frameGIFProperties[(id)kCGImagePropertyGIFDelayTime];
if (delayTime == nil) {
- if (i == 0) {
+ if (delays.count == 0) {
delayTime = @(kDelayTimeIntervalDefault);
} else {
- delayTime = delays[i - 1];
+ delayTime = delays.lastObject;
}
}
@@ -77,8 +84,8 @@
}
duration += delayTime.doubleValue;
- delays[i] = delayTime;
- images[i] = (__bridge_transfer id)imageRef;
+ [delays addObject:delayTime];
+ [images addObject:(__bridge_transfer id)imageRef];
}
CFRelease(imageSource);

Libraries/Image/RCTImageBlurUtils.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

Libraries/Image/RCTImageBlurUtils.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Image/RCTImageCache.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Image/RCTImageCache.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -21,22 +21,25 @@
static const NSUInteger RCTMaxCachableDecodedImageSizeInBytes = 2097152; // 2 MB
static NSString *RCTCacheKeyForImage(NSString *imageTag, CGSize size, CGFloat scale,
- RCTResizeMode resizeMode, NSString *responseDate)
+ RCTResizeMode resizeMode)
{
- return [NSString stringWithFormat:@"%@|%g|%g|%g|%lld|%@",
- imageTag, size.width, size.height, scale, (long long)resizeMode, responseDate];
+ return [NSString stringWithFormat:@"%@|%g|%g|%g|%lld",
+ imageTag, size.width, size.height, scale, (long long)resizeMode];
}
@implementation RCTImageCache
{
NSOperationQueue *_imageDecodeQueue;
NSCache *_decodedImageCache;
+ NSMutableDictionary *_cacheStaleTimes;
}
- (instancetype)init
{
+ if (self = [super init]) {
_decodedImageCache = [NSCache new];
_decodedImageCache.totalCostLimit = 20 * 1024 * 1024; // 20 MB
+ _cacheStaleTimes = [[NSMutableDictionary alloc] init];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(clearCache)
@@ -46,6 +49,7 @@
selector:@selector(clearCache)
name:UIApplicationWillResignActiveNotification
object:nil];
+ }
return self;
}
@@ -58,6 +62,9 @@
- (void)clearCache
{
[_decodedImageCache removeAllObjects];
+ @synchronized(_cacheStaleTimes) {
+ [_cacheStaleTimes removeAllObjects];
+ }
}
- (void)addImageToCache:(UIImage *)image
@@ -66,7 +73,7 @@
if (!image) {
return;
}
- CGFloat bytes = image.size.width * image.size.height * image.scale * image.scale * 4;
+ NSInteger bytes = image.reactDecodedImageBytes;
if (bytes <= RCTMaxCachableDecodedImageSizeInBytes) {
[self->_decodedImageCache setObject:image
forKey:cacheKey
@@ -78,9 +85,19 @@
size:(CGSize)size
scale:(CGFloat)scale
resizeMode:(RCTResizeMode)resizeMode
- responseDate:(NSString *)responseDate
{
- NSString *cacheKey = RCTCacheKeyForImage(url, size, scale, resizeMode, responseDate);
+ NSString *cacheKey = RCTCacheKeyForImage(url, size, scale, resizeMode);
+ @synchronized(_cacheStaleTimes) {
+ id staleTime = _cacheStaleTimes[cacheKey];
+ if (staleTime) {
+ if ([[NSDate new] compare:(NSDate *)staleTime] == NSOrderedDescending) {
+ // cached image has expired, clear it out to make room for others
+ [_cacheStaleTimes removeObjectForKey:cacheKey];
+ [_decodedImageCache removeObjectForKey:cacheKey];
+ return nil;
+ }
+ }
+ }
return [_decodedImageCache objectForKey:cacheKey];
}
@@ -89,10 +106,63 @@
size:(CGSize)size
scale:(CGFloat)scale
resizeMode:(RCTResizeMode)resizeMode
- responseDate:(NSString *)responseDate
+ response:(NSURLResponse *)response
{
- NSString *cacheKey = RCTCacheKeyForImage(url, size, scale, resizeMode, responseDate);
+ if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
+ NSString *cacheKey = RCTCacheKeyForImage(url, size, scale, resizeMode);
+ BOOL shouldCache = YES;
+ NSString *responseDate = ((NSHTTPURLResponse *)response).allHeaderFields[@"Date"];
+ NSDate *originalDate = [self dateWithHeaderString:responseDate];
+ NSString *cacheControl = ((NSHTTPURLResponse *)response).allHeaderFields[@"Cache-Control"];
+ NSDate *staleTime;
+ NSArray<NSString *> *components = [cacheControl componentsSeparatedByString:@","];
+ for (NSString *component in components) {
+ if ([component containsString:@"no-cache"] || [component containsString:@"no-store"] || [component hasSuffix:@"max-age=0"]) {
+ shouldCache = NO;
+ break;
+ } else {
+ NSRange range = [component rangeOfString:@"max-age="];
+ if (range.location != NSNotFound) {
+ NSInteger seconds = [[component substringFromIndex:range.location + range.length] integerValue];
+ staleTime = [originalDate dateByAddingTimeInterval:(NSTimeInterval)seconds];
+ }
+ }
+ }
+ if (shouldCache) {
+ if (!staleTime && originalDate) {
+ NSString *expires = ((NSHTTPURLResponse *)response).allHeaderFields[@"Expires"];
+ NSString *lastModified = ((NSHTTPURLResponse *)response).allHeaderFields[@"Last-Modified"];
+ if (expires) {
+ staleTime = [self dateWithHeaderString:expires];
+ } else if (lastModified) {
+ NSDate *lastModifiedDate = [self dateWithHeaderString:lastModified];
+ if (lastModifiedDate) {
+ NSTimeInterval interval = [originalDate timeIntervalSinceDate:lastModifiedDate] / 10;
+ staleTime = [originalDate dateByAddingTimeInterval:interval];
+ }
+ }
+ }
+ if (staleTime) {
+ @synchronized(_cacheStaleTimes) {
+ _cacheStaleTimes[cacheKey] = staleTime;
+ }
+ }
return [self addImageToCache:image forKey:cacheKey];
+ }
+ }
+}
+
+- (NSDate *)dateWithHeaderString:(NSString *)headerDateString {
+ static NSDateFormatter *formatter;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ formatter = [[NSDateFormatter alloc] init];
+ formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
+ formatter.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'";
+ formatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
+ });
+
+ return [formatter dateFromString:headerDateString];
}
@end

Libraries/Image/RCTImageEditingManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Image/RCTImageEditingManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Image/RCTImageLoader.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -24,15 +24,14 @@
- (UIImage *)imageForUrl:(NSString *)url
size:(CGSize)size
scale:(CGFloat)scale
- resizeMode:(RCTResizeMode)resizeMode
- responseDate:(NSString *)responseDate;
+ resizeMode:(RCTResizeMode)resizeMode;
- (void)addImageToCache:(UIImage *)image
URL:(NSString *)url
size:(CGSize)size
scale:(CGFloat)scale
resizeMode:(RCTResizeMode)resizeMode
- responseDate:(NSString *)responseDate;
+ response:(NSURLResponse *)response;
@end
@@ -52,6 +51,11 @@
@property (nonatomic, copy) CAKeyframeAnimation *reactKeyframeAnimation;
+/**
+ * Memory bytes of the image with the default calculation of static image or GIF. Custom calculations of decoded bytes can be assigned manually.
+ */
+@property (nonatomic, assign) NSInteger reactDecodedImageBytes;
+
@end
@interface RCTImageLoader : NSObject <RCTBridgeModule, RCTURLRequestHandler>
@@ -129,10 +133,18 @@
*/
- (RCTImageLoaderCancellationBlock)getImageSizeForURLRequest:(NSURLRequest *)imageURLRequest
block:(void(^)(NSError *error, CGSize size))completionBlock;
+/**
+ * Determines whether given image URLs are cached locally. The `requests` array is expected
+ * to contain objects convertible to NSURLRequest. The return value maps URLs to strings:
+ * "disk" for images known to be cached in non-volatile storage, "memory" for images known
+ * to be cached in memory. Dictionary items corresponding to images that are not known to be
+ * cached are simply missing.
+ */
+- (NSDictionary *)getImageCacheStatus:(NSArray *)requests;
/**
* Allows developers to set their own caching implementation for
- * decoded images as long as it conforms to the RCTImageCacheDelegate
+ * decoded images as long as it conforms to the RCTImageCache
* protocol. This method should be called in bridgeDidInitializeModule.
*/
- (void)setImageCache:(id<RCTImageCache>)cache;

Libraries/Image/RCTImageLoader.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -20,6 +20,17 @@
#import "RCTImageCache.h"
#import "RCTImageUtils.h"
+static NSInteger RCTImageBytesForImage(UIImage *image)
+{
+ CAKeyframeAnimation *keyFrameAnimation = [image reactKeyframeAnimation];
+ NSInteger singleImageBytes = image.size.width * image.size.height * image.scale * image.scale * 4;
+ if (keyFrameAnimation) {
+ return keyFrameAnimation.values.count * singleImageBytes;
+ } else {
+ return image.images ? image.images.count * singleImageBytes : singleImageBytes;
+ }
+}
+
@implementation UIImage (React)
- (CAKeyframeAnimation *)reactKeyframeAnimation
@@ -32,6 +43,20 @@
objc_setAssociatedObject(self, @selector(reactKeyframeAnimation), reactKeyframeAnimation, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
+- (NSInteger)reactDecodedImageBytes
+{
+ NSNumber *imageBytes = objc_getAssociatedObject(self, _cmd);
+ if (!imageBytes) {
+ imageBytes = @(RCTImageBytesForImage(self));
+ }
+ return [imageBytes integerValue];
+}
+
+- (void)setReactDecodedImageBytes:(NSInteger)bytes
+{
+ objc_setAssociatedObject(self, @selector(reactDecodedImageBytes), @(bytes), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
@end
@implementation RCTImageLoader
@@ -236,7 +261,7 @@
return image;
}
-- (RCTImageLoaderCancellationBlock)loadImageWithURLRequest:(NSURLRequest *)imageURLRequest
+- (RCTImageLoaderCancellationBlock) loadImageWithURLRequest:(NSURLRequest *)imageURLRequest
callback:(RCTImageLoaderCompletionBlock)callback
{
return [self loadImageWithURLRequest:imageURLRequest
@@ -321,7 +346,7 @@
resizeMode:(RCTResizeMode)resizeMode
progressBlock:(RCTImageLoaderProgressBlock)progressHandler
partialLoadBlock:(RCTImageLoaderPartialLoadBlock)partialLoadHandler
- completionBlock:(void (^)(NSError *error, id imageOrData, BOOL cacheResult, NSString *fetchDate))completionBlock
+ completionBlock:(void (^)(NSError *error, id imageOrData, BOOL cacheResult, NSURLResponse *response))completionBlock
{
{
NSMutableURLRequest *mutableRequest = [request mutableCopy];
@@ -344,15 +369,15 @@
BOOL requiresScheduling = [loadHandler respondsToSelector:@selector(requiresScheduling)] ?
[loadHandler requiresScheduling] : YES;
+ BOOL cacheResult = [loadHandler respondsToSelector:@selector(shouldCacheLoadedImages)] ?
+ [loadHandler shouldCacheLoadedImages] : YES;
+
__block atomic_bool cancelled = ATOMIC_VAR_INIT(NO);
// TODO: Protect this variable shared between threads.
__block dispatch_block_t cancelLoad = nil;
- void (^completionHandler)(NSError *, id, NSString *) = ^(NSError *error, id imageOrData, NSString *fetchDate) {
+ void (^completionHandler)(NSError *, id, NSURLResponse *) = ^(NSError *error, id imageOrData, NSURLResponse *response) {
cancelLoad = nil;
- BOOL cacheResult = [loadHandler respondsToSelector:@selector(shouldCacheLoadedImages)] ?
- [loadHandler shouldCacheLoadedImages] : YES;
-
// If we've received an image, we should try to set it synchronously,
// if it's data, do decoding on a background thread.
if (RCTIsMainQueue() && ![imageOrData isKindOfClass:[UIImage class]]) {
@@ -360,11 +385,11 @@
// expecting it, and may do expensive post-processing in the callback
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if (!atomic_load(&cancelled)) {
- completionBlock(error, imageOrData, cacheResult, fetchDate);
+ completionBlock(error, imageOrData, cacheResult, response);
}
});
} else if (!atomic_load(&cancelled)) {
- completionBlock(error, imageOrData, cacheResult, fetchDate);
+ completionBlock(error, imageOrData, cacheResult, response);
}
};
@@ -405,11 +430,23 @@
completionHandler(error, image, nil);
}];
} else {
+ UIImage *image;
+ if (cacheResult) {
+ image = [[strongSelf imageCache] imageForUrl:request.URL.absoluteString
+ size:size
+ scale:scale
+ resizeMode:resizeMode];
+ }
+
+ if (image) {
+ completionHandler(nil, image, nil);
+ } else {
// Use networking module to load image
cancelLoad = [strongSelf _loadURLRequest:request
progressBlock:progressHandler
completionBlock:completionHandler];
}
+ }
});
return ^{
@@ -427,7 +464,7 @@
- (RCTImageLoaderCancellationBlock)_loadURLRequest:(NSURLRequest *)request
progressBlock:(RCTImageLoaderProgressBlock)progressHandler
- completionBlock:(void (^)(NSError *error, id imageOrData, NSString *fetchDate))completionHandler
+ completionBlock:(void (^)(NSError *error, id imageOrData, NSURLResponse *response))completionHandler
{
// Check if networking module is available
if (RCT_DEBUG && ![_bridge respondsToSelector:@selector(networking)]) {
@@ -449,18 +486,17 @@
RCTURLRequestCompletionBlock processResponse = ^(NSURLResponse *response, NSData *data, NSError *error) {
// Check for system errors
if (error) {
- completionHandler(error, nil, nil);
+ completionHandler(error, nil, response);
return;
} else if (!response) {
- completionHandler(RCTErrorWithMessage(@"Response metadata error"), nil, nil);
+ completionHandler(RCTErrorWithMessage(@"Response metadata error"), nil, response);
return;
} else if (!data) {
- completionHandler(RCTErrorWithMessage(@"Unknown image download error"), nil, nil);
+ completionHandler(RCTErrorWithMessage(@"Unknown image download error"), nil, response);
return;
}
// Check for http errors
- NSString *responseDate;
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSInteger statusCode = ((NSHTTPURLResponse *)response).statusCode;
if (statusCode != 200) {
@@ -468,15 +504,13 @@
NSDictionary *userInfo = @{NSLocalizedDescriptionKey: errorMessage};
completionHandler([[NSError alloc] initWithDomain:NSURLErrorDomain
code:statusCode
- userInfo:userInfo], nil, nil);
+ userInfo:userInfo], nil, response);
return;
}
-
- responseDate = ((NSHTTPURLResponse *)response).allHeaderFields[@"Date"];
}
// Call handler
- completionHandler(nil, data, responseDate);
+ completionHandler(nil, data, response);
};
// Download image
@@ -498,7 +532,7 @@
} else {
someError = RCTErrorWithMessage(@"Unknown image download error");
}
- completionHandler(someError, nil, nil);
+ completionHandler(someError, nil, response);
[strongSelf dequeueTasks];
return;
}
@@ -564,7 +598,7 @@
};
__weak RCTImageLoader *weakSelf = self;
- void (^completionHandler)(NSError *, id, BOOL, NSString *) = ^(NSError *error, id imageOrData, BOOL cacheResult, NSString *fetchDate) {
+ void (^completionHandler)(NSError *, id, BOOL, NSURLResponse *) = ^(NSError *error, id imageOrData, BOOL cacheResult, NSURLResponse *response) {
__typeof(self) strongSelf = weakSelf;
if (atomic_load(&cancelled) || !strongSelf) {
return;
@@ -576,20 +610,6 @@
return;
}
- // Check decoded image cache
- if (cacheResult) {
- UIImage *image = [[strongSelf imageCache] imageForUrl:imageURLRequest.URL.absoluteString
- size:size
- scale:scale
- resizeMode:resizeMode
- responseDate:fetchDate];
- if (image) {
- cancelLoad = nil;
- completionBlock(nil, image);
- return;
- }
- }
-
RCTImageLoaderCompletionBlock decodeCompletionHandler = ^(NSError *error_, UIImage *image) {
if (cacheResult && image) {
// Store decoded image in cache
@@ -598,7 +618,7 @@
size:size
scale:scale
resizeMode:resizeMode
- responseDate:fetchDate];
+ response:response];
}
cancelLoad = nil;
@@ -732,7 +752,7 @@
- (RCTImageLoaderCancellationBlock)getImageSizeForURLRequest:(NSURLRequest *)imageURLRequest
block:(void(^)(NSError *error, CGSize size))callback
{
- void (^completion)(NSError *, id, BOOL, NSString *) = ^(NSError *error, id imageOrData, BOOL cacheResult, NSString *fetchDate) {
+ void (^completion)(NSError *, id, BOOL, NSURLResponse *) = ^(NSError *error, id imageOrData, BOOL cacheResult, NSURLResponse *response) {
CGSize size;
if ([imageOrData isKindOfClass:[NSData class]]) {
NSDictionary *meta = RCTGetImageMetadata(imageOrData);
@@ -779,6 +799,25 @@
completionBlock:completion];
}
+- (NSDictionary *)getImageCacheStatus:(NSArray *)requests
+{
+ NSMutableDictionary *results = [NSMutableDictionary dictionary];
+ for (id request in requests) {
+ NSURLRequest *urlRequest = [RCTConvert NSURLRequest:request];
+ if (urlRequest) {
+ NSCachedURLResponse *cachedResponse = [NSURLCache.sharedURLCache cachedResponseForRequest:urlRequest];
+ if (cachedResponse) {
+ if (cachedResponse.storagePolicy == NSURLCacheStorageAllowedInMemoryOnly) {
+ [results setObject:@"memory" forKey:urlRequest.URL.absoluteString];
+ } else {
+ [results setObject:@"disk" forKey:urlRequest.URL.absoluteString];
+ }
+ }
+ }
+ }
+ return results;
+}
+
#pragma mark - RCTURLRequestHandler
- (BOOL)canHandleRequest:(NSURLRequest *)request
@@ -790,8 +829,9 @@
// but we'd have to run the logic both in RCTPhotoLibraryImageLoader and
// RCTAssetsLibraryRequestHandler. Once we drop iOS7 though, we'd drop
// RCTAssetsLibraryRequestHandler and can move it there.
- static NSRegularExpression *videoRegex = nil;
- if (!videoRegex) {
+ static NSRegularExpression *videoRegex;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
NSError *error = nil;
videoRegex = [NSRegularExpression regularExpressionWithPattern:@"(?:&|^)ext=MOV(?:&|$)"
options:NSRegularExpressionCaseInsensitive
@@ -799,12 +839,15 @@
if (error) {
RCTLogError(@"%@", error);
}
- }
+ });
NSString *query = requestURL.query;
- if (query != nil && [videoRegex firstMatchInString:query
+ if (
+ query != nil &&
+ [videoRegex firstMatchInString:query
options:0
- range:NSMakeRange(0, query.length)]) {
+ range:NSMakeRange(0, query.length)]
+ ) {
return NO;
}

Libraries/Image/RCTImageShadowView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Image/RCTImageShadowView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Image/RCTImageStoreManager.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

Libraries/Image/RCTImageStoreManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Image/RCTImageUtils.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

Libraries/Image/RCTImageUtils.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Image/RCTImageView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Image/RCTImageView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Image/RCTImageViewManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Image/RCTImageViewManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -82,4 +82,11 @@
}];
}
+RCT_EXPORT_METHOD(queryCache:(NSArray *)requests
+ resolve:(RCTPromiseResolveBlock)resolve
+ reject:(RCTPromiseRejectBlock)reject)
+{
+ resolve([self.bridge.imageLoader getImageCacheStatus:requests]);
+}
+
@end

Libraries/Image/RCTLocalAssetImageLoader.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Image/RCTLocalAssetImageLoader.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Image/RCTResizeMode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Image/RCTResizeMode.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Image/RelativeImageStub.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Image/resolveAssetSource.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Image/TextInlineImageNativeComponent.js

@@ -0,0 +1,17 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow
+ */
+
+'use strict';
+
+const requireNativeComponent = require('requireNativeComponent');
+
+const TextInlineImage = requireNativeComponent('RCTTextInlineImage');
+
+module.exports = TextInlineImage;

Libraries/Inspector/BorderBox.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Inspector/BoxInspector.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -87,12 +87,6 @@
textAlign: 'left',
top: -3,
},
- buffer: {
- fontSize: 10,
- color: 'yellow',
- flex: 1,
- textAlign: 'center',
- },
innerText: {
color: 'yellow',
fontSize: 12,

Libraries/Inspector/ElementBox.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Inspector/ElementProperties.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,7 +11,6 @@
'use strict';
const BoxInspector = require('BoxInspector');
-const PropTypes = require('prop-types');
const React = require('React');
const StyleInspector = require('StyleInspector');
const StyleSheet = require('StyleSheet');
@@ -24,32 +23,23 @@
const mapWithSeparator = require('mapWithSeparator');
const openFileInEditor = require('openFileInEditor');
-import type {DangerouslyImpreciseStyleProp} from 'StyleSheet';
+import type {ViewStyleProp} from 'StyleSheet';
-class ElementProperties extends React.Component<{
- hierarchy: Array<$FlowFixMe>,
- style?: DangerouslyImpreciseStyleProp,
- source?: {
+type Props = $ReadOnly<{|
+ hierarchy: Array<{|name: string|}>,
+ style?: ?ViewStyleProp,
+ source?: ?{
fileName?: string,
lineNumber?: number,
},
-}> {
- static propTypes = {
- hierarchy: PropTypes.array.isRequired,
- style: PropTypes.oneOfType([
- PropTypes.object,
- PropTypes.array,
- PropTypes.number,
- ]),
- source: PropTypes.shape({
- fileName: PropTypes.string,
- lineNumber: PropTypes.number,
- }),
- };
+ frame?: ?Object,
+ selection?: ?number,
+ setSelection?: number => mixed,
+|}>;
+class ElementProperties extends React.Component<Props> {
render() {
const style = flattenStyle(this.props.style);
- // $FlowFixMe found when converting React.createClass to ES6
const selection = this.props.selection;
let openFileButton;
const source = this.props.source;
@@ -96,10 +86,7 @@
<StyleInspector style={style} />
{openFileButton}
</View>
- {
- // $FlowFixMe found when converting React.createClass to ES6
- <BoxInspector style={style} frame={this.props.frame} />
- }
+ {<BoxInspector style={style} frame={this.props.frame} />}
</View>
</View>
</TouchableWithoutFeedback>

Libraries/Inspector/Inspector.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -21,7 +21,7 @@
const UIManager = require('UIManager');
const View = require('View');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
export type ReactRenderer = {
getInspectorDataForViewTag: (viewTag: number) => Object,
@@ -47,14 +47,20 @@
function getInspectorDataForViewTag(touchedViewTag: number) {
for (let i = 0; i < renderers.length; i++) {
const renderer = renderers[i];
+ if (
+ Object.prototype.hasOwnProperty.call(
+ renderer,
+ 'getInspectorDataForViewTag',
+ )
+ ) {
const inspectorData = renderer.getInspectorDataForViewTag(touchedViewTag);
if (inspectorData.hierarchy.length > 0) {
return inspectorData;
}
}
+ }
throw new Error('Expected to find at least one React renderer.');
}
-
class Inspector extends React.Component<
{
inspectedViewTag: ?number,
@@ -112,9 +118,6 @@
attachToDevtools = (agent: Object) => {
let _hideWait = null;
const hlSub = agent.sub('highlight', ({node, name, props}) => {
- /* $FlowFixMe(>=0.63.0 site=react_native_fb) This comment suppresses an
- * error found when Flow v0.63 was deployed. To see the error delete this
- * comment and run Flow. */
clearTimeout(_hideWait);
if (typeof node !== 'number') {

Libraries/Inspector/InspectorOverlay.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -12,34 +12,27 @@
const Dimensions = require('Dimensions');
const ElementBox = require('ElementBox');
-const PropTypes = require('prop-types');
const React = require('React');
const StyleSheet = require('StyleSheet');
const UIManager = require('UIManager');
const View = require('View');
-type EventLike = {
- nativeEvent: Object,
-};
+import type {PressEvent} from 'CoreEventTypes';
+import type {ViewStyleProp} from 'StyleSheet';
-class InspectorOverlay extends React.Component<{
- inspected?: {
+type Inspected = $ReadOnly<{|
frame?: Object,
- style?: any,
- },
- inspectedViewTag?: number,
- onTouchViewTag: (tag: number, frame: Object, pointerY: number) => void,
-}> {
- static propTypes = {
- inspected: PropTypes.shape({
- frame: PropTypes.object,
- style: PropTypes.any,
- }),
- inspectedViewTag: PropTypes.number,
- onTouchViewTag: PropTypes.func.isRequired,
- };
+ style?: ViewStyleProp,
+|}>;
+
+type Props = $ReadOnly<{|
+ inspected?: Inspected,
+ inspectedViewTag?: ?number,
+ onTouchViewTag: (tag: number, frame: Object, pointerY: number) => mixed,
+|}>;
- findViewForTouchEvent = (e: EventLike) => {
+class InspectorOverlay extends React.Component<Props> {
+ findViewForTouchEvent = (e: PressEvent) => {
const {locationX, locationY} = e.nativeEvent.touches[0];
UIManager.findSubviewIn(
this.props.inspectedViewTag,
@@ -54,7 +47,7 @@
);
};
- shouldSetResponser = (e: EventLike): boolean => {
+ shouldSetResponser = (e: PressEvent): boolean => {
this.findViewForTouchEvent(e);
return true;
};

Libraries/Inspector/InspectorPanel.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -14,14 +14,43 @@
const NetworkOverlay = require('NetworkOverlay');
const PerformanceOverlay = require('PerformanceOverlay');
const React = require('React');
-const PropTypes = require('prop-types');
const ScrollView = require('ScrollView');
const StyleSheet = require('StyleSheet');
const Text = require('Text');
const TouchableHighlight = require('TouchableHighlight');
const View = require('View');
-class InspectorPanel extends React.Component<$FlowFixMeProps> {
+import type {ViewStyleProp} from 'StyleSheet';
+
+type Props = $ReadOnly<{|
+ devtoolsIsOpen: boolean,
+ inspecting: boolean,
+ setInspecting: (val: boolean) => void,
+ perfing: boolean,
+ setPerfing: (val: boolean) => void,
+ touchTargeting: boolean,
+ setTouchTargeting: (val: boolean) => void,
+ networking: boolean,
+ setNetworking: (val: boolean) => void,
+ hierarchy?: ?Array<{|name: string|}>,
+ selection?: ?number,
+ setSelection: number => mixed,
+ inspected?: ?$ReadOnly<{|
+ style?: ?ViewStyleProp,
+ frame?: ?$ReadOnly<{|
+ top?: ?number,
+ left?: ?number,
+ width?: ?number,
+ height: ?number,
+ |}>,
+ source?: ?{|
+ fileName?: string,
+ lineNumber?: number,
+ |},
+ |}>,
+|}>;
+
+class InspectorPanel extends React.Component<Props> {
renderWaiting() {
if (this.props.inspecting) {
return (
@@ -40,6 +69,7 @@
style={this.props.inspected.style}
frame={this.props.inspected.frame}
source={this.props.inspected.source}
+ // $FlowFixMe: Hierarchy should be non-nullable
hierarchy={this.props.hierarchy}
selection={this.props.selection}
setSelection={this.props.setSelection}
@@ -57,22 +87,22 @@
<View style={styles.container}>
{!this.props.devtoolsIsOpen && contents}
<View style={styles.buttonRow}>
- <Button
+ <InspectorPanelButton
title={'Inspect'}
pressed={this.props.inspecting}
onClick={this.props.setInspecting}
/>
- <Button
+ <InspectorPanelButton
title={'Perf'}
pressed={this.props.perfing}
onClick={this.props.setPerfing}
/>
- <Button
+ <InspectorPanelButton
title={'Network'}
pressed={this.props.networking}
onClick={this.props.setNetworking}
/>
- <Button
+ <InspectorPanelButton
title={'Touchables'}
pressed={this.props.touchTargeting}
onClick={this.props.setTouchTargeting}
@@ -83,20 +113,13 @@
}
}
-InspectorPanel.propTypes = {
- devtoolsIsOpen: PropTypes.bool,
- inspecting: PropTypes.bool,
- setInspecting: PropTypes.func,
- inspected: PropTypes.object,
- perfing: PropTypes.bool,
- setPerfing: PropTypes.func,
- touchTargeting: PropTypes.bool,
- setTouchTargeting: PropTypes.func,
- networking: PropTypes.bool,
- setNetworking: PropTypes.func,
-};
+type InspectorPanelButtonProps = $ReadOnly<{|
+ onClick: (val: boolean) => void,
+ pressed: boolean,
+ title: string,
+|}>;
-class Button extends React.Component<$FlowFixMeProps> {
+class InspectorPanelButton extends React.Component<InspectorPanelButtonProps> {
render() {
return (
<TouchableHighlight

Libraries/Inspector/NetworkOverlay.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,7 +10,7 @@
'use strict';
-const ListView = require('ListView');
+const FlatList = require('FlatList');
const React = require('React');
const ScrollView = require('ScrollView');
const StyleSheet = require('StyleSheet');
@@ -21,12 +21,12 @@
const XHRInterceptor = require('XHRInterceptor');
const LISTVIEW_CELL_HEIGHT = 15;
-const SEPARATOR_THICKNESS = 2;
// Global id for the intercepted XMLHttpRequest objects.
let nextXHRId = 0;
type NetworkRequestInfo = {
+ id: number,
type?: string,
url?: string,
method?: string,
@@ -46,61 +46,57 @@
serverError?: Object,
};
+type Props = $ReadOnly<{||}>;
+type State = {|
+ detailRowId: ?number,
+ requests: Array<NetworkRequestInfo>,
+|};
+
+function getStringByValue(value: any): string {
+ if (value === undefined) {
+ return 'undefined';
+ }
+ if (typeof value === 'object') {
+ return JSON.stringify(value);
+ }
+ if (typeof value === 'string' && value.length > 500) {
+ return String(value)
+ .substr(0, 500)
+ .concat('\n***TRUNCATED TO 500 CHARACTERS***');
+ }
+ return value;
+}
+
+function getTypeShortName(type: any): string {
+ if (type === 'XMLHttpRequest') {
+ return 'XHR';
+ } else if (type === 'WebSocket') {
+ return 'WS';
+ }
+
+ return '';
+}
+
+function keyExtractor(request: NetworkRequestInfo): string {
+ return String(request.id);
+}
+
/**
* Show all the intercepted network requests over the InspectorPanel.
*/
-class NetworkOverlay extends React.Component<
- Object,
- {
- dataSource: ListView.DataSource,
- newDetailInfo: boolean,
- detailRowID: ?number,
- },
-> {
- _requests: Array<NetworkRequestInfo>;
- _listViewDataSource: ListView.DataSource;
- _listView: ?ListView;
- _listViewHighlighted: boolean;
- _listViewHeight: number;
- _scrollView: ?ScrollView;
- _detailViewItems: Array<Array<React.Element<any>>>;
- _listViewOnLayout: (event: Event) => void;
- _captureRequestListView: (listRef: ?ListView) => void;
- _captureDetailScrollView: (scrollRef: ?ScrollView) => void;
- _renderRow: (
- rowData: NetworkRequestInfo,
- sectionID: number,
- rowID: number,
- highlightRow: (sectionID: number, rowID: number) => void,
- ) => React.Element<any>;
- _closeButtonClicked: () => void;
- // Map of `socketId` -> `index in `_requests``.
- _socketIdMap: Object;
- // Map of `xhr._index` -> `index in `_requests``.
- _xhrIdMap: {[key: number]: number};
-
- constructor(props: Object) {
- super(props);
- this._requests = [];
- this._detailViewItems = [];
- this._listViewDataSource = new ListView.DataSource({
- rowHasChanged: (r1, r2) => r1 !== r2,
- });
- this.state = {
- dataSource: this._listViewDataSource.cloneWithRows([]),
- newDetailInfo: false,
- detailRowID: null,
+class NetworkOverlay extends React.Component<Props, State> {
+ _requestsListView: ?React.ElementRef<typeof FlatList>;
+ _detailScrollView: ?React.ElementRef<typeof ScrollView>;
+
+ // Map of `socketId` -> `index in `this.state.requests`.
+ _socketIdMap = {};
+ // Map of `xhr._index` -> `index in `this.state.requests`.
+ _xhrIdMap: {[key: number]: number} = {};
+
+ state = {
+ detailRowId: null,
+ requests: [],
};
- this._listViewHighlighted = false;
- this._listViewHeight = 0;
- this._captureRequestListView = this._captureRequestListView.bind(this);
- this._captureDetailScrollView = this._captureDetailScrollView.bind(this);
- this._listViewOnLayout = this._listViewOnLayout.bind(this);
- this._renderRow = this._renderRow.bind(this);
- this._closeButtonClicked = this._closeButtonClicked.bind(this);
- this._socketIdMap = {};
- this._xhrIdMap = {};
- }
_enableXHRInterception(): void {
if (XHRInterceptor.isInterceptorEnabled()) {
@@ -112,20 +108,20 @@
// to the xhr object as a private `_index` property to identify it,
// so that we can distinguish different xhr objects in callbacks.
xhr._index = nextXHRId++;
- const xhrIndex = this._requests.length;
+ const xhrIndex = this.state.requests.length;
this._xhrIdMap[xhr._index] = xhrIndex;
const _xhr: NetworkRequestInfo = {
+ id: xhrIndex,
type: 'XMLHttpRequest',
method: method,
url: url,
};
- this._requests.push(_xhr);
- this._detailViewItems.push([]);
- this._genDetailViewItem(xhrIndex);
this.setState(
- {dataSource: this._listViewDataSource.cloneWithRows(this._requests)},
- this._scrollToBottom(),
+ {
+ requests: this.state.requests.concat(_xhr),
+ },
+ this._scrollRequestsToBottom,
);
});
@@ -134,12 +130,15 @@
if (xhrIndex === -1) {
return;
}
- const networkInfo = this._requests[xhrIndex];
- if (!networkInfo.requestHeaders) {
- networkInfo.requestHeaders = {};
+
+ this.setState(({requests}) => {
+ const networkRequestInfo = requests[xhrIndex];
+ if (!networkRequestInfo.requestHeaders) {
+ networkRequestInfo.requestHeaders = {};
}
- networkInfo.requestHeaders[header] = value;
- this._genDetailViewItem(xhrIndex);
+ networkRequestInfo.requestHeaders[header] = value;
+ return {requests};
+ });
});
XHRInterceptor.setSendCallback((data, xhr) => {
@@ -147,8 +146,12 @@
if (xhrIndex === -1) {
return;
}
- this._requests[xhrIndex].dataSent = data;
- this._genDetailViewItem(xhrIndex);
+
+ this.setState(({requests}) => {
+ const networkRequestInfo = requests[xhrIndex];
+ networkRequestInfo.dataSent = data;
+ return {requests};
+ });
});
XHRInterceptor.setHeaderReceivedCallback(
@@ -157,11 +160,14 @@
if (xhrIndex === -1) {
return;
}
- const networkInfo = this._requests[xhrIndex];
- networkInfo.responseContentType = type;
- networkInfo.responseSize = size;
- networkInfo.responseHeaders = responseHeaders;
- this._genDetailViewItem(xhrIndex);
+
+ this.setState(({requests}) => {
+ const networkRequestInfo = requests[xhrIndex];
+ networkRequestInfo.responseContentType = type;
+ networkRequestInfo.responseSize = size;
+ networkRequestInfo.responseHeaders = responseHeaders;
+ return {requests};
+ });
},
);
@@ -171,13 +177,17 @@
if (xhrIndex === -1) {
return;
}
- const networkInfo = this._requests[xhrIndex];
- networkInfo.status = status;
- networkInfo.timeout = timeout;
- networkInfo.response = response;
- networkInfo.responseURL = responseURL;
- networkInfo.responseType = responseType;
- this._genDetailViewItem(xhrIndex);
+
+ this.setState(({requests}) => {
+ const networkRequestInfo = requests[xhrIndex];
+ networkRequestInfo.status = status;
+ networkRequestInfo.timeout = timeout;
+ networkRequestInfo.response = response;
+ networkRequestInfo.responseURL = responseURL;
+ networkRequestInfo.responseType = responseType;
+
+ return {requests};
+ });
},
);
@@ -192,19 +202,19 @@
// Show the WebSocket request item in listView when 'connect' is called.
WebSocketInterceptor.setConnectCallback(
(url, protocols, options, socketId) => {
- const socketIndex = this._requests.length;
+ const socketIndex = this.state.requests.length;
this._socketIdMap[socketId] = socketIndex;
const _webSocket: NetworkRequestInfo = {
+ id: socketIndex,
type: 'WebSocket',
url: url,
protocols: protocols,
};
- this._requests.push(_webSocket);
- this._detailViewItems.push([]);
- this._genDetailViewItem(socketIndex);
this.setState(
- {dataSource: this._listViewDataSource.cloneWithRows(this._requests)},
- this._scrollToBottom(),
+ {
+ requests: this.state.requests.concat(_webSocket),
+ },
+ this._scrollRequestsToBottom,
);
},
);
@@ -216,10 +226,13 @@
return;
}
if (statusCode !== null && closeReason !== null) {
- this._requests[socketIndex].status = statusCode;
- this._requests[socketIndex].closeReason = closeReason;
+ this.setState(({requests}) => {
+ const networkRequestInfo = requests[socketIndex];
+ networkRequestInfo.status = statusCode;
+ networkRequestInfo.closeReason = closeReason;
+ return {requests};
+ });
}
- this._genDetailViewItem(socketIndex);
},
);
@@ -228,12 +241,17 @@
if (socketIndex === undefined) {
return;
}
- if (!this._requests[socketIndex].messages) {
- this._requests[socketIndex].messages = '';
+
+ this.setState(({requests}) => {
+ const networkRequestInfo = requests[socketIndex];
+
+ if (!networkRequestInfo.messages) {
+ networkRequestInfo.messages = '';
}
- this._requests[socketIndex].messages +=
- 'Sent: ' + JSON.stringify(data) + '\n';
- this._genDetailViewItem(socketIndex);
+ networkRequestInfo.messages += 'Sent: ' + JSON.stringify(data) + '\n';
+
+ return {requests};
+ });
});
WebSocketInterceptor.setOnMessageCallback((socketId, message) => {
@@ -241,12 +259,18 @@
if (socketIndex === undefined) {
return;
}
- if (!this._requests[socketIndex].messages) {
- this._requests[socketIndex].messages = '';
+
+ this.setState(({requests}) => {
+ const networkRequestInfo = requests[socketIndex];
+
+ if (!networkRequestInfo.messages) {
+ networkRequestInfo.messages = '';
}
- this._requests[socketIndex].messages +=
+ networkRequestInfo.messages +=
'Received: ' + JSON.stringify(message) + '\n';
- this._genDetailViewItem(socketIndex);
+
+ return {requests};
+ });
});
WebSocketInterceptor.setOnCloseCallback((socketId, message) => {
@@ -254,8 +278,13 @@
if (socketIndex === undefined) {
return;
}
- this._requests[socketIndex].serverClose = message;
- this._genDetailViewItem(socketIndex);
+
+ this.setState(({requests}) => {
+ const networkRequestInfo = requests[socketIndex];
+ networkRequestInfo.serverClose = message;
+
+ return {requests};
+ });
});
WebSocketInterceptor.setOnErrorCallback((socketId, message) => {
@@ -263,8 +292,13 @@
if (socketIndex === undefined) {
return;
}
- this._requests[socketIndex].serverError = message;
- this._genDetailViewItem(socketIndex);
+
+ this.setState(({requests}) => {
+ const networkRequestInfo = requests[socketIndex];
+ networkRequestInfo.serverError = message;
+
+ return {requests};
+ });
});
// Fire above callbacks.
@@ -281,126 +315,100 @@
WebSocketInterceptor.disableInterception();
}
- _renderRow(
- rowData: NetworkRequestInfo,
- sectionID: number,
- rowID: number,
- highlightRow: (sectionID: number, rowID: number) => void,
- ): React.Element<any> {
- let urlCellViewStyle = styles.urlEvenCellView;
- let methodCellViewStyle = styles.methodEvenCellView;
- if (rowID % 2 === 1) {
- urlCellViewStyle = styles.urlOddCellView;
- methodCellViewStyle = styles.methodOddCellView;
- }
+ _renderItem = ({item, index}): ?React.Element<any> => {
+ const tableRowViewStyle = [
+ styles.tableRow,
+ index % 2 === 1 ? styles.tableRowOdd : styles.tableRowEven,
+ index === this.state.detailRowId && styles.tableRowPressed,
+ ];
+ const urlCellViewStyle = styles.urlCellView;
+ const methodCellViewStyle = styles.methodCellView;
+
return (
<TouchableHighlight
onPress={() => {
- this._pressRow(rowID);
- highlightRow(sectionID, rowID);
+ this._pressRow(index);
}}>
<View>
- <View style={styles.tableRow}>
+ <View style={tableRowViewStyle}>
<View style={urlCellViewStyle}>
<Text style={styles.cellText} numberOfLines={1}>
- {rowData.url}
+ {item.url}
</Text>
</View>
<View style={methodCellViewStyle}>
<Text style={styles.cellText} numberOfLines={1}>
- {this._getTypeShortName(rowData.type)}
+ {getTypeShortName(item.type)}
</Text>
</View>
</View>
</View>
</TouchableHighlight>
);
- }
+ };
- _renderSeperator(
- sectionID: number,
- rowID: number,
- adjacentRowHighlighted: boolean,
- ): React.Element<any> {
+ _renderItemDetail(id) {
+ const requestItem = this.state.requests[id];
+ const details = Object.keys(requestItem).map(key => {
+ if (key === 'id') {
+ return;
+ }
return (
- <View
- key={`${sectionID}-${rowID}`}
- style={{
- height: adjacentRowHighlighted ? SEPARATOR_THICKNESS : 0,
- backgroundColor: adjacentRowHighlighted ? '#3B5998' : '#CCCCCC',
- }}
- />
+ <View style={styles.detailViewRow} key={key}>
+ <Text style={[styles.detailViewText, styles.detailKeyCellView]}>
+ {key}
+ </Text>
+ <Text style={[styles.detailViewText, styles.detailValueCellView]}>
+ {getStringByValue(requestItem[key])}
+ </Text>
+ </View>
);
- }
+ });
- _scrollToBottom(): void {
- if (this._listView) {
- const scrollResponder = this._listView.getScrollResponder();
- if (scrollResponder) {
- const scrollY = Math.max(
- this._requests.length * LISTVIEW_CELL_HEIGHT +
- (this._listViewHighlighted ? 2 * SEPARATOR_THICKNESS : 0) -
- this._listViewHeight,
- 0,
+ return (
+ <View>
+ <TouchableHighlight
+ style={styles.closeButton}
+ onPress={this._closeButtonClicked}>
+ <View>
+ <Text style={styles.closeButtonText}>v</Text>
+ </View>
+ </TouchableHighlight>
+ <ScrollView
+ style={styles.detailScrollView}
+ ref={scrollRef => (this._detailScrollView = scrollRef)}>
+ {details}
+ </ScrollView>
+ </View>
);
- scrollResponder.scrollResponderScrollTo({
- x: 0,
- y: scrollY,
- animated: true,
- });
- }
- }
}
- _captureRequestListView(listRef: ?ListView): void {
- this._listView = listRef;
+ _scrollRequestsToBottom(): void {
+ if (this._requestsListView) {
+ this._requestsListView.scrollToEnd();
}
-
- _listViewOnLayout(event: any): void {
- const {height} = event.nativeEvent.layout;
- this._listViewHeight = height;
}
/**
* Popup a scrollView to dynamically show detailed information of
* the request, when pressing a row in the network flow listView.
*/
- _pressRow(rowID: number): void {
- this._listViewHighlighted = true;
- this.setState({detailRowID: rowID}, this._scrollToTop());
+ _pressRow(rowId: number): void {
+ this.setState({detailRowId: rowId}, this._scrollDetailToTop);
}
- _scrollToTop(): void {
- if (this._scrollView) {
- this._scrollView.scrollTo({
+ _scrollDetailToTop = (): void => {
+ if (this._detailScrollView) {
+ this._detailScrollView.scrollTo({
y: 0,
animated: false,
});
}
- }
-
- _captureDetailScrollView(scrollRef: ?ScrollView): void {
- this._scrollView = scrollRef;
- }
-
- _closeButtonClicked() {
- this.setState({detailRowID: null});
- }
+ };
- _getStringByValue(value: any): string {
- if (value === undefined) {
- return 'undefined';
- }
- if (typeof value === 'object') {
- return JSON.stringify(value);
- }
- if (typeof value === 'string' && value.length > 500) {
- return String(value)
- .substr(0, 500)
- .concat('\n***TRUNCATED TO 500 CHARACTERS***');
- }
- return value;
- }
+ _closeButtonClicked = () => {
+ this.setState({detailRowId: null});
+ };
_getRequestIndexByXHRID(index: number): number {
if (index === undefined) {
@@ -414,68 +422,14 @@
}
}
- _getTypeShortName(type: any): string {
- if (type === 'XMLHttpRequest') {
- return 'XHR';
- } else if (type === 'WebSocket') {
- return 'WS';
- }
-
- return '';
- }
+ render(): React.Node {
+ const {requests, detailRowId} = this.state;
- /**
- * Generate a list of views containing network request information for
- * a XHR object, to be shown in the detail scrollview. This function
- * should be called every time there is a new update of the XHR object,
- * in order to show network request/response information in real time.
- */
- _genDetailViewItem(index: number): void {
- this._detailViewItems[index] = [];
- const detailViewItem = this._detailViewItems[index];
- const requestItem = this._requests[index];
- for (let key in requestItem) {
- detailViewItem.push(
- <View style={styles.detailViewRow} key={key}>
- <Text style={[styles.detailViewText, styles.detailKeyCellView]}>
- {key}
- </Text>
- <Text style={[styles.detailViewText, styles.detailValueCellView]}>
- {this._getStringByValue(requestItem[key])}
- </Text>
- </View>,
- );
- }
- // Re-render if this network request is showing in the detail view.
- if (
- this.state.detailRowID != null &&
- Number(this.state.detailRowID) === index
- ) {
- this.setState({newDetailInfo: true});
- }
- }
-
- render() {
return (
<View style={styles.container}>
- {this.state.detailRowID != null && (
- <TouchableHighlight
- style={styles.closeButton}
- onPress={this._closeButtonClicked}>
- <View>
- <Text style={styles.clostButtonText}>v</Text>
- </View>
- </TouchableHighlight>
- )}
- {this.state.detailRowID != null && (
- <ScrollView
- style={styles.detailScrollView}
- ref={this._captureDetailScrollView}>
- {this._detailViewItems[this.state.detailRowID]}
- </ScrollView>
- )}
+ {detailRowId != null && this._renderItemDetail(detailRowId)}
<View style={styles.listViewTitle}>
- {this._requests.length > 0 && (
+ {requests.length > 0 && (
<View style={styles.tableRow}>
<View style={styles.urlTitleCellView}>
<Text style={styles.cellText} numberOfLines={1}>
@@ -490,15 +444,14 @@
</View>
)}
</View>
- <ListView
+
+ <FlatList
+ ref={listRef => (this._requestsListView = listRef)}
style={styles.listView}
- ref={this._captureRequestListView}
- dataSource={this.state.dataSource}
- renderRow={this._renderRow}
- enableEmptySections={true}
- renderSeparator={this._renderSeperator}
- // $FlowFixMe Found when typing ListView
- onLayout={this._listViewOnLayout}
+ data={requests}
+ renderItem={this._renderItem}
+ keyExtractor={keyExtractor}
+ extraData={this.state}
/>
</View>
);
@@ -522,6 +475,16 @@
tableRow: {
flexDirection: 'row',
flex: 1,
+ height: LISTVIEW_CELL_HEIGHT,
+ },
+ tableRowEven: {
+ backgroundColor: '#555',
+ },
+ tableRowOdd: {
+ backgroundColor: '#000',
+ },
+ tableRowPressed: {
+ backgroundColor: '#3B5998',
},
cellText: {
color: 'white',
@@ -550,41 +513,20 @@
flex: 5,
paddingLeft: 3,
},
- methodOddCellView: {
- height: 15,
- borderColor: '#DCD7CD',
- borderRightWidth: 1,
- alignItems: 'center',
- justifyContent: 'center',
- backgroundColor: '#000',
- flex: 1,
- },
- urlOddCellView: {
- height: 15,
- borderColor: '#DCD7CD',
- borderLeftWidth: 1,
- borderRightWidth: 1,
- justifyContent: 'center',
- backgroundColor: '#000',
- flex: 5,
- paddingLeft: 3,
- },
- methodEvenCellView: {
+ methodCellView: {
height: 15,
borderColor: '#DCD7CD',
borderRightWidth: 1,
alignItems: 'center',
justifyContent: 'center',
- backgroundColor: '#888',
flex: 1,
},
- urlEvenCellView: {
+ urlCellView: {
height: 15,
borderColor: '#DCD7CD',
borderLeftWidth: 1,
borderRightWidth: 1,
justifyContent: 'center',
- backgroundColor: '#888',
flex: 5,
paddingLeft: 3,
},
@@ -608,7 +550,7 @@
color: 'white',
fontSize: 11,
},
- clostButtonText: {
+ closeButtonText: {
color: 'white',
fontSize: 10,
},

Libraries/Inspector/PerformanceOverlay.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Inspector/resolveBoxStyle.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Inspector/StyleInspector.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -53,11 +53,6 @@
container: {
flexDirection: 'row',
},
- row: {
- flexDirection: 'row',
- alignItems: 'center',
- justifyContent: 'space-around',
- },
attr: {
fontSize: 10,
color: '#ccc',

Libraries/Interaction/Batchinator.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Interaction/BridgeSpyStallHandler.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Interaction/FrameRateLogger.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -12,7 +12,7 @@
const NativeModules = require('NativeModules');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
/**
* Flow API for native FrameRateLogger module. If the native module is not installed, function calls

Libraries/Interaction/InteractionManager.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -12,14 +12,10 @@
const BatchedBridge = require('BatchedBridge');
const EventEmitter = require('EventEmitter');
-const Set = require('Set');
const TaskQueue = require('TaskQueue');
const infoLog = require('infoLog');
-const invariant = require('fbjs/lib/invariant');
-/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
- * found when Flow v0.54 was deployed. To see the error delete this comment and
- * run Flow. */
+const invariant = require('invariant');
const keyMirror = require('fbjs/lib/keyMirror');
type Handle = number;

Libraries/Interaction/InteractionMixin.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Interaction/InteractionStallDebugger.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Interaction/JSEventLoopWatchdog.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Interaction/PanResponder.js

@@ -1,9 +1,10 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
*
+ * @flow
* @format
*/
@@ -12,6 +13,8 @@
const InteractionManager = require('./InteractionManager');
const TouchHistoryMath = require('./TouchHistoryMath');
+import type {PressEvent} from 'CoreEventTypes';
+
const currentCentroidXOfTouchesChangedAfter =
TouchHistoryMath.currentCentroidXOfTouchesChangedAfter;
const currentCentroidYOfTouchesChangedAfter =
@@ -121,6 +124,93 @@
* [PanResponder example in RNTester](https://github.com/facebook/react-native/blob/master/RNTester/js/PanResponderExample.js)
*/
+export type GestureState = {|
+ /**
+ * ID of the gestureState - persisted as long as there at least one touch on screen
+ */
+ stateID: number,
+
+ /**
+ * The latest screen coordinates of the recently-moved touch
+ */
+ moveX: number,
+
+ /**
+ * The latest screen coordinates of the recently-moved touch
+ */
+ moveY: number,
+
+ /**
+ * The screen coordinates of the responder grant
+ */
+ x0: number,
+
+ /**
+ * The screen coordinates of the responder grant
+ */
+ y0: number,
+
+ /**
+ * Accumulated distance of the gesture since the touch started
+ */
+ dx: number,
+
+ /**
+ * Accumulated distance of the gesture since the touch started
+ */
+ dy: number,
+
+ /**
+ * Current velocity of the gesture
+ */
+ vx: number,
+
+ /**
+ * Current velocity of the gesture
+ */
+ vy: number,
+
+ /**
+ * Number of touches currently on screen
+ */
+ numberActiveTouches: number,
+
+ /**
+ * All `gestureState` accounts for timeStamps up until this value
+ *
+ * @private
+ */
+ _accountsForMovesUpTo: number,
+|};
+
+type ActiveCallback = (
+ event: PressEvent,
+ gestureState: GestureState,
+) => boolean;
+
+type PassiveCallback = (event: PressEvent, gestureState: GestureState) => mixed;
+
+type PanResponderConfig = $ReadOnly<{|
+ onMoveShouldSetPanResponder?: ?ActiveCallback,
+ onMoveShouldSetPanResponderCapture?: ?ActiveCallback,
+ onStartShouldSetPanResponder?: ?ActiveCallback,
+ onStartShouldSetPanResponderCapture?: ?ActiveCallback,
+ /**
+ * The body of `onResponderGrant` returns a bool, but the vast majority of
+ * callsites return void and this TODO notice is found in it:
+ * TODO: t7467124 investigate if this can be removed
+ */
+ onPanResponderGrant?: ?(PassiveCallback | ActiveCallback),
+ onPanResponderReject?: ?PassiveCallback,
+ onPanResponderStart?: ?PassiveCallback,
+ onPanResponderEnd?: ?PassiveCallback,
+ onPanResponderRelease?: ?PassiveCallback,
+ onPanResponderMove?: ?PassiveCallback,
+ onPanResponderTerminate?: ?PassiveCallback,
+ onPanResponderTerminationRequest?: ?ActiveCallback,
+ onShouldBlockNativeResponder?: ?ActiveCallback,
+|}>;
+
const PanResponder = {
/**
*
@@ -185,7 +275,7 @@
* - vx/vy: Velocity.
*/
- _initializeGestureState: function(gestureState) {
+ _initializeGestureState(gestureState: GestureState) {
gestureState.moveX = 0;
gestureState.moveY = 0;
gestureState.x0 = 0;
@@ -223,7 +313,10 @@
* typical responder callback pattern (without using `PanResponder`), but
* avoids more dispatches than necessary.
*/
- _updateGestureStateOnMove: function(gestureState, touchHistory) {
+ _updateGestureStateOnMove(
+ gestureState: GestureState,
+ touchHistory: $PropertyType<PressEvent, 'touchHistory'>,
+ ) {
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
gestureState.moveX = currentCentroidXOfTouchesChangedAfter(
touchHistory,
@@ -290,40 +383,50 @@
* accordingly. (numberActiveTouches) may not be totally accurate unless you
* are the responder.
*/
- create: function(config) {
+ create(config: PanResponderConfig) {
const interactionState = {
handle: (null: ?number),
};
- const gestureState = {
+ const gestureState: GestureState = {
// Useful for debugging
stateID: Math.random(),
+ moveX: 0,
+ moveY: 0,
+ x0: 0,
+ y0: 0,
+ dx: 0,
+ dy: 0,
+ vx: 0,
+ vy: 0,
+ numberActiveTouches: 0,
+ _accountsForMovesUpTo: 0,
};
- PanResponder._initializeGestureState(gestureState);
const panHandlers = {
- onStartShouldSetResponder: function(e) {
- return config.onStartShouldSetPanResponder === undefined
+ onStartShouldSetResponder(event: PressEvent): boolean {
+ return config.onStartShouldSetPanResponder == null
? false
- : config.onStartShouldSetPanResponder(e, gestureState);
+ : config.onStartShouldSetPanResponder(event, gestureState);
},
- onMoveShouldSetResponder: function(e) {
- return config.onMoveShouldSetPanResponder === undefined
+ onMoveShouldSetResponder(event: PressEvent): boolean {
+ return config.onMoveShouldSetPanResponder == null
? false
- : config.onMoveShouldSetPanResponder(e, gestureState);
+ : config.onMoveShouldSetPanResponder(event, gestureState);
},
- onStartShouldSetResponderCapture: function(e) {
+ onStartShouldSetResponderCapture(event: PressEvent): boolean {
// TODO: Actually, we should reinitialize the state any time
// touches.length increases from 0 active to > 0 active.
- if (e.nativeEvent.touches.length === 1) {
+ if (event.nativeEvent.touches.length === 1) {
PanResponder._initializeGestureState(gestureState);
}
- gestureState.numberActiveTouches = e.touchHistory.numberActiveTouches;
- return config.onStartShouldSetPanResponderCapture !== undefined
- ? config.onStartShouldSetPanResponderCapture(e, gestureState)
+ gestureState.numberActiveTouches =
+ event.touchHistory.numberActiveTouches;
+ return config.onStartShouldSetPanResponderCapture != null
+ ? config.onStartShouldSetPanResponderCapture(event, gestureState)
: false;
},
- onMoveShouldSetResponderCapture: function(e) {
- const touchHistory = e.touchHistory;
+ onMoveShouldSetResponderCapture(event: PressEvent): boolean {
+ const touchHistory = event.touchHistory;
// Responder system incorrectly dispatches should* to current responder
// Filter out any touch moves past the first one - we would have
// already processed multi-touch geometry during the first event.
@@ -335,56 +438,56 @@
}
PanResponder._updateGestureStateOnMove(gestureState, touchHistory);
return config.onMoveShouldSetPanResponderCapture
- ? config.onMoveShouldSetPanResponderCapture(e, gestureState)
+ ? config.onMoveShouldSetPanResponderCapture(event, gestureState)
: false;
},
- onResponderGrant: function(e) {
+ onResponderGrant(event: PressEvent): boolean {
if (!interactionState.handle) {
interactionState.handle = InteractionManager.createInteractionHandle();
}
- gestureState.x0 = currentCentroidX(e.touchHistory);
- gestureState.y0 = currentCentroidY(e.touchHistory);
+ gestureState.x0 = currentCentroidX(event.touchHistory);
+ gestureState.y0 = currentCentroidY(event.touchHistory);
gestureState.dx = 0;
gestureState.dy = 0;
if (config.onPanResponderGrant) {
- config.onPanResponderGrant(e, gestureState);
+ config.onPanResponderGrant(event, gestureState);
}
// TODO: t7467124 investigate if this can be removed
- return config.onShouldBlockNativeResponder === undefined
+ return config.onShouldBlockNativeResponder == null
? true
- : config.onShouldBlockNativeResponder();
+ : config.onShouldBlockNativeResponder(event, gestureState);
},
- onResponderReject: function(e) {
+ onResponderReject(event: PressEvent): void {
clearInteractionHandle(
interactionState,
config.onPanResponderReject,
- e,
+ event,
gestureState,
);
},
- onResponderRelease: function(e) {
+ onResponderRelease(event: PressEvent): void {
clearInteractionHandle(
interactionState,
config.onPanResponderRelease,
- e,
+ event,
gestureState,
);
PanResponder._initializeGestureState(gestureState);
},
- onResponderStart: function(e) {
- const touchHistory = e.touchHistory;
+ onResponderStart(event: PressEvent): void {
+ const touchHistory = event.touchHistory;
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
if (config.onPanResponderStart) {
- config.onPanResponderStart(e, gestureState);
+ config.onPanResponderStart(event, gestureState);
}
},
- onResponderMove: function(e) {
- const touchHistory = e.touchHistory;
+ onResponderMove(event: PressEvent): void {
+ const touchHistory = event.touchHistory;
// Guard against the dispatch of two touch moves when there are two
// simultaneously changed touches.
if (
@@ -397,35 +500,35 @@
// already processed multi-touch geometry during the first event.
PanResponder._updateGestureStateOnMove(gestureState, touchHistory);
if (config.onPanResponderMove) {
- config.onPanResponderMove(e, gestureState);
+ config.onPanResponderMove(event, gestureState);
}
},
- onResponderEnd: function(e) {
- const touchHistory = e.touchHistory;
+ onResponderEnd(event: PressEvent): void {
+ const touchHistory = event.touchHistory;
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
clearInteractionHandle(
interactionState,
config.onPanResponderEnd,
- e,
+ event,
gestureState,
);
},
- onResponderTerminate: function(e) {
+ onResponderTerminate(event: PressEvent): void {
clearInteractionHandle(
interactionState,
config.onPanResponderTerminate,
- e,
+ event,
gestureState,
);
PanResponder._initializeGestureState(gestureState);
},
- onResponderTerminationRequest: function(e) {
- return config.onPanResponderTerminationRequest === undefined
+ onResponderTerminationRequest(event: PressEvent): boolean {
+ return config.onPanResponderTerminationRequest == null
? true
- : config.onPanResponderTerminationRequest(e, gestureState);
+ : config.onPanResponderTerminationRequest(event, gestureState);
},
};
return {
@@ -439,9 +542,9 @@
function clearInteractionHandle(
interactionState: {handle: ?number},
- callback: Function,
- event: Object,
- gestureState: Object,
+ callback: ?(ActiveCallback | PassiveCallback),
+ event: PressEvent,
+ gestureState: GestureState,
) {
if (interactionState.handle) {
InteractionManager.clearInteractionHandle(interactionState.handle);
@@ -452,4 +555,9 @@
}
}
+export type PanResponderInstance = $Call<
+ $PropertyType<typeof PanResponder, 'create'>,
+ PanResponderConfig,
+>;
+
module.exports = PanResponder;

Libraries/Interaction/TaskQueue.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,7 +11,7 @@
'use strict';
const infoLog = require('infoLog');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
type SimpleTask = {
name: string,

Libraries/Interaction/TouchHistoryMath.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.

Libraries/JSInspector/InspectorAgent.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/JSInspector/JSInspector.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/JSInspector/NetworkAgent.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -12,7 +12,6 @@
const InspectorAgent = require('InspectorAgent');
const JSInspector = require('JSInspector');
-const Map = require('Map');
const XMLHttpRequest = require('XMLHttpRequest');
import type EventSender from 'InspectorAgent';

Libraries/LayoutAnimation/LayoutAnimation.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,121 +7,82 @@
* @flow
* @format
*/
+
'use strict';
-const PropTypes = require('prop-types');
+import Platform from 'Platform';
const UIManager = require('UIManager');
-/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
- * found when Flow v0.54 was deployed. To see the error delete this comment and
- * run Flow. */
-const keyMirror = require('fbjs/lib/keyMirror');
-
-const {checkPropTypes} = PropTypes;
-
-const TypesEnum = {
- spring: true,
- linear: true,
- easeInEaseOut: true,
- easeIn: true,
- easeOut: true,
- keyboard: true,
-};
-const Types = keyMirror(TypesEnum);
+type Type =
+ | 'spring'
+ | 'linear'
+ | 'easeInEaseOut'
+ | 'easeIn'
+ | 'easeOut'
+ | 'keyboard';
-const PropertiesEnum = {
- opacity: true,
- scaleX: true,
- scaleY: true,
- scaleXY: true,
-};
-const Properties = keyMirror(PropertiesEnum);
+type Property = 'opacity' | 'scaleX' | 'scaleY' | 'scaleXY';
-const animType = PropTypes.shape({
- duration: PropTypes.number,
- delay: PropTypes.number,
- springDamping: PropTypes.number,
- initialVelocity: PropTypes.number,
- type: PropTypes.oneOf(Object.keys(Types)).isRequired,
- property: PropTypes.oneOf(
- // Only applies to create/delete
- Object.keys(Properties),
- ),
-});
-
-type Anim = {
+type AnimationConfig = $ReadOnly<{|
duration?: number,
delay?: number,
springDamping?: number,
initialVelocity?: number,
- type?: $Enum<typeof TypesEnum>,
- property?: $Enum<typeof PropertiesEnum>,
-};
+ type?: Type,
+ property?: Property,
+|}>;
-const configType = PropTypes.shape({
- duration: PropTypes.number.isRequired,
- create: animType,
- update: animType,
- delete: animType,
-});
-
-type Config = {
+type LayoutAnimationConfig = $ReadOnly<{|
duration: number,
- create?: Anim,
- update?: Anim,
- delete?: Anim,
-};
-
-function checkConfig(config: Config, location: string, name: string) {
- checkPropTypes({config: configType}, {config}, location, name);
-}
-
-function configureNext(config: Config, onAnimationDidEnd?: Function) {
- if (__DEV__) {
- checkConfig(config, 'config', 'LayoutAnimation.configureNext');
- }
+ create?: AnimationConfig,
+ update?: AnimationConfig,
+ delete?: AnimationConfig,
+|}>;
+
+function configureNext(
+ config: LayoutAnimationConfig,
+ onAnimationDidEnd?: Function,
+) {
+ if (!Platform.isTesting) {
UIManager.configureNextLayoutAnimation(
config,
- onAnimationDidEnd || function() {},
+ onAnimationDidEnd ?? function() {},
function() {
/* unused */
},
);
+ }
}
-function create(duration: number, type, creationProp): Config {
+function create(
+ duration: number,
+ type: Type,
+ property: Property,
+): LayoutAnimationConfig {
return {
duration,
- create: {
- type,
- property: creationProp,
- },
- update: {
- type,
- },
- delete: {
- type,
- property: creationProp,
- },
+ create: {type, property},
+ update: {type},
+ delete: {type, property},
};
}
const Presets = {
- easeInEaseOut: create(300, Types.easeInEaseOut, Properties.opacity),
- linear: create(500, Types.linear, Properties.opacity),
+ easeInEaseOut: create(300, 'easeInEaseOut', 'opacity'),
+ linear: create(500, 'linear', 'opacity'),
spring: {
duration: 700,
create: {
- type: Types.linear,
- property: Properties.opacity,
+ type: 'linear',
+ property: 'opacity',
},
update: {
- type: Types.spring,
+ type: 'spring',
springDamping: 0.4,
},
delete: {
- type: Types.linear,
- property: Properties.opacity,
+ type: 'linear',
+ property: 'opacity',
},
},
};
@@ -143,9 +104,8 @@
* @param config Specifies animation properties:
*
* - `duration` in milliseconds
- * - `create`, config for animating in new views (see `Anim` type)
- * - `update`, config for animating views that have been updated
- * (see `Anim` type)
+ * - `create`, `AnimationConfig` for animating in new views
+ * - `update`, `AnimationConfig` for animating views that have been updated
*
* @param onAnimationDidEnd Called when the animation finished.
* Only supported on iOS.
@@ -156,9 +116,23 @@
* Helper for creating a config for `configureNext`.
*/
create,
- Types,
- Properties,
- checkConfig,
+ Types: Object.freeze({
+ spring: 'spring',
+ linear: 'linear',
+ easeInEaseOut: 'easeInEaseOut',
+ easeIn: 'easeIn',
+ easeOut: 'easeOut',
+ keyboard: 'keyboard',
+ }),
+ Properties: Object.freeze({
+ opacity: 'opacity',
+ scaleX: 'scaleX',
+ scaleY: 'scaleY',
+ scaleXY: 'scaleXY',
+ }),
+ checkConfig(...args: Array<mixed>) {
+ console.error('LayoutAnimation.checkConfig(...) has been disabled.');
+ },
Presets,
easeInEaseOut: configureNext.bind(null, Presets.easeInEaseOut),
linear: configureNext.bind(null, Presets.linear),

Libraries/Linking/Linking.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -14,7 +14,7 @@
const NativeModules = require('NativeModules');
const Platform = require('Platform');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
const LinkingManager =
Platform.OS === 'android'
@@ -81,6 +81,20 @@
return LinkingManager.getInitialURL();
}
+ /*
+ * Launch an Android intent with extras (optional)
+ *
+ * @platform android
+ *
+ * See https://facebook.github.io/react-native/docs/linking.html#sendintent
+ */
+ sendIntent(
+ action: String,
+ extras?: [{key: string, value: string | number | boolean}],
+ ) {
+ return LinkingManager.sendIntent(action, extras);
+ }
+
_validateURL(url: string) {
invariant(
typeof url === 'string',

Libraries/LinkingIOS/RCTLinkingManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -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

Libraries/LinkingIOS/RCTLinkingManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -67,8 +67,12 @@
+ (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

Libraries/Lists/FillRateHelper.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Lists/FlatList.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,16 +9,16 @@
*/
'use strict';
-const MetroListView = require('MetroListView'); // Used as a fallback legacy option
+const Platform = require('Platform');
+const deepDiffer = require('deepDiffer');
const React = require('React');
const View = require('View');
const VirtualizedList = require('VirtualizedList');
-const ListView = require('ListView');
const StyleSheet = require('StyleSheet');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
-import type {DangerouslyImpreciseStyleProp, ViewStyleProp} from 'StyleSheet';
+import type {ViewStyleProp} from 'StyleSheet';
import type {
ViewabilityConfig,
ViewToken,
@@ -104,7 +104,7 @@
/**
* Optional custom style for multi-item rows generated when numColumns > 1.
*/
- columnWrapperStyle?: DangerouslyImpreciseStyleProp,
+ columnWrapperStyle?: ViewStyleProp,
/**
* A marker property for telling the list to re-render (since it implements `PureComponent`). If
* any of your `renderItem`, Header, Footer, etc. functions depend on anything outside of the
@@ -189,7 +189,10 @@
* @platform android
*/
progressViewOffset?: number,
- legacyImplementation?: ?boolean,
+ /**
+ * The legacy implementation is no longer supported.
+ */
+ legacyImplementation?: empty,
/**
* Set this true while waiting for new data from a refresh.
*/
@@ -217,6 +220,12 @@
const defaultProps = {
...VirtualizedList.defaultProps,
numColumns: 1,
+ /**
+ * Enabling this prop on Android greatly improves scrolling performance with no known issues.
+ * The alternative is that scrolling on Android is unusably bad. Enabling it on iOS has a few
+ * known issues.
+ */
+ removeClippedSubviews: Platform.OS === 'android',
};
export type DefaultProps = typeof defaultProps;
@@ -355,7 +364,6 @@
viewPosition?: number,
}) {
if (this._listRef) {
- // $FlowFixMe Found when typing ListView
this._listRef.scrollToIndex(params);
}
}
@@ -372,7 +380,6 @@
viewPosition?: number,
}) {
if (this._listRef) {
- // $FlowFixMe Found when typing ListView
this._listRef.scrollToItem(params);
}
}
@@ -384,7 +391,6 @@
*/
scrollToOffset(params: {animated?: ?boolean, offset: number}) {
if (this._listRef) {
- // $FlowFixMe Found when typing ListView
this._listRef.scrollToOffset(params);
}
}
@@ -396,7 +402,6 @@
*/
recordInteraction() {
if (this._listRef) {
- // $FlowFixMe Found when typing ListView
this._listRef.recordInteraction();
}
}
@@ -408,7 +413,6 @@
*/
flashScrollIndicators() {
if (this._listRef) {
- // $FlowFixMe Found when typing ListView
this._listRef.flashScrollIndicators();
}
}
@@ -418,14 +422,12 @@
*/
getScrollResponder() {
if (this._listRef) {
- // $FlowFixMe Found when typing ListView
return this._listRef.getScrollResponder();
}
}
getScrollableNode() {
if (this._listRef) {
- // $FlowFixMe Found when typing ListView
return this._listRef.getScrollableNode();
}
}
@@ -472,7 +474,7 @@
'Changing onViewableItemsChanged on the fly is not supported',
);
invariant(
- prevProps.viewabilityConfig === this.props.viewabilityConfig,
+ !deepDiffer(prevProps.viewabilityConfig, this.props.viewabilityConfig),
'Changing viewabilityConfig on the fly is not supported',
);
invariant(
@@ -484,8 +486,7 @@
this._checkProps(this.props);
}
- _hasWarnedLegacy = false;
- _listRef: null | VirtualizedList | ListView | MetroListView;
+ _listRef: ?React.ElementRef<typeof VirtualizedList>;
_virtualizedListPairs: Array<ViewabilityConfigCallbackPair> = [];
_captureRef = ref => {
@@ -497,7 +498,6 @@
getItem,
getItemCount,
horizontal,
- legacyImplementation,
numColumns,
columnWrapperStyle,
onViewableItemsChanged,
@@ -515,22 +515,6 @@
'columnWrapperStyle not supported for single column lists',
);
}
- if (legacyImplementation) {
- invariant(
- numColumns === 1,
- 'Legacy list does not support multiple columns.',
- );
- // Warning: may not have full feature parity and is meant more for debugging and performance
- // comparison.
- if (!this._hasWarnedLegacy) {
- console.warn(
- 'FlatList: legacyImplementation is deprecated and will be removed in a ' +
- 'future release - some features not supported and performance may suffer. ' +
- 'Please migrate to the default implementation.',
- );
- this._hasWarnedLegacy = true;
- }
- }
invariant(
!(onViewableItemsChanged && viewabilityConfigCallbackPairs),
'FlatList does not support setting both onViewableItemsChanged and ' +
@@ -644,21 +628,6 @@
};
render() {
- if (this.props.legacyImplementation) {
- return (
- /* $FlowFixMe(>=0.66.0 site=react_native_fb) This comment suppresses an
- * error found when Flow v0.66 was deployed. To see the error delete
- * this comment and run Flow. */
- <MetroListView
- {...this.props}
- /* $FlowFixMe(>=0.66.0 site=react_native_fb) This comment suppresses
- * an error found when Flow v0.66 was deployed. To see the error
- * delete this comment and run Flow. */
- items={this.props.data}
- ref={this._captureRef}
- />
- );
- } else {
return (
<VirtualizedList
{...this.props}
@@ -671,7 +640,6 @@
/>
);
}
- }
}
const styles = StyleSheet.create({

Libraries/Lists/__flowtests__/FlatList-flowtest.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Lists/__flowtests__/SectionList-flowtest.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Lists/ListView/InternalListViewType.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Lists/ListView/ListViewDataSource.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,7 +9,7 @@
*/
'use strict';
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
const isEmpty = require('isEmpty');
/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
* found when Flow v0.54 was deployed. To see the error delete this comment and
@@ -62,7 +62,7 @@
*
* ```
* getInitialState: function() {
- * var ds = new ListView.DataSource({rowHasChanged: this._rowHasChanged});
+ * const ds = new ListView.DataSource({rowHasChanged: this._rowHasChanged});
* return {ds};
* },
* _onDataArrived(newData) {
@@ -356,7 +356,7 @@
const prevSectionsHash = keyedDictionaryFromArray(prevSectionIDs);
const prevRowsHash = {};
for (let ii = 0; ii < prevRowIDs.length; ii++) {
- var sectionID = prevSectionIDs[ii];
+ const sectionID = prevSectionIDs[ii];
warning(
!prevRowsHash[sectionID],
'SectionID appears more than once: ' + sectionID,
@@ -370,7 +370,7 @@
let dirty;
for (let sIndex = 0; sIndex < this.sectionIdentities.length; sIndex++) {
- var sectionID = this.sectionIdentities[sIndex];
+ const sectionID = this.sectionIdentities[sIndex];
// dirty if the sectionHeader is new or _sectionHasChanged is true
dirty = !prevSectionsHash[sectionID];
const sectionHeaderHasChanged = this._sectionHeaderHasChanged;

Libraries/Lists/ListView/ListView.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -427,7 +427,7 @@
);
continue;
} else {
- const invariant = require('fbjs/lib/invariant');
+ const invariant = require('invariant');
invariant(
this.props.enableEmptySections,
"In next release 'enableEmptySections' flag will be deprecated, empty section headers will always be rendered." +

Libraries/Lists/ListView/__mocks__/ListViewMock.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -27,31 +28,47 @@
componentDidMount() {
ListViewMock.latestRef = this;
}
+
render() {
const {dataSource, renderFooter, renderHeader} = this.props;
- const rows = [renderHeader && renderHeader()];
- const allRowIDs = dataSource.rowIdentities;
- for (let sectionIdx = 0; sectionIdx < allRowIDs.length; sectionIdx++) {
- const sectionID = dataSource.sectionIdentities[sectionIdx];
- const rowIDs = allRowIDs[sectionIdx];
- for (let rowIdx = 0; rowIdx < rowIDs.length; rowIdx++) {
- const rowID = rowIDs[rowIdx];
- // Row IDs are only unique in a section
- rows.push(
+ let rows = [
+ renderHeader && (
<StaticRenderer
- key={'section_' + sectionID + '_row_' + rowID}
+ key="renderHeader"
+ shouldUpdate={true}
+ render={renderHeader}
+ />
+ ),
+ ];
+
+ const dataSourceRows = dataSource.rowIdentities.map(
+ (rowIdentity, rowIdentityIndex) => {
+ const sectionID = dataSource.sectionIdentities[rowIdentityIndex];
+ return rowIdentity.map((row, rowIndex) => (
+ <StaticRenderer
+ key={'section_' + sectionID + '_row_' + rowIndex}
shouldUpdate={true}
render={this.props.renderRow.bind(
null,
- dataSource.getRowData(sectionIdx, rowIdx),
+ dataSource.getRowData(rowIdentityIndex, rowIndex),
sectionID,
- rowID,
+ row,
)}
+ />
+ ));
+ },
+ );
+
+ rows = [...rows, ...dataSourceRows];
+ renderFooter &&
+ rows.push(
+ <StaticRenderer
+ key="renderFooter"
+ shouldUpdate={true}
+ render={renderFooter}
/>,
);
- }
- }
- renderFooter && rows.push(renderFooter());
+
return this.props.renderScrollComponent({...this.props, children: rows});
}
static DataSource = ListViewDataSource;

Libraries/Lists/MetroListView.js

@@ -1,203 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @flow
- * @format
- */
-'use strict';
-
-const ListView = require('ListView');
-const React = require('React');
-const RefreshControl = require('RefreshControl');
-const ScrollView = require('ScrollView');
-
-const invariant = require('fbjs/lib/invariant');
-
-type Item = any;
-
-type NormalProps = {
- FooterComponent?: React.ComponentType<*>,
- renderItem: (info: Object) => ?React.Element<any>,
- /* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This comment
- * suppresses an error when upgrading Flow's support for React. To see the
- * error delete this comment and run Flow. */
- renderSectionHeader?: ({section: Object}) => ?React.Element<any>,
- SeparatorComponent?: ?React.ComponentType<*>, // not supported yet
-
- // Provide either `items` or `sections`
- items?: ?Array<Item>, // By default, an Item is assumed to be {key: string}
- // $FlowFixMe - Something is a little off with the type Array<Item>
- sections?: ?Array<{key: string, data: Array<Item>}>,
-
- /**
- * If provided, a standard RefreshControl will be added for "Pull to Refresh" functionality. Make
- * sure to also set the `refreshing` prop correctly.
- */
- onRefresh?: ?Function,
- /**
- * Set this true while waiting for new data from a refresh.
- */
- refreshing?: boolean,
- /**
- * If true, renders items next to each other horizontally instead of stacked vertically.
- */
- horizontal?: ?boolean,
-};
-type DefaultProps = {
- keyExtractor: (item: Item, index: number) => string,
-};
-type Props = NormalProps & DefaultProps;
-
-/**
- * This is just a wrapper around the legacy ListView that matches the new API of FlatList, but with
- * some section support tacked on. It is recommended to just use FlatList directly, this component
- * is mostly for debugging and performance comparison.
- */
-class MetroListView extends React.Component<Props, $FlowFixMeState> {
- scrollToEnd(params?: ?{animated?: ?boolean}) {
- throw new Error('scrollToEnd not supported in legacy ListView.');
- }
- scrollToIndex(params: {
- animated?: ?boolean,
- index: number,
- viewPosition?: number,
- }) {
- throw new Error('scrollToIndex not supported in legacy ListView.');
- }
- scrollToItem(params: {
- animated?: ?boolean,
- item: Item,
- viewPosition?: number,
- }) {
- throw new Error('scrollToItem not supported in legacy ListView.');
- }
- scrollToLocation(params: {
- animated?: ?boolean,
- itemIndex: number,
- sectionIndex: number,
- viewOffset?: number,
- viewPosition?: number,
- }) {
- throw new Error('scrollToLocation not supported in legacy ListView.');
- }
- scrollToOffset(params: {animated?: ?boolean, offset: number}) {
- const {animated, offset} = params;
- // $FlowFixMe Invalid prop usage
- this._listRef.scrollTo(
- this.props.horizontal ? {x: offset, animated} : {y: offset, animated},
- );
- }
- getListRef() {
- return this._listRef;
- }
- setNativeProps(props: Object) {
- if (this._listRef) {
- this._listRef.setNativeProps(props);
- }
- }
- static defaultProps: DefaultProps = {
- keyExtractor: (item, index) => item.key || String(index),
- renderScrollComponent: (props: Props) => {
- if (props.onRefresh) {
- return (
- // $FlowFixMe Invalid prop usage
- <ScrollView
- {...props}
- refreshControl={
- /* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss)
- * This comment suppresses an error when upgrading Flow's support
- * for React. To see the error delete this comment and run Flow.
- */
- <RefreshControl
- refreshing={props.refreshing}
- onRefresh={props.onRefresh}
- />
- }
- />
- );
- } else {
- // $FlowFixMe Invalid prop usage
- return <ScrollView {...props} />;
- }
- },
- };
- state = this._computeState(this.props, {
- ds: new ListView.DataSource({
- rowHasChanged: (itemA, itemB) => true,
- sectionHeaderHasChanged: () => true,
- getSectionHeaderData: (dataBlob, sectionID) =>
- this.state.sectionHeaderData[sectionID],
- }),
- sectionHeaderData: {},
- });
- UNSAFE_componentWillReceiveProps(newProps: Props) {
- this.setState(state => this._computeState(newProps, state));
- }
- render() {
- return (
- // $FlowFixMe Found when typing ListView
- <ListView
- {...this.props}
- dataSource={this.state.ds}
- ref={this._captureRef}
- renderRow={this._renderRow}
- renderFooter={this.props.FooterComponent && this._renderFooter}
- renderSectionHeader={this.props.sections && this._renderSectionHeader}
- renderSeparator={this.props.SeparatorComponent && this._renderSeparator}
- />
- );
- }
- _listRef: ?ListView;
- _captureRef = ref => {
- this._listRef = ref;
- };
- _computeState(props: Props, state) {
- const sectionHeaderData = {};
- if (props.sections) {
- invariant(!props.items, 'Cannot have both sections and items props.');
- const sections = {};
- props.sections.forEach((sectionIn, ii) => {
- const sectionID = 's' + ii;
- sections[sectionID] = sectionIn.data;
- sectionHeaderData[sectionID] = sectionIn;
- });
- return {
- ds: state.ds.cloneWithRowsAndSections(sections),
- sectionHeaderData,
- };
- } else {
- invariant(!props.sections, 'Cannot have both sections and items props.');
- return {
- // $FlowFixMe Found when typing ListView
- ds: state.ds.cloneWithRows(props.items),
- sectionHeaderData,
- };
- }
- }
- /* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This comment
- * suppresses an error when upgrading Flow's support for React. To see the
- * error delete this comment and run Flow. */
- _renderFooter = () => <this.props.FooterComponent key="$footer" />;
- _renderRow = (item, sectionID, rowID, highlightRow) => {
- return this.props.renderItem({item, index: rowID});
- };
- _renderSectionHeader = (section, sectionID) => {
- const {renderSectionHeader} = this.props;
- invariant(
- renderSectionHeader,
- 'Must provide renderSectionHeader with sections prop',
- );
- return renderSectionHeader({section});
- };
- _renderSeparator = (sID, rID) => (
- /* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This comment
- * suppresses an error when upgrading Flow's support for React. To see the
- * error delete this comment and run Flow. */
- <this.props.SeparatorComponent key={sID + rID} />
- );
-}
-
-module.exports = MetroListView;

Libraries/Lists/SectionList.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,7 +9,6 @@
*/
'use strict';
-const MetroListView = require('MetroListView');
const Platform = require('Platform');
const React = require('React');
const ScrollView = require('ScrollView');
@@ -181,7 +180,10 @@
*/
stickySectionHeadersEnabled?: boolean,
- legacyImplementation?: ?boolean,
+ /**
+ * The legacy implementation is no longer supported.
+ */
+ legacyImplementation?: empty,
};
export type Props<SectionT> = RequiredProps<SectionT> &
@@ -274,8 +276,10 @@
viewOffset?: number,
viewPosition?: number,
}) {
+ if (this._wrapperListRef != null) {
this._wrapperListRef.scrollToLocation(params);
}
+ }
/**
* Tells the list an interaction has occurred, which should trigger viewability calculations, e.g.
@@ -284,7 +288,6 @@
*/
recordInteraction() {
const listRef = this._wrapperListRef && this._wrapperListRef.getListRef();
- // $FlowFixMe Found when typing ListView
listRef && listRef.recordInteraction();
}
@@ -323,20 +326,14 @@
}
render() {
- const List = this.props.legacyImplementation
- ? MetroListView
- : VirtualizedSectionList;
/* $FlowFixMe(>=0.66.0 site=react_native_fb) This comment suppresses an
* error found when Flow v0.66 was deployed. To see the error delete this
* comment and run Flow. */
- return <List {...this.props} ref={this._captureRef} />;
+ return <VirtualizedSectionList {...this.props} ref={this._captureRef} />;
}
- _wrapperListRef: MetroListView | VirtualizedSectionList<any>;
+ _wrapperListRef: ?React.ElementRef<typeof VirtualizedSectionList>;
_captureRef = ref => {
- /* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This comment
- * suppresses an error when upgrading Flow's support for React. To see the
- * error delete this comment and run Flow. */
this._wrapperListRef = ref;
};
}

Libraries/Lists/ViewabilityHelper.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,7 +9,7 @@
*/
'use strict';
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
export type ViewToken = {
item: any,
@@ -121,10 +121,13 @@
}
let firstVisible = -1;
const {first, last} = renderRange || {first: 0, last: itemCount - 1};
- invariant(
- last < itemCount,
- 'Invalid render range ' + JSON.stringify({renderRange, itemCount}),
+ if (last >= itemCount) {
+ console.warn(
+ 'Invalid render range computing viewability ' +
+ JSON.stringify({renderRange, itemCount}),
);
+ return [];
+ }
for (let idx = first; idx <= last; idx++) {
const metrics = getFrameMetrics(idx);
if (!metrics) {

Libraries/Lists/VirtualizedList.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -23,7 +23,7 @@
const flattenStyle = require('flattenStyle');
const infoLog = require('infoLog');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
* found when Flow v0.54 was deployed. To see the error delete this comment and
* run Flow. */
@@ -31,7 +31,7 @@
const {computeWindowedRenderLimits} = require('VirtualizeUtils');
-import type {DangerouslyImpreciseStyleProp, ViewStyleProp} from 'StyleSheet';
+import type {ViewStyleProp} from 'StyleSheet';
import type {
ViewabilityConfig,
ViewToken,
@@ -175,6 +175,7 @@
viewableItems: Array<ViewToken>,
changed: Array<ViewToken>,
}) => void,
+ persistentScrollbar?: ?boolean,
/**
* Set this when offset is needed for the loading indicator to show correctly.
* @platform android
@@ -643,7 +644,7 @@
}
static getDerivedStateFromProps(newProps: Props, prevState: State) {
- const {data, extraData, getItemCount, maxToRenderPerBatch} = newProps;
+ const {data, getItemCount, maxToRenderPerBatch} = newProps;
// first and last could be stale (e.g. if a new, shorter items props is passed in), so we make
// sure we're rendering a reasonable range here.
return {
@@ -661,7 +662,7 @@
stickyIndicesFromProps: Set<number>,
first: number,
last: number,
- inversionStyle: ?DangerouslyImpreciseStyleProp,
+ inversionStyle: ViewStyleProp,
) {
const {
CellRendererComponent,
@@ -805,7 +806,10 @@
if (stickyIndicesFromProps.has(ii + stickyOffset)) {
const initBlock = this._getFrameMetricsApprox(lastInitialIndex);
const stickyBlock = this._getFrameMetricsApprox(ii);
- const leadSpace = stickyBlock.offset - initBlock.offset;
+ const leadSpace =
+ stickyBlock.offset -
+ initBlock.offset -
+ (this.props.initialScrollIndex ? 0 : initBlock.length);
cells.push(
<View key="$sticky_lead" style={{[spacerKey]: leadSpace}} />,
);
@@ -881,16 +885,17 @@
<ListEmptyComponent />
)): any);
cells.push(
- React.cloneElement(element, {
- key: '$empty',
+ <View key="$empty" style={inversionStyle}>
+ {React.cloneElement(element, {
onLayout: event => {
this._onLayoutEmpty(event);
if (element.props.onLayout) {
element.props.onLayout(event);
}
},
- style: [element.props.style, inversionStyle],
- }),
+ style: element.props.style,
+ })}
+ </View>,
);
}
if (ListFooterComponent) {
@@ -933,7 +938,7 @@
: 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. */
@@ -947,7 +952,6 @@
(this.props.renderScrollComponent || this._defaultRenderScrollComponent)(
scrollProps,
),
- // $FlowFixMe Invalid prop usage
{
ref: this._captureScrollRef,
},
@@ -955,7 +959,7 @@
);
if (this.props.debug) {
return (
- <View style={{flex: 1}}>
+ <View style={styles.debug}>
{ret}
{this._renderDebugOverlay()}
</View>
@@ -1178,7 +1182,8 @@
_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++) {
@@ -1195,47 +1200,41 @@
const windowLen = frameLast.offset + frameLast.length - windowTop;
const visTop = this._scrollMetrics.offset;
const visLen = this._scrollMetrics.visibleLength;
- const baseStyle = {position: 'absolute', top: 0, right: 0};
+
return (
- <View
- style={{
- ...baseStyle,
- bottom: 0,
- width: 20,
- borderColor: 'blue',
- borderWidth: 1,
- }}>
+ <View style={[styles.debugOverlayBase, styles.debugOverlay]}>
{framesInLayout.map((f, ii) => (
<View
key={'f' + ii}
- style={{
- ...baseStyle,
- left: 0,
+ style={[
+ styles.debugOverlayBase,
+ styles.debugOverlayFrame,
+ {
top: f.offset * normalize,
height: f.length * normalize,
- backgroundColor: 'orange',
- }}
+ },
+ ]}
/>
))}
<View
- style={{
- ...baseStyle,
- left: 0,
+ style={[
+ styles.debugOverlayBase,
+ styles.debugOverlayFrameLast,
+ {
top: windowTop * normalize,
height: windowLen * normalize,
- borderColor: 'green',
- borderWidth: 2,
- }}
+ },
+ ]}
/>
<View
- style={{
- ...baseStyle,
- left: 0,
+ style={[
+ styles.debugOverlayBase,
+ styles.debugOverlayFrameVis,
+ {
top: visTop * normalize,
height: visLen * normalize,
- borderColor: 'red',
- borderWidth: 2,
- }}
+ },
+ ]}
/>
</View>
);
@@ -1631,7 +1630,7 @@
fillRateHelper: FillRateHelper,
horizontal: ?boolean,
index: number,
- inversionStyle: ?DangerouslyImpreciseStyleProp,
+ inversionStyle: ViewStyleProp,
item: Item,
onLayout: (event: Object) => void, // This is extracted by ScrollViewStickyHeader
onUnmount: (cellKey: string) => void,
@@ -1738,6 +1737,9 @@
: inversionStyle;
if (!CellRendererComponent) {
return (
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete
+ * this comment and run Flow. */
<View style={cellStyle} onLayout={onLayout}>
{element}
{itemSeparator}
@@ -1786,6 +1788,34 @@
horizontallyInverted: {
transform: [{scaleX: -1}],
},
+ debug: {
+ flex: 1,
+ },
+ debugOverlayBase: {
+ position: 'absolute',
+ top: 0,
+ right: 0,
+ },
+ debugOverlay: {
+ bottom: 0,
+ width: 20,
+ borderColor: 'blue',
+ borderWidth: 1,
+ },
+ debugOverlayFrame: {
+ left: 0,
+ backgroundColor: 'orange',
+ },
+ debugOverlayFrameLast: {
+ left: 0,
+ borderColor: 'green',
+ borderWidth: 2,
+ },
+ debugOverlayFrameVis: {
+ left: 0,
+ borderColor: 'red',
+ borderWidth: 2,
+ },
});
module.exports = VirtualizedList;

Libraries/Lists/VirtualizedSectionList.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,11 +9,12 @@
*/
'use strict';
+const Platform = require('Platform');
const React = require('React');
const View = require('View');
const VirtualizedList = require('VirtualizedList');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
import type {ViewToken} from 'ViewabilityHelper';
import type {Props as VirtualizedListProps} from 'VirtualizedList';
@@ -145,7 +146,7 @@
sectionIndex: number,
viewPosition?: number,
}) {
- let index = 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;
}
@@ -505,6 +506,9 @@
<SeparatorComponent {...this.state.separatorProps} />
);
return leadingSeparator || separator ? (
+ /* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.89 was deployed. To see the error, delete
+ * this comment and run Flow. */
<View>
{leadingSeparator}
{element}

Libraries/Lists/VirtualizeUtils.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,7 +9,7 @@
*/
'use strict';
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
/**
* Used to find the indices of the frames that overlap the given offsets. Useful for finding the

Libraries/Modal/Modal.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -20,10 +20,7 @@
const StyleSheet = require('StyleSheet');
const View = require('View');
-const deprecatedPropType = require('deprecatedPropType');
-const requireNativeComponent = require('requireNativeComponent');
-
-const RCTModalHostView = requireNativeComponent('RCTModalHostView');
+const RCTModalHostView = require('RCTModalHostViewNativeComponent');
const ModalEventEmitter =
Platform.OS === 'ios' && NativeModules.ModalManager
@@ -31,6 +28,8 @@
: null;
import type EmitterSubscription from 'EmitterSubscription';
+import type {ViewProps} from 'ViewPropTypes';
+import type {SyntheticEvent} from 'CoreEventTypes';
/**
* The Modal component is a simple way to present content above an enclosing view.
@@ -44,95 +43,110 @@
// destroyed before the callback is fired.
let uniqueModalIdentifier = 0;
-class Modal extends React.Component<Object> {
- static propTypes = {
+type OrientationChangeEvent = SyntheticEvent<
+ $ReadOnly<{|
+ orientation: 'portrait' | 'landscape',
+ |}>,
+>;
+
+type Props = $ReadOnly<{|
+ ...ViewProps,
+
/**
* The `animationType` prop controls how the modal animates.
*
* See https://facebook.github.io/react-native/docs/modal.html#animationtype
*/
- animationType: PropTypes.oneOf(['none', 'slide', 'fade']),
+ animationType?: ?('none' | 'slide' | 'fade'),
+
/**
* The `presentationStyle` prop controls how the modal appears.
*
* See https://facebook.github.io/react-native/docs/modal.html#presentationstyle
*/
- presentationStyle: PropTypes.oneOf([
- 'fullScreen',
- 'pageSheet',
- 'formSheet',
- 'overFullScreen',
- ]),
+ presentationStyle?: ?(
+ | 'fullScreen'
+ | 'pageSheet'
+ | 'formSheet'
+ | 'overFullScreen'
+ ),
+
/**
* The `transparent` prop determines whether your modal will fill the
* entire view.
*
* See https://facebook.github.io/react-native/docs/modal.html#transparent
*/
- transparent: PropTypes.bool,
+ transparent?: ?boolean,
+
/**
* The `hardwareAccelerated` prop controls whether to force hardware
* acceleration for the underlying window.
*
* See https://facebook.github.io/react-native/docs/modal.html#hardwareaccelerated
*/
- hardwareAccelerated: PropTypes.bool,
+ hardwareAccelerated?: ?boolean,
+
/**
* The `visible` prop determines whether your modal is visible.
*
* See https://facebook.github.io/react-native/docs/modal.html#visible
*/
- visible: PropTypes.bool,
+ visible?: ?boolean,
+
/**
* The `onRequestClose` callback is called when the user taps the hardware
* back button on Android or the menu button on Apple TV.
*
+ * This is required on Apple TV and Android.
+ *
* See https://facebook.github.io/react-native/docs/modal.html#onrequestclose
*/
- onRequestClose:
- Platform.isTV || Platform.OS === 'android'
- ? PropTypes.func.isRequired
- : PropTypes.func,
+ onRequestClose?: ?(event?: SyntheticEvent<null>) => mixed,
+
/**
* The `onShow` prop allows passing a function that will be called once the
* modal has been shown.
*
* See https://facebook.github.io/react-native/docs/modal.html#onshow
*/
- onShow: PropTypes.func,
+ onShow?: ?(event?: SyntheticEvent<null>) => mixed,
+
/**
* The `onDismiss` prop allows passing a function that will be called once
* the modal has been dismissed.
*
* See https://facebook.github.io/react-native/docs/modal.html#ondismiss
*/
- onDismiss: PropTypes.func,
- animated: deprecatedPropType(
- PropTypes.bool,
- 'Use the `animationType` prop instead.',
- ),
+ onDismiss?: ?() => mixed,
+
+ /**
+ * Deprecated. Use the `animationType` prop instead.
+ */
+ animated?: ?boolean,
+
/**
* The `supportedOrientations` prop allows the modal to be rotated to any of the specified orientations.
*
* See https://facebook.github.io/react-native/docs/modal.html#supportedorientations
*/
- supportedOrientations: PropTypes.arrayOf(
- PropTypes.oneOf([
- 'portrait',
- 'portrait-upside-down',
- 'landscape',
- 'landscape-left',
- 'landscape-right',
- ]),
- ),
+ supportedOrientations?: ?$ReadOnlyArray<
+ | 'portrait'
+ | 'portrait-upside-down'
+ | 'landscape'
+ | 'landscape-left'
+ | 'landscape-right',
+ >,
+
/**
* The `onOrientationChange` callback is called when the orientation changes while the modal is being displayed.
*
* See https://facebook.github.io/react-native/docs/modal.html#onorientationchange
*/
- onOrientationChange: PropTypes.func,
- };
+ onOrientationChange?: ?(event: OrientationChangeEvent) => mixed,
+|}>;
+class Modal extends React.Component<Props> {
static defaultProps = {
visible: true,
hardwareAccelerated: false,
@@ -145,7 +159,7 @@
_identifier: number;
_eventSubscription: ?EmitterSubscription;
- constructor(props: Object) {
+ constructor(props: Props) {
super(props);
Modal._confirmProps(props);
this._identifier = uniqueModalIdentifier++;
@@ -182,11 +196,11 @@
}
}
- UNSAFE_componentWillReceiveProps(nextProps: Object) {
+ UNSAFE_componentWillReceiveProps(nextProps: Props) {
Modal._confirmProps(nextProps);
}
- static _confirmProps(props: Object) {
+ static _confirmProps(props: Props) {
if (
props.presentationStyle &&
props.presentationStyle !== 'overFullScreen' &&

Libraries/Modal/RCTModalHostViewNativeComponent.js

@@ -0,0 +1,131 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow
+ */
+
+'use strict';
+
+const requireNativeComponent = require('requireNativeComponent');
+
+import type {ViewProps} from 'ViewPropTypes';
+import type {SyntheticEvent} from 'CoreEventTypes';
+import type {NativeComponent} from 'ReactNative';
+
+type OrientationChangeEvent = SyntheticEvent<
+ $ReadOnly<{|
+ orientation: 'portrait' | 'landscape',
+ |}>,
+>;
+
+type ModalNativeProps = $ReadOnly<{|
+ ...ViewProps,
+
+ /**
+ * The `animationType` prop controls how the modal animates.
+ *
+ * See https://facebook.github.io/react-native/docs/modal.html#animationtype
+ */
+ animationType?: ?('none' | 'slide' | 'fade'),
+
+ /**
+ * The `presentationStyle` prop controls how the modal appears.
+ *
+ * See https://facebook.github.io/react-native/docs/modal.html#presentationstyle
+ */
+ presentationStyle?: ?(
+ | 'fullScreen'
+ | 'pageSheet'
+ | 'formSheet'
+ | 'overFullScreen'
+ ),
+
+ /**
+ * The `transparent` prop determines whether your modal will fill the
+ * entire view.
+ *
+ * See https://facebook.github.io/react-native/docs/modal.html#transparent
+ */
+ transparent?: ?boolean,
+
+ /**
+ * The `hardwareAccelerated` prop controls whether to force hardware
+ * acceleration for the underlying window.
+ *
+ * See https://facebook.github.io/react-native/docs/modal.html#hardwareaccelerated
+ */
+ hardwareAccelerated?: ?boolean,
+
+ /**
+ * The `visible` prop determines whether your modal is visible.
+ *
+ * See https://facebook.github.io/react-native/docs/modal.html#visible
+ */
+ visible?: ?boolean,
+
+ /**
+ * The `onRequestClose` callback is called when the user taps the hardware
+ * back button on Android or the menu button on Apple TV.
+ *
+ * This is required on Apple TV and Android.
+ *
+ * See https://facebook.github.io/react-native/docs/modal.html#onrequestclose
+ */
+ onRequestClose?: ?(event?: SyntheticEvent<null>) => mixed,
+
+ /**
+ * The `onShow` prop allows passing a function that will be called once the
+ * modal has been shown.
+ *
+ * See https://facebook.github.io/react-native/docs/modal.html#onshow
+ */
+ onShow?: ?(event?: SyntheticEvent<null>) => mixed,
+
+ /**
+ * The `onDismiss` prop allows passing a function that will be called once
+ * the modal has been dismissed.
+ *
+ * See https://facebook.github.io/react-native/docs/modal.html#ondismiss
+ */
+ onDismiss?: ?() => mixed,
+
+ /**
+ * Deprecated. Use the `animationType` prop instead.
+ */
+ animated?: ?boolean,
+
+ /**
+ * The `supportedOrientations` prop allows the modal to be rotated to any of the specified orientations.
+ *
+ * See https://facebook.github.io/react-native/docs/modal.html#supportedorientations
+ */
+ supportedOrientations?: ?$ReadOnlyArray<
+ | 'portrait'
+ | 'portrait-upside-down'
+ | 'landscape'
+ | 'landscape-left'
+ | 'landscape-right',
+ >,
+
+ /**
+ * The `onOrientationChange` callback is called when the orientation changes while the modal is being displayed.
+ *
+ * See https://facebook.github.io/react-native/docs/modal.html#onorientationchange
+ */
+ onOrientationChange?: ?(event: OrientationChangeEvent) => mixed,
+
+ /**
+ * The `identifier` is the unique number for identifying Modal components.
+ */
+ identifier?: ?number,
+|}>;
+
+type RCTModalHostViewNativeType = Class<NativeComponent<ModalNativeProps>>;
+
+module.exports = ((requireNativeComponent(
+ 'RCTModalHostView',
+): any): RCTModalHostViewNativeType);

Libraries/NativeAnimation/Drivers/RCTAnimationDriver.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Drivers/RCTDecayAnimation.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Drivers/RCTDecayAnimation.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,6 +10,7 @@
#import <UIKit/UIKit.h>
#import <React/RCTConvert.h>
+#import "RCTAnimationUtils.h"
#import "RCTValueAnimatedNode.h"
@interface RCTDecayAnimation ()
@@ -100,7 +101,7 @@
CGFloat value = _fromValue +
(_velocity / (1 - _deceleration)) *
- (1 - exp(-(1 - _deceleration) * (currentTime - _frameStartTime) * 1000.0));
+ (1 - exp(-(1 - _deceleration) * (currentTime - _frameStartTime) * 1000.0 / RCTAnimationDragCoefficient()));
[self updateValue:value];

Libraries/NativeAnimation/Drivers/RCTEventAnimation.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Drivers/RCTEventAnimation.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Drivers/RCTFrameAnimation.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Drivers/RCTFrameAnimation.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -97,7 +97,7 @@
}
_animationCurrentTime = currentTime;
- NSTimeInterval currentDuration = _animationCurrentTime - _animationStartTime;
+ NSTimeInterval currentDuration = (_animationCurrentTime - _animationStartTime) / RCTAnimationDragCoefficient();
// Determine how many frames have passed since last update.
// Get index of frames that surround the current interval

Libraries/NativeAnimation/Drivers/RCTSpringAnimation.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Drivers/RCTSpringAnimation.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -12,6 +12,7 @@
#import <React/RCTConvert.h>
#import <React/RCTDefines.h>
+#import "RCTAnimationUtils.h"
#import "RCTValueAnimatedNode.h"
@interface RCTSpringAnimation ()
@@ -120,7 +121,7 @@
} else {
// Handle frame drops, and only advance dt by a max of MAX_DELTA_TIME
deltaTime = MIN(MAX_DELTA_TIME, currentTime - _animationCurrentTime);
- _t = _t + deltaTime;
+ _t = _t + deltaTime / RCTAnimationDragCoefficient();
}
// store the timestamp

Libraries/NativeAnimation/Nodes/RCTAdditionAnimatedNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Nodes/RCTAdditionAnimatedNode.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Nodes/RCTAnimatedNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Nodes/RCTAnimatedNode.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Nodes/RCTDiffClampAnimatedNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Nodes/RCTDiffClampAnimatedNode.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Nodes/RCTDivisionAnimatedNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Nodes/RCTDivisionAnimatedNode.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Nodes/RCTInterpolationAnimatedNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Nodes/RCTInterpolationAnimatedNode.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Nodes/RCTModuloAnimatedNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Nodes/RCTModuloAnimatedNode.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Nodes/RCTMultiplicationAnimatedNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Nodes/RCTMultiplicationAnimatedNode.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Nodes/RCTStyleAnimatedNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Nodes/RCTStyleAnimatedNode.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Nodes/RCTSubtractionAnimatedNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Nodes/RCTSubtractionAnimatedNode.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Nodes/RCTTrackingAnimatedNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Nodes/RCTTrackingAnimatedNode.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Nodes/RCTTransformAnimatedNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Nodes/RCTTransformAnimatedNode.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/RCTAnimationUtils.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -30,3 +30,9 @@
RCT_EXTERN CGFloat RCTRadiansToDegrees(CGFloat radians);
RCT_EXTERN CGFloat RCTDegreesToRadians(CGFloat degrees);
+
+/**
+ * Coefficient to slow down animations, respects the ios
+ * simulator `Slow Animations (⌘T)` option.
+ */
+RCT_EXTERN CGFloat RCTAnimationDragCoefficient(void);

Libraries/NativeAnimation/RCTAnimationUtils.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -93,3 +93,23 @@
{
return degrees / 180.0 * M_PI;
}
+
+#if TARGET_IPHONE_SIMULATOR
+// Based on https://stackoverflow.com/a/13307674
+float UIAnimationDragCoefficient(void);
+#endif
+
+CGFloat RCTAnimationDragCoefficient()
+{
+#if TARGET_IPHONE_SIMULATOR
+ if (NSClassFromString(@"XCTest") != nil) {
+ // UIAnimationDragCoefficient is 10.0 in tests for some reason, but
+ // we need it to be 1.0. Fixes T34233294
+ return 1.0;
+ } else {
+ return (CGFloat)UIAnimationDragCoefficient();
+ }
+#else
+ return 1.0;
+#endif
+}

Libraries/NativeAnimation/RCTNativeAnimatedModule.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/RCTNativeAnimatedModule.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/RCTNativeAnimatedNodesManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/NativeAnimation/RCTNativeAnimatedNodesManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Network/convertRequestBody.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Network/fetch.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Network/FormData.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Network/NetInfo.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,7 +10,6 @@
'use strict';
-const Map = require('Map');
const NativeEventEmitter = require('NativeEventEmitter');
const NativeModules = require('NativeModules');
const Platform = require('Platform');
@@ -222,13 +221,7 @@
removeEventListener(eventName: ChangeEventName, handler: Function): void {
const listener = _isConnectedSubscriptions.get(handler);
- NetInfo.removeEventListener(
- eventName,
- /* $FlowFixMe(>=0.36.0 site=react_native_fb,react_native_oss) Flow error
- * detected during the deploy of Flow v0.36.0. To see the error, remove
- * this comment and run Flow */
- listener,
- );
+ NetInfo.removeEventListener(eventName, listener);
_isConnectedSubscriptions.delete(handler);
},

Libraries/Network/RCTDataRequestHandler.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Network/RCTDataRequestHandler.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Network/RCTFileRequestHandler.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Network/RCTFileRequestHandler.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Network/RCTHTTPRequestHandler.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Network/RCTHTTPRequestHandler.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -23,13 +23,16 @@
}
@synthesize bridge = _bridge;
+@synthesize methodQueue = _methodQueue;
RCT_EXPORT_MODULE()
- (void)invalidate
{
- [_session invalidateAndCancel];
- _session = nil;
+ dispatch_async(self->_methodQueue, ^{
+ [self->_session invalidateAndCancel];
+ self->_session = nil;
+ });
}
- (BOOL)isValid
@@ -73,8 +76,10 @@
valueOptions:NSPointerFunctionsStrongMemory
capacity:0];
}
-
- NSURLSessionDataTask *task = [_session dataTaskWithRequest:request];
+ __block NSURLSessionDataTask *task = nil;
+ dispatch_sync(self->_methodQueue, ^{
+ task = [self->_session dataTaskWithRequest:request];
+ });
{
std::lock_guard<std::mutex> lock(_mutex);
[_delegates setObject:delegate forKey:task];
@@ -109,6 +114,21 @@
}
- (void)URLSession:(NSURLSession *)session
+ task:(NSURLSessionTask *)task
+willPerformHTTPRedirection:(NSHTTPURLResponse *)response
+ newRequest:(NSURLRequest *)request
+ completionHandler:(void (^)(NSURLRequest *))completionHandler
+{
+ // Reset the cookies on redirect.
+ // This is necessary because we're not letting iOS handle cookies by itself
+ NSMutableURLRequest *nextRequest = [request mutableCopy];
+
+ NSArray<NSHTTPCookie *> *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:request.URL];
+ nextRequest.allHTTPHeaderFields = [NSHTTPCookie requestHeaderFieldsWithCookies:cookies];
+ completionHandler(nextRequest);
+}
+
+- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)task
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler

Libraries/Network/RCTNetInfo.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Network/RCTNetInfo.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -52,20 +52,25 @@
{
RCTNetInfo *self = (__bridge id)info;
BOOL didSetReachabilityFlags = [self setReachabilityStatus:flags];
+
+ NSString *connectionType = self->_connectionType ?: RCTConnectionTypeUnknown;
+ NSString *effectiveConnectionType = self->_effectiveConnectionType ?: RCTEffectiveConnectionTypeUnknown;
+ NSString *networkInfo = self->_statusDeprecated ?: RCTReachabilityStateUnknown;
+
if (self->_firstTimeReachability && self->_resolve) {
SCNetworkReachabilityUnscheduleFromRunLoop(self->_firstTimeReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
CFRelease(self->_firstTimeReachability);
- self->_resolve(@{@"connectionType": self->_connectionType ?: RCTConnectionTypeUnknown,
- @"effectiveConnectionType": self->_effectiveConnectionType ?: RCTEffectiveConnectionTypeUnknown,
- @"network_info": self->_statusDeprecated ?: RCTReachabilityStateUnknown});
+ self->_resolve(@{@"connectionType": connectionType,
+ @"effectiveConnectionType": effectiveConnectionType,
+ @"network_info": networkInfo});
self->_firstTimeReachability = nil;
self->_resolve = nil;
}
if (didSetReachabilityFlags && self->_isObserving) {
- [self sendEventWithName:@"networkStatusDidChange" body:@{@"connectionType": self->_connectionType,
- @"effectiveConnectionType": self->_effectiveConnectionType,
- @"network_info": self->_statusDeprecated}];
+ [self sendEventWithName:@"networkStatusDidChange" body:@{@"connectionType": connectionType,
+ @"effectiveConnectionType": effectiveConnectionType,
+ @"network_info": networkInfo}];
}
}

Libraries/Network/RCTNetworking.android.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Network/RCTNetworking.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Network/RCTNetworking.ios.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Network/RCTNetworking.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Network/RCTNetworkTask.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Network/RCTNetworkTask.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Network/XHRInterceptor.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Network/XMLHttpRequest.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -17,7 +17,7 @@
* found when Flow v0.54 was deployed. To see the error delete this comment and
* run Flow. */
const base64 = require('base64-js');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
* found when Flow v0.54 was deployed. To see the error delete this comment and
* run Flow. */

Libraries/Performance/PureComponentDebug.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

Libraries/Performance/QuickPerformanceLogger.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Performance/SamplingProfiler.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Performance/Systrace.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,7 +10,7 @@
'use strict';
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
const TRACE_TAG_REACT_APPS = 1 << 17; // eslint-disable-line no-bitwise
const TRACE_TAG_JS_VM_CALLS = 1 << 27; // eslint-disable-line no-bitwise

Libraries/PermissionsAndroid/PermissionsAndroid.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/polyfills/Array.es6.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

Libraries/polyfills/Array.prototype.es6.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/polyfills/babelHelpers.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -44,6 +44,8 @@
* @polyfill
*/
+/* eslint-disable no-func-assign, no-shadow, no-proto, no-void, no-undef-init */
+
'use strict';
var babelHelpers = (global.babelHelpers = {});

Libraries/polyfills/console.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,7 +9,7 @@
* @format
*/
-/* eslint-disable no-shadow, eqeqeq, curly, no-unused-vars, no-void */
+/* eslint-disable no-shadow, eqeqeq, curly, no-unused-vars, no-void, no-control-regex */
/**
* This pipes all of our console logging functions to native logging so that
@@ -361,17 +361,6 @@
return typeof arg === 'function';
}
- function isPrimitive(arg) {
- return (
- arg === null ||
- typeof arg === 'boolean' ||
- typeof arg === 'number' ||
- typeof arg === 'string' ||
- typeof arg === 'symbol' || // ES6 symbol
- typeof arg === 'undefined'
- );
- }
-
function objectToString(o) {
return Object.prototype.toString.call(o);
}
@@ -520,6 +509,11 @@
groupStack.push(GROUP_PAD);
}
+function consoleGroupCollapsedPolyfill(label) {
+ global.nativeLoggingHook(groupFormat(GROUP_CLOSE, label), LOG_LEVELS.info);
+ groupStack.push(GROUP_PAD);
+}
+
function consoleGroupEndPolyfill() {
groupStack.pop();
global.nativeLoggingHook(groupFormat(GROUP_CLOSE), LOG_LEVELS.info);
@@ -527,6 +521,14 @@
if (global.nativeLoggingHook) {
const originalConsole = global.console;
+ // Preserve the original `console` as `originalConsole`
+ if (__DEV__ && originalConsole) {
+ const descriptor = Object.getOwnPropertyDescriptor(global, 'console');
+ if (descriptor) {
+ Object.defineProperty(global, 'originalConsole', descriptor);
+ }
+ }
+
global.console = {
error: getNativeLogFunction(LOG_LEVELS.error),
info: getNativeLogFunction(LOG_LEVELS.info),
@@ -537,18 +539,13 @@
table: consoleTablePolyfill,
group: consoleGroupPolyfill,
groupEnd: consoleGroupEndPolyfill,
+ groupCollapsed: consoleGroupCollapsedPolyfill,
};
// If available, also call the original `console` method since that is
// sometimes useful. Ex: on OS X, this will let you see rich output in
// the Safari Web Inspector console.
if (__DEV__ && originalConsole) {
- // Preserve the original `console` as `originalConsole`
- const descriptor = Object.getOwnPropertyDescriptor(global, 'console');
- if (descriptor) {
- Object.defineProperty(global, 'originalConsole', descriptor);
- }
-
Object.keys(console).forEach(methodName => {
const reactNativeMethod = console[methodName];
if (originalConsole[methodName]) {
@@ -558,6 +555,25 @@
};
}
});
+
+ // The following methods are not supported by this polyfill but
+ // we still should pass them to original console if they are
+ // supported by it.
+ [
+ 'assert',
+ 'clear',
+ 'dir',
+ 'dirxml',
+ 'groupCollapsed',
+ 'profile',
+ 'profileEnd',
+ ].forEach(methodName => {
+ if (typeof originalConsole[methodName] === 'function') {
+ console[methodName] = function() {
+ originalConsole[methodName](...arguments);
+ };
+ }
+ });
}
} else if (!global.console) {
const log = global.print || function consoleLoggingStub() {};

Libraries/polyfills/error-guard.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/polyfills/Number.es6.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/polyfills/Object.es6.js

@@ -1,65 +1,39 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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
* @polyfill
- * @nolint
*/
-// WARNING: This is an optimized version that fails on hasOwnProperty checks
-// and non objects. It's not spec-compliant. It's a perf optimization.
-// This is only needed for iOS 8 and current Android JSC.
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
-Object.assign = function(target, sources) {
- if (__DEV__) {
+if (typeof Object.assign !== 'function') {
+ Object.defineProperty(Object, 'assign', {
+ value: function assign(target, varArgs) {
+ 'use strict';
if (target == null) {
- throw new TypeError('Object.assign target cannot be null or undefined');
- }
- if (typeof target !== 'object' && typeof target !== 'function') {
- throw new TypeError(
- 'In this environment the target of assign MUST be an object. ' +
- 'This error is a performance optimization and not spec compliant.',
- );
- }
+ throw new TypeError('Cannot convert undefined or null to object');
}
- for (var nextIndex = 1; nextIndex < arguments.length; nextIndex++) {
- var nextSource = arguments[nextIndex];
- if (nextSource == null) {
- continue;
- }
+ let to = Object(target);
- if (__DEV__) {
- if (typeof nextSource !== 'object' && typeof nextSource !== 'function') {
- throw new TypeError(
- 'In this environment the sources for assign MUST be an object. ' +
- 'This error is a performance optimization and not spec compliant.',
- );
- }
- }
-
- // We don't currently support accessors nor proxies. Therefore this
- // copy cannot throw. If we ever supported this then we must handle
- // exceptions and side-effects.
+ for (let index = 1; index < arguments.length; index++) {
+ let nextSource = arguments[index];
- for (var key in nextSource) {
- if (__DEV__) {
- var hasOwnProperty = Object.prototype.hasOwnProperty;
- if (!hasOwnProperty.call(nextSource, key)) {
- throw new TypeError(
- 'One of the sources for assign has an enumerable key on the ' +
- 'prototype chain. Are you trying to assign a prototype property? ' +
- "We don't allow it, as this is an edge case that we do not support. " +
- 'This error is a performance optimization and not spec compliant.',
- );
+ if (nextSource != null) {
+ for (let nextKey in nextSource) {
+ if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
+ to[nextKey] = nextSource[nextKey];
}
}
- target[key] = nextSource[key];
}
}
-
- return target;
-};
+ return to;
+ },
+ writable: true,
+ configurable: true,
+ });
+}

Libraries/polyfills/Object.es7.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/polyfills/String.prototype.es6.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

Libraries/Promise.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.
@@ -10,10 +10,12 @@
'use strict';
-/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
- * found when Flow v0.54 was deployed. To see the error delete this comment and
- * run Flow. */
-const Promise = require('fbjs/lib/Promise.native');
+const Promise = require('promise/setimmediate/es6-extensions');
+require('promise/setimmediate/done');
+
+Promise.prototype.finally = function(onSettled) {
+ return this.then(onSettled, onSettled);
+};
if (__DEV__) {
/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an

Libraries/promiseRejectionIsError.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.

Libraries/PushNotificationIOS/PushNotificationIOS.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -13,7 +13,7 @@
const NativeEventEmitter = require('NativeEventEmitter');
const RCTPushNotificationManager = require('NativeModules')
.PushNotificationManager;
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
const PushNotificationEmitter = new NativeEventEmitter(
RCTPushNotificationManager,

Libraries/PushNotificationIOS/RCTPushNotificationManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/PushNotificationIOS/RCTPushNotificationManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/RCTTest/FBSnapshotTestCase/FBSnapshotTestCase.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

Libraries/RCTTest/FBSnapshotTestCase/FBSnapshotTestCase.m

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

Libraries/RCTTest/FBSnapshotTestCase/FBSnapshotTestController.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

Libraries/RCTTest/FBSnapshotTestCase/FBSnapshotTestController.m

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

Libraries/RCTTest/FBSnapshotTestCase/UIImage+Compare.h

@@ -1,3 +1,8 @@
+// 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.
+
//
// Created by Gabriel Handford on 3/1/09.
// Copyright 2009-2013. All rights reserved.

Libraries/RCTTest/FBSnapshotTestCase/UIImage+Compare.m

@@ -1,3 +1,8 @@
+// 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.
+
//
// Created by Gabriel Handford on 3/1/09.
// Copyright 2009-2013. All rights reserved.

Libraries/RCTTest/FBSnapshotTestCase/UIImage+Diff.h

@@ -1,3 +1,8 @@
+// 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.
+
//
// Created by Gabriel Handford on 3/1/09.
// Copyright 2009-2013. All rights reserved.

Libraries/RCTTest/FBSnapshotTestCase/UIImage+Diff.m

@@ -1,3 +1,8 @@
+// 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.
+
//
// Created by Gabriel Handford on 3/1/09.
// Copyright 2009-2013. All rights reserved.

Libraries/RCTTest/RCTSnapshotManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/RCTTest/RCTSnapshotManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/RCTTest/RCTSnapshotNativeComponent.js

@@ -0,0 +1,33 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow
+ */
+
+'use strict';
+
+import type {SyntheticEvent} from 'CoreEventTypes';
+import type {ViewProps} from 'ViewPropTypes';
+import type {NativeComponent} from 'ReactNative';
+
+type SnapshotReadyEvent = SyntheticEvent<
+ $ReadOnly<{
+ testIdentifier: string,
+ }>,
+>;
+
+type NativeProps = $ReadOnly<{|
+ ...ViewProps,
+ onSnapshotReady?: ?(event: SnapshotReadyEvent) => mixed,
+ testIdentifier?: ?string,
+|}>;
+
+type SnapshotViewNativeType = Class<NativeComponent<NativeProps>>;
+
+const requireNativeComponent = require('requireNativeComponent');
+
+module.exports = ((requireNativeComponent('RCTSnapshot'):any): SnapshotViewNativeType);

Libraries/RCTTest/RCTTestModule.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/RCTTest/RCTTestModule.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/RCTTest/RCTTestRunner.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -36,6 +36,11 @@
moduleProvider:(moduleProvider__) \
scriptURL: scriptURL__]
+#define RCTInitRunnerForAppWithDelegate(app__, bridgeDelegate__) \
+[[RCTTestRunner alloc] initWithApp:(app__) \
+ referenceDirectory:@FB_REFERENCE_IMAGE_DIR \
+ bridgeDelegate:(bridgeDelegate__)]
+
@protocol RCTBridgeModule;
@class RCTBridge;
@@ -64,11 +69,25 @@
* @param app The path to the app bundle without suffixes, e.g. IntegrationTests/IntegrationTestsApp
* @param referenceDirectory The path for snapshot references images.
* @param block A block that returns an array of extra modules to be used by the test runner.
+ * @param scriptURL URL to the JS bundle to use.
+ * @param bridgeDelegate Custom delegate for bridge activities.
*/
- (instancetype)initWithApp:(NSString *)app
referenceDirectory:(NSString *)referenceDirectory
moduleProvider:(RCTBridgeModuleListProvider)block
- scriptURL:(NSURL *)scriptURL NS_DESIGNATED_INITIALIZER;
+ scriptURL:(NSURL *)scriptURL
+ bridgeDelegate:(id<RCTBridgeDelegate>)bridgeDelegate NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)initWithApp:(NSString *)app
+ referenceDirectory:(NSString *)referenceDirectory
+ moduleProvider:(RCTBridgeModuleListProvider)block
+ scriptURL:(NSURL *)scriptURL;
+
+- (instancetype)initWithApp:(NSString *)app
+ referenceDirectory:(NSString *)referenceDirectory
+ bridgeDelegate:(id<RCTBridgeDelegate>)bridgeDelegate;
+
+- (NSURL *)defaultScriptURL;
/**
* Simplest runTest function simply mounts the specified JS module with no

Libraries/RCTTest/RCTTestRunner.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -25,6 +25,7 @@
FBSnapshotTestController *_testController;
RCTBridgeModuleListProvider _moduleProvider;
NSString *_appPath;
+ __weak id<RCTBridgeDelegate> _bridgeDelegate;
}
- (instancetype)initWithApp:(NSString *)app
@@ -32,6 +33,30 @@
moduleProvider:(RCTBridgeModuleListProvider)block
scriptURL:(NSURL *)scriptURL
{
+ return [self initWithApp:app
+ referenceDirectory:referenceDirectory
+ moduleProvider:block
+ scriptURL:scriptURL
+ bridgeDelegate:nil];
+}
+
+- (instancetype)initWithApp:(NSString *)app
+ referenceDirectory:(NSString *)referenceDirectory
+ bridgeDelegate:(id<RCTBridgeDelegate>)bridgeDelegate
+{
+ return [self initWithApp:app
+ referenceDirectory:referenceDirectory
+ moduleProvider:nil
+ scriptURL:nil
+ bridgeDelegate:bridgeDelegate];
+}
+
+- (instancetype)initWithApp:(NSString *)app
+ referenceDirectory:(NSString *)referenceDirectory
+ moduleProvider:(RCTBridgeModuleListProvider)block
+ scriptURL:(NSURL *)scriptURL
+ bridgeDelegate:(id<RCTBridgeDelegate>)bridgeDelegate
+{
RCTAssertParam(app);
RCTAssertParam(referenceDirectory);
@@ -46,10 +71,11 @@
_testController.referenceImagesDirectory = referenceDirectory;
_moduleProvider = [block copy];
_appPath = app;
+ _bridgeDelegate = bridgeDelegate;
if (scriptURL != nil) {
_scriptURL = scriptURL;
- } else {
+ } else if (!_bridgeDelegate) {
[self updateScript];
}
}
@@ -58,13 +84,18 @@
RCT_NOT_IMPLEMENTED(- (instancetype)init)
-- (void)updateScript
+- (NSURL *)defaultScriptURL
{
if (getenv("CI_USE_PACKAGER") || _useBundler) {
- _scriptURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:8081/%@.bundle?platform=ios&dev=true", _appPath]];
+ return [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:8081/%@.bundle?platform=ios&dev=true", _appPath]];
} else {
- _scriptURL = [[NSBundle bundleForClass:[RCTBridge class]] URLForResource:@"main" withExtension:@"jsbundle"];
+ return [[NSBundle bundleForClass:[RCTBridge class]] URLForResource:@"main" withExtension:@"jsbundle"];
}
+}
+
+- (void)updateScript
+{
+ _scriptURL = [self defaultScriptURL];
RCTAssert(_scriptURL != nil, @"No scriptURL set");
}
@@ -129,9 +160,14 @@
});
@autoreleasepool {
- RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:_scriptURL
+ RCTBridge *bridge;
+ if (_bridgeDelegate) {
+ bridge = [[RCTBridge alloc] initWithDelegate:_bridgeDelegate launchOptions:nil];
+ } else {
+ bridge= [[RCTBridge alloc] initWithBundleURL:_scriptURL
moduleProvider:_moduleProvider
launchOptions:nil];
+ }
[bridge.devSettings setIsDebuggingRemotely:_useJSDebugger];
batchedBridge = [bridge batchedBridge];

Libraries/RCTTest/SnapshotViewIOS.android.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/RCTTest/SnapshotViewIOS.ios.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,37 +11,36 @@
'use strict';
const React = require('React');
-const PropTypes = require('prop-types');
const StyleSheet = require('StyleSheet');
-const {TestModule} = require('NativeModules');
const UIManager = require('UIManager');
const View = require('View');
-const ViewPropTypes = require('ViewPropTypes');
+const {TestModule} = require('NativeModules');
-const requireNativeComponent = require('requireNativeComponent');
+import type {SyntheticEvent} from 'CoreEventTypes';
+import type {ViewProps} from 'ViewPropTypes';
// Verify that RCTSnapshot is part of the UIManager since it is only loaded
// if you have linked against RCTTest like in tests, otherwise we will have
// a warning printed out
-const RCTSnapshot = UIManager.RCTSnapshot
- ? requireNativeComponent('RCTSnapshot')
+const RCTSnapshot = UIManager.getViewManagerConfig('RCTSnapshot')
+ ? require('RCTSnapshotNativeComponent')
: View;
-class SnapshotViewIOS extends React.Component<{
- onSnapshotReady?: Function,
- testIdentifier?: string,
-}> {
- // $FlowFixMe(>=0.41.0)
- static propTypes = {
- ...ViewPropTypes,
- // A callback when the Snapshot view is ready to be compared
- onSnapshotReady: PropTypes.func,
- // A name to identify the individual instance to the SnapshotView
- testIdentifier: PropTypes.string,
- };
+type SnapshotReadyEvent = SyntheticEvent<
+ $ReadOnly<{
+ testIdentifier: string,
+ }>,
+>;
+
+type Props = $ReadOnly<{|
+ ...ViewProps,
+ onSnapshotReady?: ?(event: SnapshotReadyEvent) => mixed,
+ testIdentifier?: ?string,
+|}>;
- onDefaultAction = (event: Object) => {
+class SnapshotViewIOS extends React.Component<Props> {
+ onDefaultAction = (event: SnapshotReadyEvent) => {
TestModule.verifySnapshot(TestModule.markTestPassed);
};

Libraries/react-native/React.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.

Libraries/react-native/react-native-implementation.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,13 +10,11 @@
'use strict';
-const invariant = require('fbjs/lib/invariant');
-
-let showedListViewDeprecation = false;
-let showedSwipeableListViewDeprecation = false;
+const invariant = require('invariant');
+const warnOnce = require('warnOnce');
// Export React, plus some native additions.
-const ReactNative = {
+module.exports = {
// Components
get AccessibilityInfo() {
return require('AccessibilityInfo');
@@ -52,6 +50,13 @@
return require('ImageEditor');
},
get ImageStore() {
+ warnOnce(
+ 'imagestore-deprecation',
+ 'ImageStore is deprecated and will be removed in a future release. ' +
+ 'To get a base64-encoded string from a local image use either of the following third-party libraries:' +
+ "* expo-file-system: `readAsStringAsync(filepath, 'base64')`" +
+ "* react-native-fs: `readFile(filepath, 'base64')`",
+ );
return require('ImageStore');
},
get InputAccessoryView() {
@@ -61,25 +66,25 @@
return require('KeyboardAvoidingView');
},
get ListView() {
- if (!showedListViewDeprecation) {
- console.warn(
+ warnOnce(
+ 'listview-deprecation',
'ListView is deprecated and will be removed in a future release. ' +
'See https://fb.me/nolistview for more information',
);
-
- showedListViewDeprecation = true;
- }
return require('ListView');
},
get MaskedViewIOS() {
+ warnOnce(
+ 'maskedviewios-moved',
+ 'MaskedViewIOS has been extracted from react-native core and will be removed in a future release. ' +
+ "It can now be installed and imported from '@react-native-community/masked-view' instead of 'react-native'. " +
+ 'See https://github.com/react-native-community/react-native-masked-view',
+ );
return require('MaskedViewIOS');
},
get Modal() {
return require('Modal');
},
- get NavigatorIOS() {
- return require('NavigatorIOS');
- },
get Picker() {
return require('Picker');
},
@@ -105,6 +110,12 @@
return require('SegmentedControlIOS');
},
get Slider() {
+ warnOnce(
+ 'slider-moved',
+ 'Slider has been extracted from react-native core and will be removed in a future release. ' +
+ "It can now be installed and imported from '@react-native-community/slider' instead of 'react-native'. " +
+ 'See https://github.com/react-native-community/react-native-slider',
+ );
return require('Slider');
},
get SnapshotViewIOS() {
@@ -123,28 +134,19 @@
return require('SwipeableFlatList');
},
get SwipeableListView() {
- if (!showedSwipeableListViewDeprecation) {
- console.warn(
+ warnOnce(
+ 'swipablelistview-deprecation',
'ListView and SwipeableListView are deprecated and will be removed in a future release. ' +
'See https://fb.me/nolistview for more information',
);
-
- showedSwipeableListViewDeprecation = true;
- }
return require('SwipeableListView');
},
- get TabBarIOS() {
- return require('TabBarIOS');
- },
get Text() {
return require('Text');
},
get TextInput() {
return require('TextInput');
},
- get ToastAndroid() {
- return require('ToastAndroid');
- },
get ToolbarAndroid() {
return require('ToolbarAndroid');
},
@@ -167,12 +169,24 @@
return require('View');
},
get ViewPagerAndroid() {
+ warnOnce(
+ 'viewpager-moved',
+ 'ViewPagerAndroid has been extracted from react-native core and will be removed in a future release. ' +
+ "It can now be installed and imported from '@react-native-community/viewpager' instead of 'react-native'. " +
+ 'See https://github.com/react-native-community/react-native-viewpager',
+ );
return require('ViewPagerAndroid');
},
get VirtualizedList() {
return require('VirtualizedList');
},
get WebView() {
+ warnOnce(
+ 'webview-moved',
+ 'WebView has been extracted from react-native core and will be removed in a future release. ' +
+ "It can now be installed and imported from 'react-native-webview' instead of 'react-native'. " +
+ 'See https://github.com/react-native-community/react-native-webview',
+ );
return require('WebView');
},
@@ -184,7 +198,11 @@
return require('Alert');
},
get AlertIOS() {
- return require('AlertIOS');
+ warnOnce(
+ 'alert-ios',
+ 'AlertIOS is deprecated. Use the `Alert` module directly instead.',
+ );
+ return require('Alert');
},
get Animated() {
return require('Animated');
@@ -196,11 +214,14 @@
return require('AppState');
},
get AsyncStorage() {
+ warnOnce(
+ 'async-storage-moved',
+ 'Async Storage has been extracted from react-native core and will be removed in a future release. ' +
+ "It can now be installed and imported from '@react-native-community/async-storage' instead of 'react-native'. " +
+ 'See https://github.com/react-native-community/react-native-async-storage',
+ );
return require('AsyncStorage');
},
- get BackAndroid() {
- return require('BackAndroid');
- }, // deprecated: use BackHandler instead
get BackHandler() {
return require('BackHandler');
},
@@ -247,6 +268,12 @@
return require('NativeEventEmitter');
},
get NetInfo() {
+ warnOnce(
+ 'netinfo-moved',
+ 'NetInfo has been extracted from react-native core and will be removed in a future release. ' +
+ "It can now be installed and imported from '@react-native-community/netinfo' instead of 'react-native'. " +
+ 'See https://github.com/react-native-community/react-native-netinfo',
+ );
return require('NetInfo');
},
get PanResponder() {
@@ -279,6 +306,9 @@
get TimePickerAndroid() {
return require('TimePickerAndroid');
},
+ get ToastAndroid() {
+ return require('ToastAndroid');
+ },
get TVEventHandler() {
return require('TVEventHandler');
},
@@ -288,6 +318,9 @@
get unstable_batchedUpdates() {
return require('ReactNative').unstable_batchedUpdates;
},
+ get UTFSequence() {
+ return require('UTFSequence');
+ },
get Vibration() {
return require('Vibration');
},
@@ -323,19 +356,27 @@
// Prop Types
get ColorPropType() {
- return require('ColorPropType');
+ return require('DeprecatedColorPropType');
},
get EdgeInsetsPropType() {
- return require('EdgeInsetsPropType');
+ return require('DeprecatedEdgeInsetsPropType');
},
get PointPropType() {
- return require('PointPropType');
+ return require('DeprecatedPointPropType');
},
get ViewPropTypes() {
- return require('ViewPropTypes');
+ return require('DeprecatedViewPropTypes');
},
// Deprecated
+ get BackAndroid() {
+ invariant(
+ false,
+ 'BackAndroid is deprecated and has been removed from this package. ' +
+ 'Use BackHandler instead',
+ );
+ },
+
get Navigator() {
invariant(
false,
@@ -344,6 +385,11 @@
'Learn about alternative navigation solutions at http://facebook.github.io/react-native/docs/navigation.html',
);
},
+ get NavigatorIOS() {
+ invariant(
+ false,
+ 'NavigatorIOS is deprecated and has been removed from this package. ' +
+ 'Learn about alternative navigation solutions at http://facebook.github.io/react-native/docs/navigation.html',
+ );
+ },
};
-
-module.exports = ReactNative;

Libraries/react-native/react-native-interface.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ReactNative/AppContainer.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ReactNative/AppRegistry.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -16,11 +16,14 @@
const SceneTracker = require('SceneTracker');
const infoLog = require('infoLog');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
const renderApplication = require('renderApplication');
type Task = (taskData: any) => Promise<void>;
type TaskProvider = () => Task;
+/* $FlowFixMe(>=0.90.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.90 was deployed. To see the error, delete this
+ * comment and run Flow. */
export type ComponentProvider = () => React$ComponentType<any>;
export type ComponentProviderInstrumentationHook = (
component: ComponentProvider,

Libraries/ReactNative/FabricUIManager.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ReactNative/getNativeComponentAttributes.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -19,11 +19,11 @@
const processColor = require('processColor');
const resolveAssetSource = require('resolveAssetSource');
const sizesDiffer = require('sizesDiffer');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
const warning = require('fbjs/lib/warning');
function getNativeComponentAttributes(uiViewClassName: string) {
- const viewConfig = UIManager[uiViewClassName];
+ const viewConfig = UIManager.getViewManagerConfig(uiViewClassName);
invariant(
viewConfig != null && viewConfig.NativeProps != null,
@@ -36,7 +36,7 @@
let {baseModuleName, bubblingEventTypes, directEventTypes} = viewConfig;
let nativeProps = viewConfig.NativeProps;
while (baseModuleName) {
- const baseModule = UIManager[baseModuleName];
+ const baseModule = UIManager.getViewManagerConfig(baseModuleName);
if (!baseModule) {
warning(false, 'Base module "%s" does not exist', baseModuleName);
baseModuleName = null;
@@ -96,7 +96,7 @@
// This is supported on UIManager platforms (ex: Android),
// as lazy view managers are not implemented for all platforms.
// See [UIManager] for details on constants and implementations.
- if (UIManager.ViewManagerNames) {
+ if (UIManager.ViewManagerNames || UIManager.LazyViewManagersEnabled) {
// Lazy view managers enabled.
viewConfig = merge(viewConfig, UIManager.getDefaultEventTypes());
} else {

Libraries/ReactNative/I18nManager.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ReactNative/queryLayoutByID.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ReactNative/ReactFabricIndicator.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ReactNative/ReactFabricInternals.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ReactNative/renderApplication.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,10 +11,11 @@
'use strict';
const AppContainer = require('AppContainer');
+import PerformanceLogger from 'PerformanceLogger';
const React = require('React');
const ReactFabricIndicator = require('ReactFabricIndicator');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
// require BackHandler so it sets the default handler that exits the app if no listeners respond
require('BackHandler');
@@ -53,11 +54,13 @@
renderable = <ConcurrentMode>{renderable}</ConcurrentMode>;
}
+ PerformanceLogger.startTimespan('renderApplication_React_render');
if (fabric) {
require('ReactFabric').render(renderable, rootTag);
} else {
require('ReactNative').render(renderable, rootTag);
}
+ PerformanceLogger.stopTimespan('renderApplication_React_render');
}
module.exports = renderApplication;

Libraries/ReactNative/requireNativeComponent.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ReactNative/takeSnapshot.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/ReactNative/UIManager.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,11 +11,13 @@
const NativeModules = require('NativeModules');
const Platform = require('Platform');
+const UIManagerProperties = require('UIManagerProperties');
const defineLazyObjectProperty = require('defineLazyObjectProperty');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
const {UIManager} = NativeModules;
+const viewManagerConfigs = {};
invariant(
UIManager,
@@ -35,16 +37,50 @@
'Use ReactNative.takeSnapshot instead.',
);
};
+const triedLoadingConfig = new Set();
+UIManager.getViewManagerConfig = function(viewManagerName: string) {
+ if (
+ viewManagerConfigs[viewManagerName] === undefined &&
+ UIManager.getConstantsForViewManager
+ ) {
+ try {
+ viewManagerConfigs[
+ viewManagerName
+ ] = UIManager.getConstantsForViewManager(viewManagerName);
+ } catch (e) {
+ viewManagerConfigs[viewManagerName] = null;
+ }
+ }
-/**
- * Copies the ViewManager constants and commands into UIManager. This is
- * only needed for iOS, which puts the constants in the ViewManager
- * namespace instead of UIManager, unlike Android.
- */
-if (Platform.OS === 'ios') {
- Object.keys(UIManager).forEach(viewName => {
+ const config = viewManagerConfigs[viewManagerName];
+ if (config) {
+ return config;
+ }
+
+ // If we're in the Chrome Debugger, let's not even try calling the sync
+ // method.
+ if (__DEV__) {
+ if (!global.nativeCallSyncHook) {
+ return config;
+ }
+ }
+
+ if (UIManager.lazilyLoadView && !triedLoadingConfig.has(viewManagerName)) {
+ const result = UIManager.lazilyLoadView(viewManagerName);
+ triedLoadingConfig.add(viewManagerName);
+ if (result.viewConfig) {
+ UIManager[viewManagerName] = result.viewConfig;
+ lazifyViewManagerConfig(viewManagerName);
+ }
+ }
+
+ return viewManagerConfigs[viewManagerName];
+};
+
+function lazifyViewManagerConfig(viewName) {
const viewConfig = UIManager[viewName];
if (viewConfig.Manager) {
+ viewManagerConfigs[viewName] = viewConfig;
defineLazyObjectProperty(viewConfig, 'Constants', {
get: () => {
const viewManager = NativeModules[viewConfig.Manager];
@@ -75,6 +111,16 @@
},
});
}
+}
+
+/**
+ * Copies the ViewManager constants and commands into UIManager. This is
+ * only needed for iOS, which puts the constants in the ViewManager
+ * namespace instead of UIManager, unlike Android.
+ */
+if (Platform.OS === 'ios') {
+ Object.keys(UIManager).forEach(viewName => {
+ lazifyViewManagerConfig(viewName);
});
} else if (UIManager.ViewManagerNames) {
// We want to add all the view managers to the UIManager.
@@ -101,7 +147,28 @@
// we also tell Prepack that it has only partial knowledge of the UIManager,
// so that any accesses to unknown properties along the global code will fail
// when Prepack encounters them.
- if (global.__makePartial) global.__makePartial(UIManager);
+ if (global.__makePartial) {
+ global.__makePartial(UIManager);
+ }
+}
+
+if (__DEV__) {
+ Object.keys(UIManager).forEach(viewManagerName => {
+ if (!UIManagerProperties.includes(viewManagerName)) {
+ if (!viewManagerConfigs[viewManagerName]) {
+ viewManagerConfigs[viewManagerName] = UIManager[viewManagerName];
+ }
+ defineLazyObjectProperty(UIManager, viewManagerName, {
+ get: () => {
+ console.warn(
+ `Accessing view manager configs directly off UIManager via UIManager['${viewManagerName}'] ` +
+ `is no longer supported. Use UIManager.getViewManagerConfig('${viewManagerName}') instead.`,
+ );
+ return UIManager.getViewManagerConfig(viewManagerName);
+ },
+ });
+ }
+ });
}
module.exports = UIManager;

Libraries/ReactNative/UIManagerProperties.js

@@ -0,0 +1,67 @@
+/**
+ * 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.
+ *
+ * @flow strict-local
+ * @format
+ */
+'use strict';
+
+/**
+ * The list of non-ViewManager related UIManager properties.
+ *
+ * In an effort to improve startup performance by lazily loading view managers,
+ * the interface to access view managers will change from
+ * UIManager['viewManagerName'] to UIManager.getViewManagerConfig('viewManagerName').
+ * By using a function call instead of a property access, the UIManager will
+ * be able to initialize and load the required view manager from native
+ * synchronously. All of React Native's core components have been updated to
+ * use getViewManagerConfig(). For the next few releases, any usage of
+ * UIManager['viewManagerName'] will result in a warning. Because React Native
+ * does not support Proxy objects, a view manager access is implied if any of
+ * UIManager's properties that are not one of the properties below is being
+ * accessed. Once UIManager property accesses for view managers has been fully
+ * deprecated, this file will also be removed.
+ */
+module.exports = [
+ 'clearJSResponder',
+ 'configureNextLayoutAnimation',
+ 'createView',
+ 'dismissPopupMenu',
+ 'dispatchViewManagerCommand',
+ 'findSubviewIn',
+ 'getConstantsForViewManager',
+ 'getDefaultEventTypes',
+ 'manageChildren',
+ 'measure',
+ 'measureInWindow',
+ 'measureLayout',
+ 'measureLayoutRelativeToParent',
+ 'playTouchSound',
+ 'removeRootView',
+ 'removeSubviewsFromContainerWithID',
+ 'replaceExistingNonRootView',
+ 'sendAccessibilityEvent',
+ 'setChildren',
+ 'setJSResponder',
+ 'setLayoutAnimationEnabledExperimental',
+ 'showPopupMenu',
+ 'updateView',
+ 'viewIsDescendantOf',
+ 'PopupMenu',
+ 'LazyViewManagersEnabled',
+ 'ViewManagerNames',
+ 'StyleConstants',
+ 'AccessibilityEventTypes',
+ 'UIView',
+ '__takeSnapshot',
+ 'takeSnapshot',
+ 'getViewManagerConfig',
+ 'blur',
+ 'focus',
+ 'genericBubblingEventTypes',
+ 'genericDirectEventTypes',
+ 'lazilyLoadView',
+];

Libraries/ReactNative/UIManagerStatTracker.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Renderer/oss/ReactFabric-dev.js

@@ -104,7 +104,7 @@
// invokeGuardedCallback uses a try-catch, all user exceptions are treated
// like caught exceptions, and the DevTools won't pause unless the developer
// takes the extra step of enabling pause on caught exceptions. This is
- // untintuitive, though, because even though React has caught the error, from
+ // unintuitive, though, because even though React has caught the error, from
// the developer's perspective, the error is uncaught.
//
// To preserve the expected "Pause on exceptions" behavior, we don't use a
@@ -1090,6 +1090,7 @@
var SimpleMemoComponent = 15;
var LazyComponent = 16;
var IncompleteClassComponent = 17;
+var DehydratedSuspenseComponent = 18;
function getParent(inst) {
do {
@@ -2572,6 +2573,15 @@
var ReactSharedInternals =
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
+// Prevent newer renderers from RTE when used with older react package versions.
+// Current owner and dispatcher used to share the same ref,
+// but PR #14548 split them out to better support the react-debug-tools package.
+if (!ReactSharedInternals.hasOwnProperty("ReactCurrentDispatcher")) {
+ ReactSharedInternals.ReactCurrentDispatcher = {
+ current: null
+ };
+}
+
// The Symbol used to tag the ReactElement-like types. If there is no native Symbol
// nor polyfill, then a plain number is used for performance.
var hasSymbol = typeof Symbol === "function" && Symbol.for;
@@ -3494,6 +3504,19 @@
return frameDeadline <= now$1();
}
+var debugRenderPhaseSideEffects = false;
+var debugRenderPhaseSideEffectsForStrictMode = false;
+var enableUserTimingAPI = true;
+var replayFailedUnitOfWorkWithInvokeGuardedCallback = true;
+var warnAboutDeprecatedLifecycles = false;
+var enableProfilerTimer = true;
+var enableSchedulerTracing = true;
+var enableSuspenseServerRenderer = false;
+
+var warnAboutDeprecatedSetNativeProps = false;
+
+// Only used in www builds.
+
// Use to restore controlled state after a change event has fired.
var restoreImpl = null;
@@ -3642,21 +3665,31 @@
}
// Hydration (when unsupported)
+
var supportsHydration = false;
var canHydrateInstance = shim$1;
var canHydrateTextInstance = shim$1;
+var canHydrateSuspenseInstance = shim$1;
+var isSuspenseInstancePending = shim$1;
+var isSuspenseInstanceFallback = shim$1;
+var registerSuspenseInstanceRetry = shim$1;
var getNextHydratableSibling = shim$1;
var getFirstHydratableChild = shim$1;
var hydrateInstance = shim$1;
var hydrateTextInstance = shim$1;
+var getNextHydratableInstanceAfterSuspenseInstance = shim$1;
+var clearSuspenseBoundary = shim$1;
+var clearSuspenseBoundaryFromContainer = shim$1;
var didNotMatchHydratedContainerTextInstance = shim$1;
var didNotMatchHydratedTextInstance = shim$1;
var didNotHydrateContainerInstance = shim$1;
var didNotHydrateInstance = shim$1;
var didNotFindHydratableContainerInstance = shim$1;
var didNotFindHydratableContainerTextInstance = shim$1;
+var didNotFindHydratableContainerSuspenseInstance = shim$1;
var didNotFindHydratableInstance = shim$1;
var didNotFindHydratableTextInstance = shim$1;
+var didNotFindHydratableSuspenseInstance = shim$1;
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
@@ -3733,6 +3766,15 @@
nativeProps
) {
{
+ if (warnAboutDeprecatedSetNativeProps) {
+ warningWithoutStack$1(
+ false,
+ "Warning: Calling ref.setNativeProps(nativeProps) " +
+ "is deprecated and will be removed in a future release. " +
+ "Use the setNativeProps export from the react-native package instead." +
+ "\n\timport {setNativeProps} from 'react-native';\n\tsetNativeProps(ref, nativeProps);\n"
+ );
+ }
warnForStyleProps(nativeProps, this.viewConfig.validAttributes);
}
@@ -3910,6 +3952,8 @@
var scheduleTimeout = setTimeout;
var cancelTimeout = clearTimeout;
var noTimeout = -1;
+var schedulePassiveEffects = scheduleDeferredCallback$$1;
+var cancelPassiveEffects = cancelDeferredCallback$$1;
// -------------------
// Persistence
@@ -4110,17 +4154,6 @@
}
}
-var debugRenderPhaseSideEffects = false;
-var debugRenderPhaseSideEffectsForStrictMode = false;
-var enableUserTimingAPI = true;
-var enableHooks = false;
-var warnAboutDeprecatedLifecycles = false;
-var replayFailedUnitOfWorkWithInvokeGuardedCallback = true;
-var enableProfilerTimer = true;
-var enableSchedulerTracing = true;
-
-// Only used in www builds.
-
// Prefix measurements so that it's possible to filter them.
// Longer prefixes are hard to read in DevTools.
var reactEmoji = "\u269B";
@@ -4392,7 +4425,8 @@
}
fiber._debugIsCurrentlyTiming = false;
var warning =
- fiber.tag === SuspenseComponent
+ fiber.tag === SuspenseComponent ||
+ fiber.tag === DehydratedSuspenseComponent
? "Rendering was suspended"
: "An error was thrown inside this error boundary";
endFiberMark(fiber, null, warning);
@@ -5116,7 +5150,7 @@
this.memoizedProps = null;
this.updateQueue = null;
this.memoizedState = null;
- this.firstContextDependency = null;
+ this.contextDependencies = null;
this.mode = mode;
@@ -5133,14 +5167,16 @@
this.alternate = null;
if (enableProfilerTimer) {
- // Note: The following is done to avoid a v8 deopt.
+ // Note: The following is done to avoid a v8 performance cliff.
//
- // It is important to initialize the fields below with doubles.
- // Otherwise Fibers will deopt and end up having separate shapes when
- // doubles are later assigned to fields that initially contained smis.
- // This is a bug in v8 having something to do with Object.preventExtension().
+ // Initializing the fields below to smis and later updating them with
+ // double values will cause Fibers to end up having separate shapes.
+ // This behavior/bug has something to do with Object.preventExtension().
+ // Fortunately this only impacts DEV builds.
+ // Unfortunately it makes React unusably slow for some applications.
+ // To work around this, initialize the fields below with doubles.
//
- // Learn more about this deopt here:
+ // Learn more about this here:
// https://github.com/facebook/react/issues/14365
// https://bugs.chromium.org/p/v8/issues/detail?id=8538
this.actualDuration = Number.NaN;
@@ -5149,7 +5185,8 @@
this.treeBaseDuration = Number.NaN;
// It's okay to replace the initial doubles with smis after initialization.
- // This simplifies other profiler code and doesn't trigger the deopt.
+ // This won't trigger the performance cliff mentioned above,
+ // and it simplifies other profiler code (including DevTools).
this.actualDuration = 0;
this.actualStartTime = -1;
this.selfBaseDuration = 0;
@@ -5270,7 +5307,7 @@
workInProgress.memoizedProps = current.memoizedProps;
workInProgress.memoizedState = current.memoizedState;
workInProgress.updateQueue = current.updateQueue;
- workInProgress.firstContextDependency = current.firstContextDependency;
+ workInProgress.contextDependencies = current.contextDependencies;
// These will be overridden during the parent's reconciliation
workInProgress.sibling = current.sibling;
@@ -5536,7 +5573,7 @@
target.memoizedProps = source.memoizedProps;
target.updateQueue = source.updateQueue;
target.memoizedState = source.memoizedState;
- target.firstContextDependency = source.firstContextDependency;
+ target.contextDependencies = source.contextDependencies;
target.mode = source.mode;
target.effectTag = source.effectTag;
target.nextEffect = source.nextEffect;
@@ -5589,6 +5626,8 @@
latestSuspendedTime: NoWork,
latestPingedTime: NoWork,
+ pingCache: null,
+
didError: false,
pendingCommitExpirationTime: NoWork,
@@ -5612,6 +5651,8 @@
containerInfo: containerInfo,
pendingChildren: null,
+ pingCache: null,
+
earliestPendingTime: NoWork,
latestPendingTime: NoWork,
earliestSuspendedTime: NoWork,
@@ -5761,7 +5802,7 @@
lifecycleWarningsMap,
strictRoot
) {
- var lifecyclesWarningMesages = [];
+ var lifecyclesWarningMessages = [];
Object.keys(lifecycleWarningsMap).forEach(function(lifecycle) {
var lifecycleWarnings = lifecycleWarningsMap[lifecycle];
@@ -5776,7 +5817,7 @@
var suggestion = LIFECYCLE_SUGGESTIONS[lifecycle];
var sortedComponentNames = setToSortedString(componentNames);
- lifecyclesWarningMesages.push(
+ lifecyclesWarningMessages.push(
formatted +
": Please update the following components to use " +
(suggestion + " instead: " + sortedComponentNames)
@@ -5784,7 +5825,7 @@
}
});
- if (lifecyclesWarningMesages.length > 0) {
+ if (lifecyclesWarningMessages.length > 0) {
var strictRootComponentStack = getStackByFiberInDevAndProd(strictRoot);
warningWithoutStack$1(
@@ -5794,7 +5835,7 @@
"\n\nLearn more about this warning here:" +
"\nhttps://fb.me/react-strict-mode-warnings",
strictRootComponentStack,
- lifecyclesWarningMesages.join("\n\n")
+ lifecyclesWarningMessages.join("\n\n")
);
}
});
@@ -6095,6 +6136,10 @@
return;
}
+ if (earliestRemainingTime < root.latestPingedTime) {
+ root.latestPingedTime = NoWork;
+ }
+
// Let's see if the previous latest known pending level was just flushed.
var latestPendingTime = root.latestPendingTime;
if (latestPendingTime !== NoWork) {
@@ -6230,10 +6275,8 @@
}
function clearPing(root, completedTime) {
- // TODO: Track whether the root was pinged during the render phase. If so,
- // we need to make sure we don't lose track of it.
var latestPingedTime = root.latestPingedTime;
- if (latestPingedTime !== NoWork && latestPingedTime >= completedTime) {
+ if (latestPingedTime >= completedTime) {
root.latestPingedTime = NoWork;
}
}
@@ -6294,561 +6337,6 @@
root.expirationTime = expirationTime;
}
-// UpdateQueue is a linked list of prioritized updates.
-//
-// Like fibers, update queues come in pairs: a current queue, which represents
-// the visible state of the screen, and a work-in-progress queue, which is
-// can be mutated and processed asynchronously before it is committed — a form
-// of double buffering. If a work-in-progress render is discarded before
-// finishing, we create a new work-in-progress by cloning the current queue.
-//
-// Both queues share a persistent, singly-linked list structure. To schedule an
-// update, we append it to the end of both queues. Each queue maintains a
-// pointer to first update in the persistent list that hasn't been processed.
-// The work-in-progress pointer always has a position equal to or greater than
-// the current queue, since we always work on that one. The current queue's
-// pointer is only updated during the commit phase, when we swap in the
-// work-in-progress.
-//
-// For example:
-//
-// Current pointer: A - B - C - D - E - F
-// Work-in-progress pointer: D - E - F
-// ^
-// The work-in-progress queue has
-// processed more updates than current.
-//
-// The reason we append to both queues is because otherwise we might drop
-// updates without ever processing them. For example, if we only add updates to
-// the work-in-progress queue, some updates could be lost whenever a work-in
-// -progress render restarts by cloning from current. Similarly, if we only add
-// updates to the current queue, the updates will be lost whenever an already
-// in-progress queue commits and swaps with the current queue. However, by
-// adding to both queues, we guarantee that the update will be part of the next
-// work-in-progress. (And because the work-in-progress queue becomes the
-// current queue once it commits, there's no danger of applying the same
-// update twice.)
-//
-// Prioritization
-// --------------
-//
-// Updates are not sorted by priority, but by insertion; new updates are always
-// appended to the end of the list.
-//
-// The priority is still important, though. When processing the update queue
-// during the render phase, only the updates with sufficient priority are
-// included in the result. If we skip an update because it has insufficient
-// priority, it remains in the queue to be processed later, during a lower
-// priority render. Crucially, all updates subsequent to a skipped update also
-// remain in the queue *regardless of their priority*. That means high priority
-// updates are sometimes processed twice, at two separate priorities. We also
-// keep track of a base state, that represents the state before the first
-// update in the queue is applied.
-//
-// For example:
-//
-// Given a base state of '', and the following queue of updates
-//
-// A1 - B2 - C1 - D2
-//
-// where the number indicates the priority, and the update is applied to the
-// previous state by appending a letter, React will process these updates as
-// two separate renders, one per distinct priority level:
-//
-// First render, at priority 1:
-// Base state: ''
-// Updates: [A1, C1]
-// Result state: 'AC'
-//
-// Second render, at priority 2:
-// Base state: 'A' <- The base state does not include C1,
-// because B2 was skipped.
-// Updates: [B2, C1, D2] <- C1 was rebased on top of B2
-// Result state: 'ABCD'
-//
-// Because we process updates in insertion order, and rebase high priority
-// updates when preceding updates are skipped, the final result is deterministic
-// regardless of priority. Intermediate state may vary according to system
-// resources, but the final state is always the same.
-
-var UpdateState = 0;
-var ReplaceState = 1;
-var ForceUpdate = 2;
-var CaptureUpdate = 3;
-
-// Global state that is reset at the beginning of calling `processUpdateQueue`.
-// It should only be read right after calling `processUpdateQueue`, via
-// `checkHasForceUpdateAfterProcessing`.
-var hasForceUpdate = false;
-
-var didWarnUpdateInsideUpdate = void 0;
-var currentlyProcessingQueue = void 0;
-var resetCurrentlyProcessingQueue = void 0;
-{
- didWarnUpdateInsideUpdate = false;
- currentlyProcessingQueue = null;
- resetCurrentlyProcessingQueue = function() {
- currentlyProcessingQueue = null;
- };
-}
-
-function createUpdateQueue(baseState) {
- var queue = {
- baseState: baseState,
- firstUpdate: null,
- lastUpdate: null,
- firstCapturedUpdate: null,
- lastCapturedUpdate: null,
- firstEffect: null,
- lastEffect: null,
- firstCapturedEffect: null,
- lastCapturedEffect: null
- };
- return queue;
-}
-
-function cloneUpdateQueue(currentQueue) {
- var queue = {
- baseState: currentQueue.baseState,
- firstUpdate: currentQueue.firstUpdate,
- lastUpdate: currentQueue.lastUpdate,
-
- // TODO: With resuming, if we bail out and resuse the child tree, we should
- // keep these effects.
- firstCapturedUpdate: null,
- lastCapturedUpdate: null,
-
- firstEffect: null,
- lastEffect: null,
-
- firstCapturedEffect: null,
- lastCapturedEffect: null
- };
- return queue;
-}
-
-function createUpdate(expirationTime) {
- return {
- expirationTime: expirationTime,
-
- tag: UpdateState,
- payload: null,
- callback: null,
-
- next: null,
- nextEffect: null
- };
-}
-
-function appendUpdateToQueue(queue, update) {
- // Append the update to the end of the list.
- if (queue.lastUpdate === null) {
- // Queue is empty
- queue.firstUpdate = queue.lastUpdate = update;
- } else {
- queue.lastUpdate.next = update;
- queue.lastUpdate = update;
- }
-}
-
-function enqueueUpdate(fiber, update) {
- // Update queues are created lazily.
- var alternate = fiber.alternate;
- var queue1 = void 0;
- var queue2 = void 0;
- if (alternate === null) {
- // There's only one fiber.
- queue1 = fiber.updateQueue;
- queue2 = null;
- if (queue1 === null) {
- queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState);
- }
- } else {
- // There are two owners.
- queue1 = fiber.updateQueue;
- queue2 = alternate.updateQueue;
- if (queue1 === null) {
- if (queue2 === null) {
- // Neither fiber has an update queue. Create new ones.
- queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState);
- queue2 = alternate.updateQueue = createUpdateQueue(
- alternate.memoizedState
- );
- } else {
- // Only one fiber has an update queue. Clone to create a new one.
- queue1 = fiber.updateQueue = cloneUpdateQueue(queue2);
- }
- } else {
- if (queue2 === null) {
- // Only one fiber has an update queue. Clone to create a new one.
- queue2 = alternate.updateQueue = cloneUpdateQueue(queue1);
- } else {
- // Both owners have an update queue.
- }
- }
- }
- if (queue2 === null || queue1 === queue2) {
- // There's only a single queue.
- appendUpdateToQueue(queue1, update);
- } else {
- // There are two queues. We need to append the update to both queues,
- // while accounting for the persistent structure of the list — we don't
- // want the same update to be added multiple times.
- if (queue1.lastUpdate === null || queue2.lastUpdate === null) {
- // One of the queues is not empty. We must add the update to both queues.
- appendUpdateToQueue(queue1, update);
- appendUpdateToQueue(queue2, update);
- } else {
- // Both queues are non-empty. The last update is the same in both lists,
- // because of structural sharing. So, only append to one of the lists.
- appendUpdateToQueue(queue1, update);
- // But we still need to update the `lastUpdate` pointer of queue2.
- queue2.lastUpdate = update;
- }
- }
-
- {
- if (
- fiber.tag === ClassComponent &&
- (currentlyProcessingQueue === queue1 ||
- (queue2 !== null && currentlyProcessingQueue === queue2)) &&
- !didWarnUpdateInsideUpdate
- ) {
- warningWithoutStack$1(
- false,
- "An update (setState, replaceState, or forceUpdate) was scheduled " +
- "from inside an update function. Update functions should be pure, " +
- "with zero side-effects. Consider using componentDidUpdate or a " +
- "callback."
- );
- didWarnUpdateInsideUpdate = true;
- }
- }
-}
-
-function enqueueCapturedUpdate(workInProgress, update) {
- // Captured updates go into a separate list, and only on the work-in-
- // progress queue.
- var workInProgressQueue = workInProgress.updateQueue;
- if (workInProgressQueue === null) {
- workInProgressQueue = workInProgress.updateQueue = createUpdateQueue(
- workInProgress.memoizedState
- );
- } else {
- // TODO: I put this here rather than createWorkInProgress so that we don't
- // clone the queue unnecessarily. There's probably a better way to
- // structure this.
- workInProgressQueue = ensureWorkInProgressQueueIsAClone(
- workInProgress,
- workInProgressQueue
- );
- }
-
- // Append the update to the end of the list.
- if (workInProgressQueue.lastCapturedUpdate === null) {
- // This is the first render phase update
- workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update;
- } else {
- workInProgressQueue.lastCapturedUpdate.next = update;
- workInProgressQueue.lastCapturedUpdate = update;
- }
-}
-
-function ensureWorkInProgressQueueIsAClone(workInProgress, queue) {
- var current = workInProgress.alternate;
- if (current !== null) {
- // If the work-in-progress queue is equal to the current queue,
- // we need to clone it first.
- if (queue === current.updateQueue) {
- queue = workInProgress.updateQueue = cloneUpdateQueue(queue);
- }
- }
- return queue;
-}
-
-function getStateFromUpdate(
- workInProgress,
- queue,
- update,
- prevState,
- nextProps,
- instance
-) {
- switch (update.tag) {
- case ReplaceState: {
- var _payload = update.payload;
- if (typeof _payload === "function") {
- // Updater function
- {
- if (
- debugRenderPhaseSideEffects ||
- (debugRenderPhaseSideEffectsForStrictMode &&
- workInProgress.mode & StrictMode)
- ) {
- _payload.call(instance, prevState, nextProps);
- }
- }
- return _payload.call(instance, prevState, nextProps);
- }
- // State object
- return _payload;
- }
- case CaptureUpdate: {
- workInProgress.effectTag =
- (workInProgress.effectTag & ~ShouldCapture) | DidCapture;
- }
- // Intentional fallthrough
- case UpdateState: {
- var _payload2 = update.payload;
- var partialState = void 0;
- if (typeof _payload2 === "function") {
- // Updater function
- {
- if (
- debugRenderPhaseSideEffects ||
- (debugRenderPhaseSideEffectsForStrictMode &&
- workInProgress.mode & StrictMode)
- ) {
- _payload2.call(instance, prevState, nextProps);
- }
- }
- partialState = _payload2.call(instance, prevState, nextProps);
- } else {
- // Partial state object
- partialState = _payload2;
- }
- if (partialState === null || partialState === undefined) {
- // Null and undefined are treated as no-ops.
- return prevState;
- }
- // Merge the partial state and the previous state.
- return Object.assign({}, prevState, partialState);
- }
- case ForceUpdate: {
- hasForceUpdate = true;
- return prevState;
- }
- }
- return prevState;
-}
-
-function processUpdateQueue(
- workInProgress,
- queue,
- props,
- instance,
- renderExpirationTime
-) {
- hasForceUpdate = false;
-
- queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue);
-
- {
- currentlyProcessingQueue = queue;
- }
-
- // These values may change as we process the queue.
- var newBaseState = queue.baseState;
- var newFirstUpdate = null;
- var newExpirationTime = NoWork;
-
- // Iterate through the list of updates to compute the result.
- var update = queue.firstUpdate;
- var resultState = newBaseState;
- while (update !== null) {
- var updateExpirationTime = update.expirationTime;
- if (updateExpirationTime < renderExpirationTime) {
- // This update does not have sufficient priority. Skip it.
- if (newFirstUpdate === null) {
- // This is the first skipped update. It will be the first update in
- // the new list.
- newFirstUpdate = update;
- // Since this is the first update that was skipped, the current result
- // is the new base state.
- newBaseState = resultState;
- }
- // Since this update will remain in the list, update the remaining
- // expiration time.
- if (newExpirationTime < updateExpirationTime) {
- newExpirationTime = updateExpirationTime;
- }
- } else {
- // This update does have sufficient priority. Process it and compute
- // a new result.
- resultState = getStateFromUpdate(
- workInProgress,
- queue,
- update,
- resultState,
- props,
- instance
- );
- var _callback = update.callback;
- if (_callback !== null) {
- workInProgress.effectTag |= Callback;
- // Set this to null, in case it was mutated during an aborted render.
- update.nextEffect = null;
- if (queue.lastEffect === null) {
- queue.firstEffect = queue.lastEffect = update;
- } else {
- queue.lastEffect.nextEffect = update;
- queue.lastEffect = update;
- }
- }
- }
- // Continue to the next update.
- update = update.next;
- }
-
- // Separately, iterate though the list of captured updates.
- var newFirstCapturedUpdate = null;
- update = queue.firstCapturedUpdate;
- while (update !== null) {
- var _updateExpirationTime = update.expirationTime;
- if (_updateExpirationTime < renderExpirationTime) {
- // This update does not have sufficient priority. Skip it.
- if (newFirstCapturedUpdate === null) {
- // This is the first skipped captured update. It will be the first
- // update in the new list.
- newFirstCapturedUpdate = update;
- // If this is the first update that was skipped, the current result is
- // the new base state.
- if (newFirstUpdate === null) {
- newBaseState = resultState;
- }
- }
- // Since this update will remain in the list, update the remaining
- // expiration time.
- if (newExpirationTime < _updateExpirationTime) {
- newExpirationTime = _updateExpirationTime;
- }
- } else {
- // This update does have sufficient priority. Process it and compute
- // a new result.
- resultState = getStateFromUpdate(
- workInProgress,
- queue,
- update,
- resultState,
- props,
- instance
- );
- var _callback2 = update.callback;
- if (_callback2 !== null) {
- workInProgress.effectTag |= Callback;
- // Set this to null, in case it was mutated during an aborted render.
- update.nextEffect = null;
- if (queue.lastCapturedEffect === null) {
- queue.firstCapturedEffect = queue.lastCapturedEffect = update;
- } else {
- queue.lastCapturedEffect.nextEffect = update;
- queue.lastCapturedEffect = update;
- }
- }
- }
- update = update.next;
- }
-
- if (newFirstUpdate === null) {
- queue.lastUpdate = null;
- }
- if (newFirstCapturedUpdate === null) {
- queue.lastCapturedUpdate = null;
- } else {
- workInProgress.effectTag |= Callback;
- }
- if (newFirstUpdate === null && newFirstCapturedUpdate === null) {
- // We processed every update, without skipping. That means the new base
- // state is the same as the result state.
- newBaseState = resultState;
- }
-
- queue.baseState = newBaseState;
- queue.firstUpdate = newFirstUpdate;
- queue.firstCapturedUpdate = newFirstCapturedUpdate;
-
- // Set the remaining expiration time to be whatever is remaining in the queue.
- // This should be fine because the only two other things that contribute to
- // expiration time are props and context. We're already in the middle of the
- // begin phase by the time we start processing the queue, so we've already
- // dealt with the props. Context in components that specify
- // shouldComponentUpdate is tricky; but we'll have to account for
- // that regardless.
- workInProgress.expirationTime = newExpirationTime;
- workInProgress.memoizedState = resultState;
-
- {
- currentlyProcessingQueue = null;
- }
-}
-
-function callCallback(callback, context) {
- invariant(
- typeof callback === "function",
- "Invalid argument passed as callback. Expected a function. Instead " +
- "received: %s",
- callback
- );
- callback.call(context);
-}
-
-function resetHasForceUpdateBeforeProcessing() {
- hasForceUpdate = false;
-}
-
-function checkHasForceUpdateAfterProcessing() {
- return hasForceUpdate;
-}
-
-function commitUpdateQueue(
- finishedWork,
- finishedQueue,
- instance,
- renderExpirationTime
-) {
- // If the finished render included captured updates, and there are still
- // lower priority updates left over, we need to keep the captured updates
- // in the queue so that they are rebased and not dropped once we process the
- // queue again at the lower priority.
- if (finishedQueue.firstCapturedUpdate !== null) {
- // Join the captured update list to the end of the normal list.
- if (finishedQueue.lastUpdate !== null) {
- finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate;
- finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate;
- }
- // Clear the list of captured updates.
- finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null;
- }
-
- // Commit the effects
- commitUpdateEffects(finishedQueue.firstEffect, instance);
- finishedQueue.firstEffect = finishedQueue.lastEffect = null;
-
- commitUpdateEffects(finishedQueue.firstCapturedEffect, instance);
- finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null;
-}
-
-function commitUpdateEffects(effect, instance) {
- while (effect !== null) {
- var _callback3 = effect.callback;
- if (_callback3 !== null) {
- effect.callback = null;
- callCallback(_callback3, instance);
- }
- effect = effect.nextEffect;
- }
-}
-
-function createCapturedValue(value, source) {
- // If the value is an error, call this function immediately after it is thrown
- // so the stack is accurate.
- return {
- value: value,
- source: source,
- stack: getStackByFiberInDevAndProd(source)
- };
-}
-
/**
* Similar to invariant but only logs a warning if the condition is not met.
* This can be used to log issues in development environments in critical
@@ -6886,1046 +6374,18 @@
var warning$1 = warning;
-var valueCursor = createCursor(null);
-
-var rendererSigil = void 0;
-{
- // Use this to detect multiple renderers using the same context
- rendererSigil = {};
-}
-
-var currentlyRenderingFiber = null;
-var lastContextDependency = null;
-var lastContextWithAllBitsObserved = null;
-
-function resetContextDependences() {
- // This is called right before React yields execution, to ensure `readContext`
- // cannot be called outside the render phase.
- currentlyRenderingFiber = null;
- lastContextDependency = null;
- lastContextWithAllBitsObserved = null;
-}
-
-function pushProvider(providerFiber, nextValue) {
- var context = providerFiber.type._context;
-
- if (isPrimaryRenderer) {
- push(valueCursor, context._currentValue, providerFiber);
-
- context._currentValue = nextValue;
- {
- !(
- context._currentRenderer === undefined ||
- context._currentRenderer === null ||
- context._currentRenderer === rendererSigil
- )
- ? warningWithoutStack$1(
- false,
- "Detected multiple renderers concurrently rendering the " +
- "same context provider. This is currently unsupported."
- )
- : void 0;
- context._currentRenderer = rendererSigil;
- }
- } else {
- push(valueCursor, context._currentValue2, providerFiber);
-
- context._currentValue2 = nextValue;
- {
- !(
- context._currentRenderer2 === undefined ||
- context._currentRenderer2 === null ||
- context._currentRenderer2 === rendererSigil
- )
- ? warningWithoutStack$1(
- false,
- "Detected multiple renderers concurrently rendering the " +
- "same context provider. This is currently unsupported."
- )
- : void 0;
- context._currentRenderer2 = rendererSigil;
- }
- }
-}
-
-function popProvider(providerFiber) {
- var currentValue = valueCursor.current;
-
- pop(valueCursor, providerFiber);
-
- var context = providerFiber.type._context;
- if (isPrimaryRenderer) {
- context._currentValue = currentValue;
- } else {
- context._currentValue2 = currentValue;
- }
-}
-
-function calculateChangedBits(context, newValue, oldValue) {
- // Use Object.is to compare the new context value to the old value. Inlined
- // Object.is polyfill.
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
- if (
- (oldValue === newValue &&
- (oldValue !== 0 || 1 / oldValue === 1 / newValue)) ||
- (oldValue !== oldValue && newValue !== newValue) // eslint-disable-line no-self-compare
- ) {
- // No change
- return 0;
- } else {
- var changedBits =
- typeof context._calculateChangedBits === "function"
- ? context._calculateChangedBits(oldValue, newValue)
- : maxSigned31BitInt;
-
- {
- !((changedBits & maxSigned31BitInt) === changedBits)
- ? warning$1(
- false,
- "calculateChangedBits: Expected the return value to be a " +
- "31-bit integer. Instead received: %s",
- changedBits
- )
- : void 0;
- }
- return changedBits | 0;
- }
-}
-
-function propagateContextChange(
- workInProgress,
- context,
- changedBits,
- renderExpirationTime
-) {
- var fiber = workInProgress.child;
- if (fiber !== null) {
- // Set the return pointer of the child to the work-in-progress fiber.
- fiber.return = workInProgress;
- }
- while (fiber !== null) {
- var nextFiber = void 0;
-
- // Visit this fiber.
- var dependency = fiber.firstContextDependency;
- if (dependency !== null) {
- do {
- // Check if the context matches.
- if (
- dependency.context === context &&
- (dependency.observedBits & changedBits) !== 0
- ) {
- // Match! Schedule an update on this fiber.
-
- if (fiber.tag === ClassComponent) {
- // Schedule a force update on the work-in-progress.
- var update = createUpdate(renderExpirationTime);
- update.tag = ForceUpdate;
- // TODO: Because we don't have a work-in-progress, this will add the
- // update to the current fiber, too, which means it will persist even if
- // this render is thrown away. Since it's a race condition, not sure it's
- // worth fixing.
- enqueueUpdate(fiber, update);
- }
-
- if (fiber.expirationTime < renderExpirationTime) {
- fiber.expirationTime = renderExpirationTime;
- }
- var alternate = fiber.alternate;
- if (
- alternate !== null &&
- alternate.expirationTime < renderExpirationTime
- ) {
- alternate.expirationTime = renderExpirationTime;
- }
- // Update the child expiration time of all the ancestors, including
- // the alternates.
- var node = fiber.return;
- while (node !== null) {
- alternate = node.alternate;
- if (node.childExpirationTime < renderExpirationTime) {
- node.childExpirationTime = renderExpirationTime;
- if (
- alternate !== null &&
- alternate.childExpirationTime < renderExpirationTime
- ) {
- alternate.childExpirationTime = renderExpirationTime;
- }
- } else if (
- alternate !== null &&
- alternate.childExpirationTime < renderExpirationTime
- ) {
- alternate.childExpirationTime = renderExpirationTime;
- } else {
- // Neither alternate was updated, which means the rest of the
- // ancestor path already has sufficient priority.
- break;
- }
- node = node.return;
- }
- }
- nextFiber = fiber.child;
- dependency = dependency.next;
- } while (dependency !== null);
- } else if (fiber.tag === ContextProvider) {
- // Don't scan deeper if this is a matching provider
- nextFiber = fiber.type === workInProgress.type ? null : fiber.child;
- } else {
- // Traverse down.
- nextFiber = fiber.child;
- }
-
- if (nextFiber !== null) {
- // Set the return pointer of the child to the work-in-progress fiber.
- nextFiber.return = fiber;
- } else {
- // No child. Traverse to next sibling.
- nextFiber = fiber;
- while (nextFiber !== null) {
- if (nextFiber === workInProgress) {
- // We're back to the root of this subtree. Exit.
- nextFiber = null;
- break;
- }
- var sibling = nextFiber.sibling;
- if (sibling !== null) {
- // Set the return pointer of the sibling to the work-in-progress fiber.
- sibling.return = nextFiber.return;
- nextFiber = sibling;
- break;
- }
- // No more siblings. Traverse up.
- nextFiber = nextFiber.return;
- }
- }
- fiber = nextFiber;
- }
-}
-
-function prepareToReadContext(workInProgress, renderExpirationTime) {
- currentlyRenderingFiber = workInProgress;
- lastContextDependency = null;
- lastContextWithAllBitsObserved = null;
-
- // Reset the work-in-progress list
- workInProgress.firstContextDependency = null;
-}
-
-function readContext(context, observedBits) {
- if (lastContextWithAllBitsObserved === context) {
- // Nothing to do. We already observe everything in this context.
- } else if (observedBits === false || observedBits === 0) {
- // Do not observe any updates.
- } else {
- var resolvedObservedBits = void 0; // Avoid deopting on observable arguments or heterogeneous types.
- if (
- typeof observedBits !== "number" ||
- observedBits === maxSigned31BitInt
- ) {
- // Observe all updates.
- lastContextWithAllBitsObserved = context;
- resolvedObservedBits = maxSigned31BitInt;
- } else {
- resolvedObservedBits = observedBits;
- }
-
- var contextItem = {
- context: context,
- observedBits: resolvedObservedBits,
- next: null
- };
-
- if (lastContextDependency === null) {
- invariant(
- currentlyRenderingFiber !== null,
- "Context can only be read while React is " +
- "rendering, e.g. inside the render method or getDerivedStateFromProps."
- );
- // This is the first dependency in the list
- currentlyRenderingFiber.firstContextDependency = lastContextDependency = contextItem;
- } else {
- // Append a new context item.
- lastContextDependency = lastContextDependency.next = contextItem;
- }
- }
- return isPrimaryRenderer ? context._currentValue : context._currentValue2;
-}
-
-var NoEffect$1 = /* */ 0;
-var UnmountSnapshot = /* */ 2;
-var UnmountMutation = /* */ 4;
-var MountMutation = /* */ 8;
-var UnmountLayout = /* */ 16;
-var MountLayout = /* */ 32;
-var MountPassive = /* */ 64;
-var UnmountPassive = /* */ 128;
-
-function areHookInputsEqual(arr1, arr2) {
- // Don't bother comparing lengths in prod because these arrays should be
- // passed inline.
- {
- !(arr1.length === arr2.length)
- ? warning$1(
- false,
- "Detected a variable number of hook dependencies. The length of the " +
- "dependencies array should be constant between renders.\n\n" +
- "Previous: %s\n" +
- "Incoming: %s",
- arr1.join(", "),
- arr2.join(", ")
- )
- : void 0;
- }
- for (var i = 0; i < arr1.length; i++) {
- // Inlined Object.is polyfill.
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
- var val1 = arr1[i];
- var val2 = arr2[i];
- if (
- (val1 === val2 && (val1 !== 0 || 1 / val1 === 1 / val2)) ||
- (val1 !== val1 && val2 !== val2) // eslint-disable-line no-self-compare
- ) {
- continue;
- }
- return false;
- }
- return true;
-}
-
-// These are set right before calling the component.
-var renderExpirationTime = NoWork;
-// The work-in-progress fiber. I've named it differently to distinguish it from
-// the work-in-progress hook.
-var currentlyRenderingFiber$1 = null;
-
-// Hooks are stored as a linked list on the fiber's memoizedState field. The
-// current hook list is the list that belongs to the current fiber. The
-// work-in-progress hook list is a new list that will be added to the
-// work-in-progress fiber.
-var firstCurrentHook = null;
-var currentHook = null;
-var firstWorkInProgressHook = null;
-var workInProgressHook = null;
-
-var remainingExpirationTime = NoWork;
-var componentUpdateQueue = null;
-
-// Updates scheduled during render will trigger an immediate re-render at the
-// end of the current pass. We can't store these updates on the normal queue,
-// because if the work is aborted, they should be discarded. Because this is
-// a relatively rare case, we also don't want to add an additional field to
-// either the hook or queue object types. So we store them in a lazily create
-// map of queue -> render-phase updates, which are discarded once the component
-// completes without re-rendering.
-
-// Whether the work-in-progress hook is a re-rendered hook
-var isReRender = false;
-// Whether an update was scheduled during the currently executing render pass.
-var didScheduleRenderPhaseUpdate = false;
-// Lazily created map of render-phase updates
-var renderPhaseUpdates = null;
-// Counter to prevent infinite loops.
-var numberOfReRenders = 0;
-var RE_RENDER_LIMIT = 25;
-
-function resolveCurrentlyRenderingFiber() {
- invariant(
- currentlyRenderingFiber$1 !== null,
- "Hooks can only be called inside the body of a function component."
- );
- return currentlyRenderingFiber$1;
-}
-
-function prepareToUseHooks(current, workInProgress, nextRenderExpirationTime) {
- if (!enableHooks) {
- return;
- }
- renderExpirationTime = nextRenderExpirationTime;
- currentlyRenderingFiber$1 = workInProgress;
- firstCurrentHook = current !== null ? current.memoizedState : null;
-
- // The following should have already been reset
- // currentHook = null;
- // workInProgressHook = null;
-
- // remainingExpirationTime = NoWork;
- // componentUpdateQueue = null;
-
- // isReRender = false;
- // didScheduleRenderPhaseUpdate = false;
- // renderPhaseUpdates = null;
- // numberOfReRenders = 0;
-}
-
-function finishHooks(Component, props, children, refOrContext) {
- if (!enableHooks) {
- return children;
- }
-
- // This must be called after every function component to prevent hooks from
- // being used in classes.
-
- while (didScheduleRenderPhaseUpdate) {
- // Updates were scheduled during the render phase. They are stored in
- // the `renderPhaseUpdates` map. Call the component again, reusing the
- // work-in-progress hooks and applying the additional updates on top. Keep
- // restarting until no more updates are scheduled.
- didScheduleRenderPhaseUpdate = false;
- numberOfReRenders += 1;
-
- // Start over from the beginning of the list
- currentHook = null;
- workInProgressHook = null;
- componentUpdateQueue = null;
-
- children = Component(props, refOrContext);
- }
- renderPhaseUpdates = null;
- numberOfReRenders = 0;
-
- var renderedWork = currentlyRenderingFiber$1;
-
- renderedWork.memoizedState = firstWorkInProgressHook;
- renderedWork.expirationTime = remainingExpirationTime;
- renderedWork.updateQueue = componentUpdateQueue;
-
- var didRenderTooFewHooks = currentHook !== null && currentHook.next !== null;
-
- renderExpirationTime = NoWork;
- currentlyRenderingFiber$1 = null;
-
- firstCurrentHook = null;
- currentHook = null;
- firstWorkInProgressHook = null;
- workInProgressHook = null;
-
- remainingExpirationTime = NoWork;
- componentUpdateQueue = null;
-
- // Always set during createWorkInProgress
- // isReRender = false;
-
- // These were reset above
- // didScheduleRenderPhaseUpdate = false;
- // renderPhaseUpdates = null;
- // numberOfReRenders = 0;
-
- invariant(
- !didRenderTooFewHooks,
- "Rendered fewer hooks than expected. This may be caused by an accidental " +
- "early return statement."
- );
-
- return children;
-}
-
-function resetHooks() {
- if (!enableHooks) {
- return;
- }
-
- // This is called instead of `finishHooks` if the component throws. It's also
- // called inside mountIndeterminateComponent if we determine the component
- // is a module-style component.
- renderExpirationTime = NoWork;
- currentlyRenderingFiber$1 = null;
-
- firstCurrentHook = null;
- currentHook = null;
- firstWorkInProgressHook = null;
- workInProgressHook = null;
-
- remainingExpirationTime = NoWork;
- componentUpdateQueue = null;
-
- // Always set during createWorkInProgress
- // isReRender = false;
-
- didScheduleRenderPhaseUpdate = false;
- renderPhaseUpdates = null;
- numberOfReRenders = 0;
-}
-
-function createHook() {
- return {
- memoizedState: null,
-
- baseState: null,
- queue: null,
- baseUpdate: null,
-
- next: null
- };
-}
-
-function cloneHook(hook) {
- return {
- memoizedState: hook.memoizedState,
-
- baseState: hook.baseState,
- queue: hook.queue,
- baseUpdate: hook.baseUpdate,
-
- next: null
- };
-}
-
-function createWorkInProgressHook() {
- if (workInProgressHook === null) {
- // This is the first hook in the list
- if (firstWorkInProgressHook === null) {
- isReRender = false;
- currentHook = firstCurrentHook;
- if (currentHook === null) {
- // This is a newly mounted hook
- workInProgressHook = createHook();
- } else {
- // Clone the current hook.
- workInProgressHook = cloneHook(currentHook);
- }
- firstWorkInProgressHook = workInProgressHook;
- } else {
- // There's already a work-in-progress. Reuse it.
- isReRender = true;
- currentHook = firstCurrentHook;
- workInProgressHook = firstWorkInProgressHook;
- }
- } else {
- if (workInProgressHook.next === null) {
- isReRender = false;
- var hook = void 0;
- if (currentHook === null) {
- // This is a newly mounted hook
- hook = createHook();
- } else {
- currentHook = currentHook.next;
- if (currentHook === null) {
- // This is a newly mounted hook
- hook = createHook();
- } else {
- // Clone the current hook.
- hook = cloneHook(currentHook);
- }
- }
- // Append to the end of the list
- workInProgressHook = workInProgressHook.next = hook;
- } else {
- // There's already a work-in-progress. Reuse it.
- isReRender = true;
- workInProgressHook = workInProgressHook.next;
- currentHook = currentHook !== null ? currentHook.next : null;
- }
- }
- return workInProgressHook;
-}
-
-function createFunctionComponentUpdateQueue() {
- return {
- lastEffect: null
- };
-}
-
-function basicStateReducer(state, action) {
- return typeof action === "function" ? action(state) : action;
-}
-
-function useContext(context, observedBits) {
- // Ensure we're in a function component (class components support only the
- // .unstable_read() form)
- resolveCurrentlyRenderingFiber();
- return readContext(context, observedBits);
-}
-
-function useState(initialState) {
- return useReducer(
- basicStateReducer,
- // useReducer has a special case to support lazy useState initializers
- initialState
- );
-}
-
-function useReducer(reducer, initialState, initialAction) {
- currentlyRenderingFiber$1 = resolveCurrentlyRenderingFiber();
- workInProgressHook = createWorkInProgressHook();
- var queue = workInProgressHook.queue;
- if (queue !== null) {
- // Already have a queue, so this is an update.
- if (isReRender) {
- // This is a re-render. Apply the new render phase updates to the previous
- var _dispatch2 = queue.dispatch;
- if (renderPhaseUpdates !== null) {
- // Render phase updates are stored in a map of queue -> linked list
- var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
- if (firstRenderPhaseUpdate !== undefined) {
- renderPhaseUpdates.delete(queue);
- var newState = workInProgressHook.memoizedState;
- var update = firstRenderPhaseUpdate;
- do {
- // Process this render phase update. We don't have to check the
- // priority because it will always be the same as the current
- // render's.
- var _action = update.action;
- newState = reducer(newState, _action);
- update = update.next;
- } while (update !== null);
-
- workInProgressHook.memoizedState = newState;
-
- // Don't persist the state accumlated from the render phase updates to
- // the base state unless the queue is empty.
- // TODO: Not sure if this is the desired semantics, but it's what we
- // do for gDSFP. I can't remember why.
- if (workInProgressHook.baseUpdate === queue.last) {
- workInProgressHook.baseState = newState;
- }
-
- return [newState, _dispatch2];
- }
- }
- return [workInProgressHook.memoizedState, _dispatch2];
- }
-
- // The last update in the entire queue
- var _last = queue.last;
- // The last update that is part of the base state.
- var _baseUpdate = workInProgressHook.baseUpdate;
-
- // Find the first unprocessed update.
- var first = void 0;
- if (_baseUpdate !== null) {
- if (_last !== null) {
- // For the first update, the queue is a circular linked list where
- // `queue.last.next = queue.first`. Once the first update commits, and
- // the `baseUpdate` is no longer empty, we can unravel the list.
- _last.next = null;
- }
- first = _baseUpdate.next;
- } else {
- first = _last !== null ? _last.next : null;
- }
- if (first !== null) {
- var _newState = workInProgressHook.baseState;
- var newBaseState = null;
- var newBaseUpdate = null;
- var prevUpdate = _baseUpdate;
- var _update = first;
- var didSkip = false;
- do {
- var updateExpirationTime = _update.expirationTime;
- if (updateExpirationTime < renderExpirationTime) {
- // Priority is insufficient. Skip this update. If this is the first
- // skipped update, the previous update/state is the new base
- // update/state.
- if (!didSkip) {
- didSkip = true;
- newBaseUpdate = prevUpdate;
- newBaseState = _newState;
- }
- // Update the remaining priority in the queue.
- if (updateExpirationTime > remainingExpirationTime) {
- remainingExpirationTime = updateExpirationTime;
- }
- } else {
- // Process this update.
- var _action2 = _update.action;
- _newState = reducer(_newState, _action2);
- }
- prevUpdate = _update;
- _update = _update.next;
- } while (_update !== null && _update !== first);
-
- if (!didSkip) {
- newBaseUpdate = prevUpdate;
- newBaseState = _newState;
- }
-
- workInProgressHook.memoizedState = _newState;
- workInProgressHook.baseUpdate = newBaseUpdate;
- workInProgressHook.baseState = newBaseState;
- }
-
- var _dispatch = queue.dispatch;
- return [workInProgressHook.memoizedState, _dispatch];
- }
-
- // There's no existing queue, so this is the initial render.
- if (reducer === basicStateReducer) {
- // Special case for `useState`.
- if (typeof initialState === "function") {
- initialState = initialState();
- }
- } else if (initialAction !== undefined && initialAction !== null) {
- initialState = reducer(initialState, initialAction);
- }
- workInProgressHook.memoizedState = workInProgressHook.baseState = initialState;
- queue = workInProgressHook.queue = {
- last: null,
- dispatch: null
- };
- var dispatch = (queue.dispatch = dispatchAction.bind(
- null,
- currentlyRenderingFiber$1,
- queue
- ));
- return [workInProgressHook.memoizedState, dispatch];
-}
-
-function pushEffect(tag, create, destroy, inputs) {
- var effect = {
- tag: tag,
- create: create,
- destroy: destroy,
- inputs: inputs,
- // Circular
- next: null
- };
- if (componentUpdateQueue === null) {
- componentUpdateQueue = createFunctionComponentUpdateQueue();
- componentUpdateQueue.lastEffect = effect.next = effect;
- } else {
- var _lastEffect = componentUpdateQueue.lastEffect;
- if (_lastEffect === null) {
- componentUpdateQueue.lastEffect = effect.next = effect;
- } else {
- var firstEffect = _lastEffect.next;
- _lastEffect.next = effect;
- effect.next = firstEffect;
- componentUpdateQueue.lastEffect = effect;
- }
- }
- return effect;
-}
-
-function useRef(initialValue) {
- currentlyRenderingFiber$1 = resolveCurrentlyRenderingFiber();
- workInProgressHook = createWorkInProgressHook();
- var ref = void 0;
-
- if (workInProgressHook.memoizedState === null) {
- ref = { current: initialValue };
- {
- Object.seal(ref);
- }
- workInProgressHook.memoizedState = ref;
- } else {
- ref = workInProgressHook.memoizedState;
- }
- return ref;
-}
-
-function useLayoutEffect(create, inputs) {
- useEffectImpl(Update, UnmountMutation | MountLayout, create, inputs);
-}
-
-function useEffect(create, inputs) {
- useEffectImpl(
- Update | Passive,
- UnmountPassive | MountPassive,
- create,
- inputs
- );
-}
-
-function useEffectImpl(fiberEffectTag, hookEffectTag, create, inputs) {
- currentlyRenderingFiber$1 = resolveCurrentlyRenderingFiber();
- workInProgressHook = createWorkInProgressHook();
-
- var nextInputs = inputs !== undefined && inputs !== null ? inputs : [create];
- var destroy = null;
- if (currentHook !== null) {
- var prevEffect = currentHook.memoizedState;
- destroy = prevEffect.destroy;
- if (areHookInputsEqual(nextInputs, prevEffect.inputs)) {
- pushEffect(NoEffect$1, create, destroy, nextInputs);
- return;
- }
- }
-
- currentlyRenderingFiber$1.effectTag |= fiberEffectTag;
- workInProgressHook.memoizedState = pushEffect(
- hookEffectTag,
- create,
- destroy,
- nextInputs
- );
-}
-
-function useImperativeMethods(ref, create, inputs) {
- // TODO: If inputs are provided, should we skip comparing the ref itself?
- var nextInputs =
- inputs !== null && inputs !== undefined
- ? inputs.concat([ref])
- : [ref, create];
-
- // TODO: I've implemented this on top of useEffect because it's almost the
- // same thing, and it would require an equal amount of code. It doesn't seem
- // like a common enough use case to justify the additional size.
- useLayoutEffect(function() {
- if (typeof ref === "function") {
- var refCallback = ref;
- var _inst = create();
- refCallback(_inst);
- return function() {
- return refCallback(null);
- };
- } else if (ref !== null && ref !== undefined) {
- var refObject = ref;
- var _inst2 = create();
- refObject.current = _inst2;
- return function() {
- refObject.current = null;
- };
- }
- }, nextInputs);
-}
-
-function useCallback(callback, inputs) {
- currentlyRenderingFiber$1 = resolveCurrentlyRenderingFiber();
- workInProgressHook = createWorkInProgressHook();
-
- var nextInputs =
- inputs !== undefined && inputs !== null ? inputs : [callback];
-
- var prevState = workInProgressHook.memoizedState;
- if (prevState !== null) {
- var prevInputs = prevState[1];
- if (areHookInputsEqual(nextInputs, prevInputs)) {
- return prevState[0];
- }
- }
- workInProgressHook.memoizedState = [callback, nextInputs];
- return callback;
-}
-
-function useMemo(nextCreate, inputs) {
- currentlyRenderingFiber$1 = resolveCurrentlyRenderingFiber();
- workInProgressHook = createWorkInProgressHook();
-
- var nextInputs =
- inputs !== undefined && inputs !== null ? inputs : [nextCreate];
-
- var prevState = workInProgressHook.memoizedState;
- if (prevState !== null) {
- var prevInputs = prevState[1];
- if (areHookInputsEqual(nextInputs, prevInputs)) {
- return prevState[0];
- }
- }
-
- var nextValue = nextCreate();
- workInProgressHook.memoizedState = [nextValue, nextInputs];
- return nextValue;
-}
-
-function dispatchAction(fiber, queue, action) {
- invariant(
- numberOfReRenders < RE_RENDER_LIMIT,
- "Too many re-renders. React limits the number of renders to prevent " +
- "an infinite loop."
- );
-
- var alternate = fiber.alternate;
- if (
- fiber === currentlyRenderingFiber$1 ||
- (alternate !== null && alternate === currentlyRenderingFiber$1)
- ) {
- // This is a render phase update. Stash it in a lazily-created map of
- // queue -> linked list of updates. After this render pass, we'll restart
- // and apply the stashed updates on top of the work-in-progress hook.
- didScheduleRenderPhaseUpdate = true;
- var update = {
- expirationTime: renderExpirationTime,
- action: action,
- next: null
- };
- if (renderPhaseUpdates === null) {
- renderPhaseUpdates = new Map();
- }
- var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
- if (firstRenderPhaseUpdate === undefined) {
- renderPhaseUpdates.set(queue, update);
- } else {
- // Append the update to the end of the list.
- var lastRenderPhaseUpdate = firstRenderPhaseUpdate;
- while (lastRenderPhaseUpdate.next !== null) {
- lastRenderPhaseUpdate = lastRenderPhaseUpdate.next;
- }
- lastRenderPhaseUpdate.next = update;
- }
- } else {
- var currentTime = requestCurrentTime();
- var _expirationTime = computeExpirationForFiber(currentTime, fiber);
- var _update2 = {
- expirationTime: _expirationTime,
- action: action,
- next: null
- };
- flushPassiveEffects();
- // Append the update to the end of the list.
- var _last2 = queue.last;
- if (_last2 === null) {
- // This is the first update. Create a circular list.
- _update2.next = _update2;
- } else {
- var first = _last2.next;
- if (first !== null) {
- // Still circular.
- _update2.next = first;
- }
- _last2.next = _update2;
- }
- queue.last = _update2;
- scheduleWork(fiber, _expirationTime);
- }
-}
-
-var NO_CONTEXT = {};
-
-var contextStackCursor$1 = createCursor(NO_CONTEXT);
-var contextFiberStackCursor = createCursor(NO_CONTEXT);
-var rootInstanceStackCursor = createCursor(NO_CONTEXT);
-
-function requiredContext(c) {
- invariant(
- c !== NO_CONTEXT,
- "Expected host context to exist. This error is likely caused by a bug " +
- "in React. Please file an issue."
- );
- return c;
-}
-
-function getRootHostContainer() {
- var rootInstance = requiredContext(rootInstanceStackCursor.current);
- return rootInstance;
-}
-
-function pushHostContainer(fiber, nextRootInstance) {
- // Push current root instance onto the stack;
- // This allows us to reset root when portals are popped.
- push(rootInstanceStackCursor, nextRootInstance, fiber);
- // Track the context and the Fiber that provided it.
- // This enables us to pop only Fibers that provide unique contexts.
- push(contextFiberStackCursor, fiber, fiber);
-
- // Finally, we need to push the host context to the stack.
- // However, we can't just call getRootHostContext() and push it because
- // we'd have a different number of entries on the stack depending on
- // whether getRootHostContext() throws somewhere in renderer code or not.
- // So we push an empty value first. This lets us safely unwind on errors.
- push(contextStackCursor$1, NO_CONTEXT, fiber);
- var nextRootContext = getRootHostContext(nextRootInstance);
- // Now that we know this function doesn't throw, replace it.
- pop(contextStackCursor$1, fiber);
- push(contextStackCursor$1, nextRootContext, fiber);
-}
-
-function popHostContainer(fiber) {
- pop(contextStackCursor$1, fiber);
- pop(contextFiberStackCursor, fiber);
- pop(rootInstanceStackCursor, fiber);
-}
-
-function getHostContext() {
- var context = requiredContext(contextStackCursor$1.current);
- return context;
-}
-
-function pushHostContext(fiber) {
- var rootInstance = requiredContext(rootInstanceStackCursor.current);
- var context = requiredContext(contextStackCursor$1.current);
- var nextContext = getChildHostContext(context, fiber.type, rootInstance);
-
- // Don't push this Fiber's context unless it's unique.
- if (context === nextContext) {
- return;
- }
-
- // Track the context and the Fiber that provided it.
- // This enables us to pop only Fibers that provide unique contexts.
- push(contextFiberStackCursor, fiber, fiber);
- push(contextStackCursor$1, nextContext, fiber);
-}
-
-function popHostContext(fiber) {
- // Do not pop unless this Fiber provided the current context.
- // pushHostContext() only pushes Fibers that provide unique contexts.
- if (contextFiberStackCursor.current !== fiber) {
- return;
- }
-
- pop(contextStackCursor$1, fiber);
- pop(contextFiberStackCursor, fiber);
-}
-
-var commitTime = 0;
-var profilerStartTime = -1;
-
-function getCommitTime() {
- return commitTime;
-}
-
-function recordCommitTime() {
- if (!enableProfilerTimer) {
- return;
- }
- commitTime = now$$1();
-}
-
-function startProfilerTimer(fiber) {
- if (!enableProfilerTimer) {
- return;
- }
-
- profilerStartTime = now$$1();
-
- if (fiber.actualStartTime < 0) {
- fiber.actualStartTime = now$$1();
- }
-}
-
-function stopProfilerTimerIfRunning(fiber) {
- if (!enableProfilerTimer) {
- return;
- }
- profilerStartTime = -1;
-}
-
-function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) {
- if (!enableProfilerTimer) {
- return;
- }
-
- if (profilerStartTime >= 0) {
- var elapsedTime = now$$1() - profilerStartTime;
- fiber.actualDuration += elapsedTime;
- if (overrideBaseTime) {
- fiber.selfBaseDuration = elapsedTime;
- }
- profilerStartTime = -1;
- }
-}
-
-/*eslint-disable no-self-compare */
-
-var hasOwnProperty = Object.prototype.hasOwnProperty;
-
/**
* inlined Object.is polyfill to avoid requiring consumers ship their own
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
*/
function is(x, y) {
- // SameValue algorithm
- if (x === y) {
- // Steps 1-5, 7-10
- // Steps 6.b-6.e: +0 != -0
- // Added the nonzero y check to make Flow happy, but it is redundant
- return x !== 0 || y !== 0 || 1 / x === 1 / y;
- } else {
- // Step 6.a: NaN == NaN
- return x !== x && y !== y;
- }
+ return (
+ (x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y) // eslint-disable-line no-self-compare
+ );
}
+var hasOwnProperty = Object.prototype.hasOwnProperty;
+
/**
* Performs equality by iterating through keys on an object and returning false
* when any key has values which are not strictly equal between the arguments.
@@ -8026,19 +6486,19 @@
}
}
);
+ // Handle synchronous thenables.
+ switch (lazyComponent._status) {
+ case Resolved:
+ return lazyComponent._result;
+ case Rejected:
+ throw lazyComponent._result;
+ }
lazyComponent._result = _thenable;
throw _thenable;
}
}
}
-var ReactCurrentOwner$4 = ReactSharedInternals.ReactCurrentOwner;
-
-function readContext$1(contextType) {
- var dispatcher = ReactCurrentOwner$4.currentDispatcher;
- return dispatcher.readContext(contextType);
-}
-
var fakeInternalInstance = {};
var isArray$1 = Array.isArray;
@@ -8548,7 +7008,7 @@
}
}
- context = readContext$1(contextType);
+ context = readContext(contextType);
} else {
unmaskedContext = getUnmaskedContext(workInProgress, ctor, true);
var contextTypes = ctor.contextTypes;
@@ -8750,7 +7210,7 @@
var contextType = ctor.contextType;
if (typeof contextType === "object" && contextType !== null) {
- instance.context = readContext$1(contextType);
+ instance.context = readContext(contextType);
} else {
var unmaskedContext = getUnmaskedContext(workInProgress, ctor, true);
instance.context = getMaskedContext(workInProgress, unmaskedContext);
@@ -8858,7 +7318,7 @@
var contextType = ctor.contextType;
var nextContext = void 0;
if (typeof contextType === "object" && contextType !== null) {
- nextContext = readContext$1(contextType);
+ nextContext = readContext(contextType);
} else {
var nextLegacyUnmaskedContext = getUnmaskedContext(
workInProgress,
@@ -9007,7 +7467,7 @@
var contextType = ctor.contextType;
var nextContext = void 0;
if (typeof contextType === "object" && contextType !== null) {
- nextContext = readContext$1(contextType);
+ nextContext = readContext(contextType);
} else {
var nextUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true);
nextContext = getMaskedContext(workInProgress, nextUnmaskedContext);
@@ -9197,7 +7657,7 @@
child._store.validated = true;
var currentComponentErrorInfo =
- "Each child in an array or iterator should have a unique " +
+ "Each child in a list should have a unique " +
'"key" prop. See https://fb.me/react-warning-keys for ' +
"more information." +
getCurrentFiberStackInDev();
@@ -9208,7 +7668,7 @@
warning$1(
false,
- "Each child in an array or iterator should have a unique " +
+ "Each child in a list should have a unique " +
'"key" prop. See https://fb.me/react-warning-keys for ' +
"more information."
);
@@ -9251,7 +7711,8 @@
var ownerFiber = owner;
invariant(
ownerFiber.tag === ClassComponent,
- "Function components cannot have refs."
+ "Function components cannot have refs. " +
+ "Did you mean to use React.forwardRef()?"
);
inst = ownerFiber.stateNode;
}
@@ -9815,7 +8276,7 @@
newChildren,
expirationTime
) {
- // This algorithm can't optimize by searching from boths ends since we
+ // This algorithm can't optimize by searching from both ends since we
// don't have backpointers on fibers. I'm trying to see how far we can get
// with that model. If it ends up not being worth the tradeoffs, we can
// add it later.
@@ -10457,6 +8918,1387 @@
newChild.sibling = null;
}
+var NO_CONTEXT = {};
+
+var contextStackCursor$1 = createCursor(NO_CONTEXT);
+var contextFiberStackCursor = createCursor(NO_CONTEXT);
+var rootInstanceStackCursor = createCursor(NO_CONTEXT);
+
+function requiredContext(c) {
+ invariant(
+ c !== NO_CONTEXT,
+ "Expected host context to exist. This error is likely caused by a bug " +
+ "in React. Please file an issue."
+ );
+ return c;
+}
+
+function getRootHostContainer() {
+ var rootInstance = requiredContext(rootInstanceStackCursor.current);
+ return rootInstance;
+}
+
+function pushHostContainer(fiber, nextRootInstance) {
+ // Push current root instance onto the stack;
+ // This allows us to reset root when portals are popped.
+ push(rootInstanceStackCursor, nextRootInstance, fiber);
+ // Track the context and the Fiber that provided it.
+ // This enables us to pop only Fibers that provide unique contexts.
+ push(contextFiberStackCursor, fiber, fiber);
+
+ // Finally, we need to push the host context to the stack.
+ // However, we can't just call getRootHostContext() and push it because
+ // we'd have a different number of entries on the stack depending on
+ // whether getRootHostContext() throws somewhere in renderer code or not.
+ // So we push an empty value first. This lets us safely unwind on errors.
+ push(contextStackCursor$1, NO_CONTEXT, fiber);
+ var nextRootContext = getRootHostContext(nextRootInstance);
+ // Now that we know this function doesn't throw, replace it.
+ pop(contextStackCursor$1, fiber);
+ push(contextStackCursor$1, nextRootContext, fiber);
+}
+
+function popHostContainer(fiber) {
+ pop(contextStackCursor$1, fiber);
+ pop(contextFiberStackCursor, fiber);
+ pop(rootInstanceStackCursor, fiber);
+}
+
+function getHostContext() {
+ var context = requiredContext(contextStackCursor$1.current);
+ return context;
+}
+
+function pushHostContext(fiber) {
+ var rootInstance = requiredContext(rootInstanceStackCursor.current);
+ var context = requiredContext(contextStackCursor$1.current);
+ var nextContext = getChildHostContext(context, fiber.type, rootInstance);
+
+ // Don't push this Fiber's context unless it's unique.
+ if (context === nextContext) {
+ return;
+ }
+
+ // Track the context and the Fiber that provided it.
+ // This enables us to pop only Fibers that provide unique contexts.
+ push(contextFiberStackCursor, fiber, fiber);
+ push(contextStackCursor$1, nextContext, fiber);
+}
+
+function popHostContext(fiber) {
+ // Do not pop unless this Fiber provided the current context.
+ // pushHostContext() only pushes Fibers that provide unique contexts.
+ if (contextFiberStackCursor.current !== fiber) {
+ return;
+ }
+
+ pop(contextStackCursor$1, fiber);
+ pop(contextFiberStackCursor, fiber);
+}
+
+var NoEffect$1 = /* */ 0;
+var UnmountSnapshot = /* */ 2;
+var UnmountMutation = /* */ 4;
+var MountMutation = /* */ 8;
+var UnmountLayout = /* */ 16;
+var MountLayout = /* */ 32;
+var MountPassive = /* */ 64;
+var UnmountPassive = /* */ 128;
+
+var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher;
+
+var didWarnAboutMismatchedHooksForComponent = void 0;
+{
+ didWarnAboutMismatchedHooksForComponent = new Set();
+}
+
+// These are set right before calling the component.
+var renderExpirationTime = NoWork;
+// The work-in-progress fiber. I've named it differently to distinguish it from
+// the work-in-progress hook.
+var currentlyRenderingFiber$1 = null;
+
+// Hooks are stored as a linked list on the fiber's memoizedState field. The
+// current hook list is the list that belongs to the current fiber. The
+// work-in-progress hook list is a new list that will be added to the
+// work-in-progress fiber.
+var firstCurrentHook = null;
+var currentHook = null;
+var nextCurrentHook = null;
+var firstWorkInProgressHook = null;
+var workInProgressHook = null;
+var nextWorkInProgressHook = null;
+
+var remainingExpirationTime = NoWork;
+var componentUpdateQueue = null;
+var sideEffectTag = 0;
+
+// Updates scheduled during render will trigger an immediate re-render at the
+// end of the current pass. We can't store these updates on the normal queue,
+// because if the work is aborted, they should be discarded. Because this is
+// a relatively rare case, we also don't want to add an additional field to
+// either the hook or queue object types. So we store them in a lazily create
+// map of queue -> render-phase updates, which are discarded once the component
+// completes without re-rendering.
+
+// Whether an update was scheduled during the currently executing render pass.
+var didScheduleRenderPhaseUpdate = false;
+// Lazily created map of render-phase updates
+var renderPhaseUpdates = null;
+// Counter to prevent infinite loops.
+var numberOfReRenders = 0;
+var RE_RENDER_LIMIT = 25;
+
+// In DEV, this is the name of the currently executing primitive hook
+var currentHookNameInDev = null;
+
+function warnOnHookMismatchInDev() {
+ {
+ var componentName = getComponentName(currentlyRenderingFiber$1.type);
+ if (!didWarnAboutMismatchedHooksForComponent.has(componentName)) {
+ didWarnAboutMismatchedHooksForComponent.add(componentName);
+
+ var secondColumnStart = 22;
+
+ var table = "";
+ var prevHook = firstCurrentHook;
+ var nextHook = firstWorkInProgressHook;
+ var n = 1;
+ while (prevHook !== null && nextHook !== null) {
+ var oldHookName = prevHook._debugType;
+ var newHookName = nextHook._debugType;
+
+ var row = n + ". " + oldHookName;
+
+ // Extra space so second column lines up
+ // lol @ IE not supporting String#repeat
+ while (row.length < secondColumnStart) {
+ row += " ";
+ }
+
+ row += newHookName + "\n";
+
+ table += row;
+ prevHook = prevHook.next;
+ nextHook = nextHook.next;
+ n++;
+ }
+
+ warning$1(
+ false,
+ "React has detected a change in the order of Hooks called by %s. " +
+ "This will lead to bugs and errors if not fixed. " +
+ "For more information, read the Rules of Hooks: https://fb.me/rules-of-hooks\n\n" +
+ " Previous render Next render\n" +
+ " -------------------------------\n" +
+ "%s" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
+ componentName,
+ table
+ );
+ }
+ }
+}
+
+function throwInvalidHookError() {
+ invariant(
+ false,
+ "Hooks can only be called inside the body of a function component. " +
+ "(https://fb.me/react-invalid-hook-call)"
+ );
+}
+
+function areHookInputsEqual(nextDeps, prevDeps) {
+ if (prevDeps === null) {
+ {
+ warning$1(
+ false,
+ "%s received a final argument during this render, but not during " +
+ "the previous render. Even though the final argument is optional, " +
+ "its type cannot change between renders.",
+ currentHookNameInDev
+ );
+ }
+ return false;
+ }
+
+ {
+ // Don't bother comparing lengths in prod because these arrays should be
+ // passed inline.
+ if (nextDeps.length !== prevDeps.length) {
+ warning$1(
+ false,
+ "The final argument passed to %s changed size between renders. The " +
+ "order and size of this array must remain constant.\n\n" +
+ "Previous: %s\n" +
+ "Incoming: %s",
+ currentHookNameInDev,
+ "[" + nextDeps.join(", ") + "]",
+ "[" + prevDeps.join(", ") + "]"
+ );
+ }
+ }
+ for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
+ if (is(nextDeps[i], prevDeps[i])) {
+ continue;
+ }
+ return false;
+ }
+ return true;
+}
+
+function renderWithHooks(
+ current,
+ workInProgress,
+ Component,
+ props,
+ refOrContext,
+ nextRenderExpirationTime
+) {
+ renderExpirationTime = nextRenderExpirationTime;
+ currentlyRenderingFiber$1 = workInProgress;
+ firstCurrentHook = nextCurrentHook =
+ current !== null ? current.memoizedState : null;
+
+ // The following should have already been reset
+ // currentHook = null;
+ // workInProgressHook = null;
+
+ // remainingExpirationTime = NoWork;
+ // componentUpdateQueue = null;
+
+ // didScheduleRenderPhaseUpdate = false;
+ // renderPhaseUpdates = null;
+ // numberOfReRenders = 0;
+ // sideEffectTag = 0;
+
+ {
+ ReactCurrentDispatcher$1.current =
+ nextCurrentHook === null
+ ? HooksDispatcherOnMountInDEV
+ : HooksDispatcherOnUpdateInDEV;
+ }
+
+ var children = Component(props, refOrContext);
+
+ if (didScheduleRenderPhaseUpdate) {
+ do {
+ didScheduleRenderPhaseUpdate = false;
+ numberOfReRenders += 1;
+
+ // Start over from the beginning of the list
+ firstCurrentHook = nextCurrentHook =
+ current !== null ? current.memoizedState : null;
+ nextWorkInProgressHook = firstWorkInProgressHook;
+
+ currentHook = null;
+ workInProgressHook = null;
+ componentUpdateQueue = null;
+
+ ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdateInDEV;
+
+ children = Component(props, refOrContext);
+ } while (didScheduleRenderPhaseUpdate);
+
+ renderPhaseUpdates = null;
+ numberOfReRenders = 0;
+ }
+
+ {
+ currentHookNameInDev = null;
+ }
+
+ // We can assume the previous dispatcher is always this one, since we set it
+ // at the beginning of the render phase and there's no re-entrancy.
+ ReactCurrentDispatcher$1.current = ContextOnlyDispatcher;
+
+ var renderedWork = currentlyRenderingFiber$1;
+
+ renderedWork.memoizedState = firstWorkInProgressHook;
+ renderedWork.expirationTime = remainingExpirationTime;
+ renderedWork.updateQueue = componentUpdateQueue;
+ renderedWork.effectTag |= sideEffectTag;
+
+ var didRenderTooFewHooks = currentHook !== null && currentHook.next !== null;
+
+ renderExpirationTime = NoWork;
+ currentlyRenderingFiber$1 = null;
+
+ firstCurrentHook = null;
+ currentHook = null;
+ nextCurrentHook = null;
+ firstWorkInProgressHook = null;
+ workInProgressHook = null;
+ nextWorkInProgressHook = null;
+
+ remainingExpirationTime = NoWork;
+ componentUpdateQueue = null;
+ sideEffectTag = 0;
+
+ // These were reset above
+ // didScheduleRenderPhaseUpdate = false;
+ // renderPhaseUpdates = null;
+ // numberOfReRenders = 0;
+
+ invariant(
+ !didRenderTooFewHooks,
+ "Rendered fewer hooks than expected. This may be caused by an accidental " +
+ "early return statement."
+ );
+
+ return children;
+}
+
+function bailoutHooks(current, workInProgress, expirationTime) {
+ workInProgress.updateQueue = current.updateQueue;
+ workInProgress.effectTag &= ~(Passive | Update);
+ if (current.expirationTime <= expirationTime) {
+ current.expirationTime = NoWork;
+ }
+}
+
+function resetHooks() {
+ // We can assume the previous dispatcher is always this one, since we set it
+ // at the beginning of the render phase and there's no re-entrancy.
+ ReactCurrentDispatcher$1.current = ContextOnlyDispatcher;
+
+ // This is used to reset the state of this module when a component throws.
+ // It's also called inside mountIndeterminateComponent if we determine the
+ // component is a module-style component.
+ renderExpirationTime = NoWork;
+ currentlyRenderingFiber$1 = null;
+
+ firstCurrentHook = null;
+ currentHook = null;
+ nextCurrentHook = null;
+ firstWorkInProgressHook = null;
+ workInProgressHook = null;
+ nextWorkInProgressHook = null;
+
+ remainingExpirationTime = NoWork;
+ componentUpdateQueue = null;
+ sideEffectTag = 0;
+
+ {
+ currentHookNameInDev = null;
+ }
+
+ didScheduleRenderPhaseUpdate = false;
+ renderPhaseUpdates = null;
+ numberOfReRenders = 0;
+}
+
+function mountWorkInProgressHook() {
+ var hook = {
+ memoizedState: null,
+
+ baseState: null,
+ queue: null,
+ baseUpdate: null,
+
+ next: null
+ };
+
+ {
+ hook._debugType = currentHookNameInDev;
+ }
+ if (workInProgressHook === null) {
+ // This is the first hook in the list
+ firstWorkInProgressHook = workInProgressHook = hook;
+ } else {
+ // Append to the end of the list
+ workInProgressHook = workInProgressHook.next = hook;
+ }
+ return workInProgressHook;
+}
+
+function updateWorkInProgressHook() {
+ // This function is used both for updates and for re-renders triggered by a
+ // render phase update. It assumes there is either a current hook we can
+ // clone, or a work-in-progress hook from a previous render pass that we can
+ // use as a base. When we reach the end of the base list, we must switch to
+ // the dispatcher used for mounts.
+ if (nextWorkInProgressHook !== null) {
+ // There's already a work-in-progress. Reuse it.
+ workInProgressHook = nextWorkInProgressHook;
+ nextWorkInProgressHook = workInProgressHook.next;
+
+ currentHook = nextCurrentHook;
+ nextCurrentHook = currentHook !== null ? currentHook.next : null;
+ } else {
+ // Clone from the current hook.
+ invariant(
+ nextCurrentHook !== null,
+ "Rendered more hooks than during the previous render."
+ );
+ currentHook = nextCurrentHook;
+
+ var newHook = {
+ memoizedState: currentHook.memoizedState,
+
+ baseState: currentHook.baseState,
+ queue: currentHook.queue,
+ baseUpdate: currentHook.baseUpdate,
+
+ next: null
+ };
+
+ if (workInProgressHook === null) {
+ // This is the first hook in the list.
+ workInProgressHook = firstWorkInProgressHook = newHook;
+ } else {
+ // Append to the end of the list.
+ workInProgressHook = workInProgressHook.next = newHook;
+ }
+ nextCurrentHook = currentHook.next;
+
+ {
+ newHook._debugType = currentHookNameInDev;
+ if (currentHookNameInDev !== currentHook._debugType) {
+ warnOnHookMismatchInDev();
+ }
+ }
+ }
+ return workInProgressHook;
+}
+
+function createFunctionComponentUpdateQueue() {
+ return {
+ lastEffect: null
+ };
+}
+
+function basicStateReducer(state, action) {
+ return typeof action === "function" ? action(state) : action;
+}
+
+function mountContext(context, observedBits) {
+ {
+ mountWorkInProgressHook();
+ }
+ return readContext(context, observedBits);
+}
+
+function updateContext(context, observedBits) {
+ {
+ updateWorkInProgressHook();
+ }
+ return readContext(context, observedBits);
+}
+
+function mountReducer(reducer, initialArg, init) {
+ var hook = mountWorkInProgressHook();
+ var initialState = void 0;
+ if (init !== undefined) {
+ initialState = init(initialArg);
+ } else {
+ initialState = initialArg;
+ }
+ hook.memoizedState = hook.baseState = initialState;
+ var queue = (hook.queue = {
+ last: null,
+ dispatch: null,
+ eagerReducer: reducer,
+ eagerState: initialState
+ });
+ var dispatch = (queue.dispatch = dispatchAction.bind(
+ null,
+ // Flow doesn't know this is non-null, but we do.
+ currentlyRenderingFiber$1,
+ queue
+ ));
+ return [hook.memoizedState, dispatch];
+}
+
+function updateReducer(reducer, initialArg, init) {
+ var hook = updateWorkInProgressHook();
+ var queue = hook.queue;
+ invariant(
+ queue !== null,
+ "Should have a queue. This is likely a bug in React. Please file an issue."
+ );
+
+ if (numberOfReRenders > 0) {
+ // This is a re-render. Apply the new render phase updates to the previous
+ var _dispatch = queue.dispatch;
+ if (renderPhaseUpdates !== null) {
+ // Render phase updates are stored in a map of queue -> linked list
+ var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+ if (firstRenderPhaseUpdate !== undefined) {
+ renderPhaseUpdates.delete(queue);
+ var newState = hook.memoizedState;
+ var update = firstRenderPhaseUpdate;
+ do {
+ // Process this render phase update. We don't have to check the
+ // priority because it will always be the same as the current
+ // render's.
+ var _action = update.action;
+ newState = reducer(newState, _action);
+ update = update.next;
+ } while (update !== null);
+
+ // Mark that the fiber performed work, but only if the new state is
+ // different from the current state.
+ if (!is(newState, hook.memoizedState)) {
+ markWorkInProgressReceivedUpdate();
+ }
+
+ hook.memoizedState = newState;
+ // Don't persist the state accumlated from the render phase updates to
+ // the base state unless the queue is empty.
+ // TODO: Not sure if this is the desired semantics, but it's what we
+ // do for gDSFP. I can't remember why.
+ if (hook.baseUpdate === queue.last) {
+ hook.baseState = newState;
+ }
+
+ queue.eagerReducer = reducer;
+ queue.eagerState = newState;
+
+ return [newState, _dispatch];
+ }
+ }
+ return [hook.memoizedState, _dispatch];
+ }
+
+ // The last update in the entire queue
+ var last = queue.last;
+ // The last update that is part of the base state.
+ var baseUpdate = hook.baseUpdate;
+ var baseState = hook.baseState;
+
+ // Find the first unprocessed update.
+ var first = void 0;
+ if (baseUpdate !== null) {
+ if (last !== null) {
+ // For the first update, the queue is a circular linked list where
+ // `queue.last.next = queue.first`. Once the first update commits, and
+ // the `baseUpdate` is no longer empty, we can unravel the list.
+ last.next = null;
+ }
+ first = baseUpdate.next;
+ } else {
+ first = last !== null ? last.next : null;
+ }
+ if (first !== null) {
+ var _newState = baseState;
+ var newBaseState = null;
+ var newBaseUpdate = null;
+ var prevUpdate = baseUpdate;
+ var _update = first;
+ var didSkip = false;
+ do {
+ var updateExpirationTime = _update.expirationTime;
+ if (updateExpirationTime < renderExpirationTime) {
+ // Priority is insufficient. Skip this update. If this is the first
+ // skipped update, the previous update/state is the new base
+ // update/state.
+ if (!didSkip) {
+ didSkip = true;
+ newBaseUpdate = prevUpdate;
+ newBaseState = _newState;
+ }
+ // Update the remaining priority in the queue.
+ if (updateExpirationTime > remainingExpirationTime) {
+ remainingExpirationTime = updateExpirationTime;
+ }
+ } else {
+ // Process this update.
+ if (_update.eagerReducer === reducer) {
+ // If this update was processed eagerly, and its reducer matches the
+ // current reducer, we can use the eagerly computed state.
+ _newState = _update.eagerState;
+ } else {
+ var _action2 = _update.action;
+ _newState = reducer(_newState, _action2);
+ }
+ }
+ prevUpdate = _update;
+ _update = _update.next;
+ } while (_update !== null && _update !== first);
+
+ if (!didSkip) {
+ newBaseUpdate = prevUpdate;
+ newBaseState = _newState;
+ }
+
+ // Mark that the fiber performed work, but only if the new state is
+ // different from the current state.
+ if (!is(_newState, hook.memoizedState)) {
+ markWorkInProgressReceivedUpdate();
+ }
+
+ hook.memoizedState = _newState;
+ hook.baseUpdate = newBaseUpdate;
+ hook.baseState = newBaseState;
+
+ queue.eagerReducer = reducer;
+ queue.eagerState = _newState;
+ }
+
+ var dispatch = queue.dispatch;
+ return [hook.memoizedState, dispatch];
+}
+
+function mountState(initialState) {
+ var hook = mountWorkInProgressHook();
+ if (typeof initialState === "function") {
+ initialState = initialState();
+ }
+ hook.memoizedState = hook.baseState = initialState;
+ var queue = (hook.queue = {
+ last: null,
+ dispatch: null,
+ eagerReducer: basicStateReducer,
+ eagerState: initialState
+ });
+ var dispatch = (queue.dispatch = dispatchAction.bind(
+ null,
+ // Flow doesn't know this is non-null, but we do.
+ currentlyRenderingFiber$1,
+ queue
+ ));
+ return [hook.memoizedState, dispatch];
+}
+
+function updateState(initialState) {
+ return updateReducer(basicStateReducer, initialState);
+}
+
+function pushEffect(tag, create, destroy, deps) {
+ var effect = {
+ tag: tag,
+ create: create,
+ destroy: destroy,
+ deps: deps,
+ // Circular
+ next: null
+ };
+ if (componentUpdateQueue === null) {
+ componentUpdateQueue = createFunctionComponentUpdateQueue();
+ componentUpdateQueue.lastEffect = effect.next = effect;
+ } else {
+ var _lastEffect = componentUpdateQueue.lastEffect;
+ if (_lastEffect === null) {
+ componentUpdateQueue.lastEffect = effect.next = effect;
+ } else {
+ var firstEffect = _lastEffect.next;
+ _lastEffect.next = effect;
+ effect.next = firstEffect;
+ componentUpdateQueue.lastEffect = effect;
+ }
+ }
+ return effect;
+}
+
+function mountRef(initialValue) {
+ var hook = mountWorkInProgressHook();
+ var ref = { current: initialValue };
+ {
+ Object.seal(ref);
+ }
+ hook.memoizedState = ref;
+ return ref;
+}
+
+function updateRef(initialValue) {
+ var hook = updateWorkInProgressHook();
+ return hook.memoizedState;
+}
+
+function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) {
+ var hook = mountWorkInProgressHook();
+ var nextDeps = deps === undefined ? null : deps;
+ sideEffectTag |= fiberEffectTag;
+ hook.memoizedState = pushEffect(hookEffectTag, create, undefined, nextDeps);
+}
+
+function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) {
+ var hook = updateWorkInProgressHook();
+ var nextDeps = deps === undefined ? null : deps;
+ var destroy = undefined;
+
+ if (currentHook !== null) {
+ var prevEffect = currentHook.memoizedState;
+ destroy = prevEffect.destroy;
+ if (nextDeps !== null) {
+ var prevDeps = prevEffect.deps;
+ if (areHookInputsEqual(nextDeps, prevDeps)) {
+ pushEffect(NoEffect$1, create, destroy, nextDeps);
+ return;
+ }
+ }
+ }
+
+ sideEffectTag |= fiberEffectTag;
+ hook.memoizedState = pushEffect(hookEffectTag, create, destroy, nextDeps);
+}
+
+function mountEffect(create, deps) {
+ return mountEffectImpl(
+ Update | Passive,
+ UnmountPassive | MountPassive,
+ create,
+ deps
+ );
+}
+
+function updateEffect(create, deps) {
+ return updateEffectImpl(
+ Update | Passive,
+ UnmountPassive | MountPassive,
+ create,
+ deps
+ );
+}
+
+function mountLayoutEffect(create, deps) {
+ return mountEffectImpl(Update, UnmountMutation | MountLayout, create, deps);
+}
+
+function updateLayoutEffect(create, deps) {
+ return updateEffectImpl(Update, UnmountMutation | MountLayout, create, deps);
+}
+
+function imperativeHandleEffect(create, ref) {
+ if (typeof ref === "function") {
+ var refCallback = ref;
+ var _inst = create();
+ refCallback(_inst);
+ return function() {
+ refCallback(null);
+ };
+ } else if (ref !== null && ref !== undefined) {
+ var refObject = ref;
+ {
+ !refObject.hasOwnProperty("current")
+ ? warning$1(
+ false,
+ "Expected useImperativeHandle() first argument to either be a " +
+ "ref callback or React.createRef() object. Instead received: %s.",
+ "an object with keys {" + Object.keys(refObject).join(", ") + "}"
+ )
+ : void 0;
+ }
+ var _inst2 = create();
+ refObject.current = _inst2;
+ return function() {
+ refObject.current = null;
+ };
+ }
+}
+
+function mountImperativeHandle(ref, create, deps) {
+ {
+ !(typeof create === "function")
+ ? warning$1(
+ false,
+ "Expected useImperativeHandle() second argument to be a function " +
+ "that creates a handle. Instead received: %s.",
+ create !== null ? typeof create : "null"
+ )
+ : void 0;
+ }
+
+ // TODO: If deps are provided, should we skip comparing the ref itself?
+ var effectDeps =
+ deps !== null && deps !== undefined ? deps.concat([ref]) : null;
+
+ return mountEffectImpl(
+ Update,
+ UnmountMutation | MountLayout,
+ imperativeHandleEffect.bind(null, create, ref),
+ effectDeps
+ );
+}
+
+function updateImperativeHandle(ref, create, deps) {
+ {
+ !(typeof create === "function")
+ ? warning$1(
+ false,
+ "Expected useImperativeHandle() second argument to be a function " +
+ "that creates a handle. Instead received: %s.",
+ create !== null ? typeof create : "null"
+ )
+ : void 0;
+ }
+
+ // TODO: If deps are provided, should we skip comparing the ref itself?
+ var effectDeps =
+ deps !== null && deps !== undefined ? deps.concat([ref]) : null;
+
+ return updateEffectImpl(
+ Update,
+ UnmountMutation | MountLayout,
+ imperativeHandleEffect.bind(null, create, ref),
+ effectDeps
+ );
+}
+
+function mountDebugValue(value, formatterFn) {
+ // This hook is normally a no-op.
+ // The react-debug-hooks package injects its own implementation
+ // so that e.g. DevTools can display custom hook values.
+}
+
+var updateDebugValue = mountDebugValue;
+
+function mountCallback(callback, deps) {
+ var hook = mountWorkInProgressHook();
+ var nextDeps = deps === undefined ? null : deps;
+ hook.memoizedState = [callback, nextDeps];
+ return callback;
+}
+
+function updateCallback(callback, deps) {
+ var hook = updateWorkInProgressHook();
+ var nextDeps = deps === undefined ? null : deps;
+ var prevState = hook.memoizedState;
+ if (prevState !== null) {
+ if (nextDeps !== null) {
+ var prevDeps = prevState[1];
+ if (areHookInputsEqual(nextDeps, prevDeps)) {
+ return prevState[0];
+ }
+ }
+ }
+ hook.memoizedState = [callback, nextDeps];
+ return callback;
+}
+
+function mountMemo(nextCreate, deps) {
+ var hook = mountWorkInProgressHook();
+ var nextDeps = deps === undefined ? null : deps;
+ var nextValue = nextCreate();
+ hook.memoizedState = [nextValue, nextDeps];
+ return nextValue;
+}
+
+function updateMemo(nextCreate, deps) {
+ var hook = updateWorkInProgressHook();
+ var nextDeps = deps === undefined ? null : deps;
+ var prevState = hook.memoizedState;
+ if (prevState !== null) {
+ // Assume these are defined. If they're not, areHookInputsEqual will warn.
+ if (nextDeps !== null) {
+ var prevDeps = prevState[1];
+ if (areHookInputsEqual(nextDeps, prevDeps)) {
+ return prevState[0];
+ }
+ }
+ }
+ var nextValue = nextCreate();
+ hook.memoizedState = [nextValue, nextDeps];
+ return nextValue;
+}
+
+// in a test-like environment, we want to warn if dispatchAction()
+// is called outside of a batchedUpdates/TestUtils.act(...) call.
+var shouldWarnForUnbatchedSetState = false;
+
+{
+ // jest isn't a 'global', it's just exposed to tests via a wrapped function
+ // further, this isn't a test file, so flow doesn't recognize the symbol. So...
+ // $FlowExpectedError - because requirements don't give a damn about your type sigs.
+ if ("undefined" !== typeof jest) {
+ shouldWarnForUnbatchedSetState = true;
+ }
+}
+
+function dispatchAction(fiber, queue, action) {
+ invariant(
+ numberOfReRenders < RE_RENDER_LIMIT,
+ "Too many re-renders. React limits the number of renders to prevent " +
+ "an infinite loop."
+ );
+
+ {
+ !(arguments.length <= 3)
+ ? warning$1(
+ false,
+ "State updates from the useState() and useReducer() Hooks don't support the " +
+ "second callback argument. To execute a side effect after " +
+ "rendering, declare it in the component body with useEffect()."
+ )
+ : void 0;
+ }
+
+ var alternate = fiber.alternate;
+ if (
+ fiber === currentlyRenderingFiber$1 ||
+ (alternate !== null && alternate === currentlyRenderingFiber$1)
+ ) {
+ // This is a render phase update. Stash it in a lazily-created map of
+ // queue -> linked list of updates. After this render pass, we'll restart
+ // and apply the stashed updates on top of the work-in-progress hook.
+ didScheduleRenderPhaseUpdate = true;
+ var update = {
+ expirationTime: renderExpirationTime,
+ action: action,
+ eagerReducer: null,
+ eagerState: null,
+ next: null
+ };
+ if (renderPhaseUpdates === null) {
+ renderPhaseUpdates = new Map();
+ }
+ var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+ if (firstRenderPhaseUpdate === undefined) {
+ renderPhaseUpdates.set(queue, update);
+ } else {
+ // Append the update to the end of the list.
+ var lastRenderPhaseUpdate = firstRenderPhaseUpdate;
+ while (lastRenderPhaseUpdate.next !== null) {
+ lastRenderPhaseUpdate = lastRenderPhaseUpdate.next;
+ }
+ lastRenderPhaseUpdate.next = update;
+ }
+ } else {
+ flushPassiveEffects();
+
+ var currentTime = requestCurrentTime();
+ var _expirationTime = computeExpirationForFiber(currentTime, fiber);
+
+ var _update2 = {
+ expirationTime: _expirationTime,
+ action: action,
+ eagerReducer: null,
+ eagerState: null,
+ next: null
+ };
+
+ // Append the update to the end of the list.
+ var _last = queue.last;
+ if (_last === null) {
+ // This is the first update. Create a circular list.
+ _update2.next = _update2;
+ } else {
+ var first = _last.next;
+ if (first !== null) {
+ // Still circular.
+ _update2.next = first;
+ }
+ _last.next = _update2;
+ }
+ queue.last = _update2;
+
+ if (
+ fiber.expirationTime === NoWork &&
+ (alternate === null || alternate.expirationTime === NoWork)
+ ) {
+ // The queue is currently empty, which means we can eagerly compute the
+ // next state before entering the render phase. If the new state is the
+ // same as the current state, we may be able to bail out entirely.
+ var _eagerReducer = queue.eagerReducer;
+ if (_eagerReducer !== null) {
+ var prevDispatcher = void 0;
+ {
+ prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
+ }
+ try {
+ var currentState = queue.eagerState;
+ var _eagerState = _eagerReducer(currentState, action);
+ // Stash the eagerly computed state, and the reducer used to compute
+ // it, on the update object. If the reducer hasn't changed by the
+ // time we enter the render phase, then the eager state can be used
+ // without calling the reducer again.
+ _update2.eagerReducer = _eagerReducer;
+ _update2.eagerState = _eagerState;
+ if (is(_eagerState, currentState)) {
+ // Fast path. We can bail out without scheduling React to re-render.
+ // It's still possible that we'll need to rebase this update later,
+ // if the component re-renders for a different reason and by that
+ // time the reducer has changed.
+ return;
+ }
+ } catch (error) {
+ // Suppress the error. It will throw again in the render phase.
+ } finally {
+ {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ }
+ }
+ }
+ {
+ if (shouldWarnForUnbatchedSetState === true) {
+ warnIfNotCurrentlyBatchingInDev(fiber);
+ }
+ }
+ scheduleWork(fiber, _expirationTime);
+ }
+}
+
+var ContextOnlyDispatcher = {
+ readContext: readContext,
+
+ useCallback: throwInvalidHookError,
+ useContext: throwInvalidHookError,
+ useEffect: throwInvalidHookError,
+ useImperativeHandle: throwInvalidHookError,
+ useLayoutEffect: throwInvalidHookError,
+ useMemo: throwInvalidHookError,
+ useReducer: throwInvalidHookError,
+ useRef: throwInvalidHookError,
+ useState: throwInvalidHookError,
+ useDebugValue: throwInvalidHookError
+};
+
+var HooksDispatcherOnMountInDEV = null;
+var HooksDispatcherOnUpdateInDEV = null;
+var InvalidNestedHooksDispatcherOnMountInDEV = null;
+var InvalidNestedHooksDispatcherOnUpdateInDEV = null;
+
+{
+ var warnInvalidContextAccess = function() {
+ warning$1(
+ false,
+ "Context can only be read while React is rendering. " +
+ "In classes, you can read it in the render method or getDerivedStateFromProps. " +
+ "In function components, you can read it directly in the function body, but not " +
+ "inside Hooks like useReducer() or useMemo()."
+ );
+ };
+
+ var warnInvalidHookAccess = function() {
+ warning$1(
+ false,
+ "Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. " +
+ "You can only call Hooks at the top level of your React function. " +
+ "For more information, see " +
+ "https://fb.me/rules-of-hooks"
+ );
+ };
+
+ HooksDispatcherOnMountInDEV = {
+ readContext: function(context, observedBits) {
+ return readContext(context, observedBits);
+ },
+ useCallback: function(callback, deps) {
+ currentHookNameInDev = "useCallback";
+ return mountCallback(callback, deps);
+ },
+ useContext: function(context, observedBits) {
+ currentHookNameInDev = "useContext";
+ return mountContext(context, observedBits);
+ },
+ useEffect: function(create, deps) {
+ currentHookNameInDev = "useEffect";
+ return mountEffect(create, deps);
+ },
+ useImperativeHandle: function(ref, create, deps) {
+ currentHookNameInDev = "useImperativeHandle";
+ return mountImperativeHandle(ref, create, deps);
+ },
+ useLayoutEffect: function(create, deps) {
+ currentHookNameInDev = "useLayoutEffect";
+ return mountLayoutEffect(create, deps);
+ },
+ useMemo: function(create, deps) {
+ currentHookNameInDev = "useMemo";
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;
+ try {
+ return mountMemo(create, deps);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useReducer: function(reducer, initialArg, init) {
+ currentHookNameInDev = "useReducer";
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;
+ try {
+ return mountReducer(reducer, initialArg, init);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useRef: function(initialValue) {
+ currentHookNameInDev = "useRef";
+ return mountRef(initialValue);
+ },
+ useState: function(initialState) {
+ currentHookNameInDev = "useState";
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;
+ try {
+ return mountState(initialState);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useDebugValue: function(value, formatterFn) {
+ currentHookNameInDev = "useDebugValue";
+ return mountDebugValue(value, formatterFn);
+ }
+ };
+
+ HooksDispatcherOnUpdateInDEV = {
+ readContext: function(context, observedBits) {
+ return readContext(context, observedBits);
+ },
+ useCallback: function(callback, deps) {
+ currentHookNameInDev = "useCallback";
+ return updateCallback(callback, deps);
+ },
+ useContext: function(context, observedBits) {
+ currentHookNameInDev = "useContext";
+ return updateContext(context, observedBits);
+ },
+ useEffect: function(create, deps) {
+ currentHookNameInDev = "useEffect";
+ return updateEffect(create, deps);
+ },
+ useImperativeHandle: function(ref, create, deps) {
+ currentHookNameInDev = "useImperativeHandle";
+ return updateImperativeHandle(ref, create, deps);
+ },
+ useLayoutEffect: function(create, deps) {
+ currentHookNameInDev = "useLayoutEffect";
+ return updateLayoutEffect(create, deps);
+ },
+ useMemo: function(create, deps) {
+ currentHookNameInDev = "useMemo";
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
+ try {
+ return updateMemo(create, deps);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useReducer: function(reducer, initialArg, init) {
+ currentHookNameInDev = "useReducer";
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
+ try {
+ return updateReducer(reducer, initialArg, init);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useRef: function(initialValue) {
+ currentHookNameInDev = "useRef";
+ return updateRef(initialValue);
+ },
+ useState: function(initialState) {
+ currentHookNameInDev = "useState";
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
+ try {
+ return updateState(initialState);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useDebugValue: function(value, formatterFn) {
+ currentHookNameInDev = "useDebugValue";
+ return updateDebugValue(value, formatterFn);
+ }
+ };
+
+ InvalidNestedHooksDispatcherOnMountInDEV = {
+ readContext: function(context, observedBits) {
+ warnInvalidContextAccess();
+ return readContext(context, observedBits);
+ },
+ useCallback: function(callback, deps) {
+ currentHookNameInDev = "useCallback";
+ warnInvalidHookAccess();
+ return mountCallback(callback, deps);
+ },
+ useContext: function(context, observedBits) {
+ currentHookNameInDev = "useContext";
+ warnInvalidHookAccess();
+ return mountContext(context, observedBits);
+ },
+ useEffect: function(create, deps) {
+ currentHookNameInDev = "useEffect";
+ warnInvalidHookAccess();
+ return mountEffect(create, deps);
+ },
+ useImperativeHandle: function(ref, create, deps) {
+ currentHookNameInDev = "useImperativeHandle";
+ warnInvalidHookAccess();
+ return mountImperativeHandle(ref, create, deps);
+ },
+ useLayoutEffect: function(create, deps) {
+ currentHookNameInDev = "useLayoutEffect";
+ warnInvalidHookAccess();
+ return mountLayoutEffect(create, deps);
+ },
+ useMemo: function(create, deps) {
+ currentHookNameInDev = "useMemo";
+ warnInvalidHookAccess();
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;
+ try {
+ return mountMemo(create, deps);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useReducer: function(reducer, initialArg, init) {
+ currentHookNameInDev = "useReducer";
+ warnInvalidHookAccess();
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;
+ try {
+ return mountReducer(reducer, initialArg, init);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useRef: function(initialValue) {
+ currentHookNameInDev = "useRef";
+ warnInvalidHookAccess();
+ return mountRef(initialValue);
+ },
+ useState: function(initialState) {
+ currentHookNameInDev = "useState";
+ warnInvalidHookAccess();
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;
+ try {
+ return mountState(initialState);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useDebugValue: function(value, formatterFn) {
+ currentHookNameInDev = "useDebugValue";
+ warnInvalidHookAccess();
+ return mountDebugValue(value, formatterFn);
+ }
+ };
+
+ InvalidNestedHooksDispatcherOnUpdateInDEV = {
+ readContext: function(context, observedBits) {
+ warnInvalidContextAccess();
+ return readContext(context, observedBits);
+ },
+ useCallback: function(callback, deps) {
+ currentHookNameInDev = "useCallback";
+ warnInvalidHookAccess();
+ return updateCallback(callback, deps);
+ },
+ useContext: function(context, observedBits) {
+ currentHookNameInDev = "useContext";
+ warnInvalidHookAccess();
+ return updateContext(context, observedBits);
+ },
+ useEffect: function(create, deps) {
+ currentHookNameInDev = "useEffect";
+ warnInvalidHookAccess();
+ return updateEffect(create, deps);
+ },
+ useImperativeHandle: function(ref, create, deps) {
+ currentHookNameInDev = "useImperativeHandle";
+ warnInvalidHookAccess();
+ return updateImperativeHandle(ref, create, deps);
+ },
+ useLayoutEffect: function(create, deps) {
+ currentHookNameInDev = "useLayoutEffect";
+ warnInvalidHookAccess();
+ return updateLayoutEffect(create, deps);
+ },
+ useMemo: function(create, deps) {
+ currentHookNameInDev = "useMemo";
+ warnInvalidHookAccess();
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
+ try {
+ return updateMemo(create, deps);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useReducer: function(reducer, initialArg, init) {
+ currentHookNameInDev = "useReducer";
+ warnInvalidHookAccess();
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
+ try {
+ return updateReducer(reducer, initialArg, init);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useRef: function(initialValue) {
+ currentHookNameInDev = "useRef";
+ warnInvalidHookAccess();
+ return updateRef(initialValue);
+ },
+ useState: function(initialState) {
+ currentHookNameInDev = "useState";
+ warnInvalidHookAccess();
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
+ try {
+ return updateState(initialState);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useDebugValue: function(value, formatterFn) {
+ currentHookNameInDev = "useDebugValue";
+ warnInvalidHookAccess();
+ return updateDebugValue(value, formatterFn);
+ }
+ };
+}
+
+var commitTime = 0;
+var profilerStartTime = -1;
+
+function getCommitTime() {
+ return commitTime;
+}
+
+function recordCommitTime() {
+ if (!enableProfilerTimer) {
+ return;
+ }
+ commitTime = now$$1();
+}
+
+function startProfilerTimer(fiber) {
+ if (!enableProfilerTimer) {
+ return;
+ }
+
+ profilerStartTime = now$$1();
+
+ if (fiber.actualStartTime < 0) {
+ fiber.actualStartTime = now$$1();
+ }
+}
+
+function stopProfilerTimerIfRunning(fiber) {
+ if (!enableProfilerTimer) {
+ return;
+ }
+ profilerStartTime = -1;
+}
+
+function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) {
+ if (!enableProfilerTimer) {
+ return;
+ }
+
+ if (profilerStartTime >= 0) {
+ var elapsedTime = now$$1() - profilerStartTime;
+ fiber.actualDuration += elapsedTime;
+ if (overrideBaseTime) {
+ fiber.selfBaseDuration = elapsedTime;
+ }
+ profilerStartTime = -1;
+ }
+}
+
// The deepest Fiber on the stack involved in a hydration context.
// This may have been an insertion or a hydration.
var hydrationParentFiber = null;
@@ -10475,6 +10317,18 @@
return true;
}
+function reenterHydrationStateFromDehydratedSuspenseInstance(fiber) {
+ if (!supportsHydration) {
+ return false;
+ }
+
+ var suspenseInstance = fiber.stateNode;
+ nextHydratableInstance = getNextHydratableSibling(suspenseInstance);
+ popToNextHostParent(fiber);
+ isHydrating = true;
+ return true;
+}
+
function deleteHydratableInstance(returnFiber, instance) {
{
switch (returnFiber.tag) {
@@ -10529,6 +10383,9 @@
var text = fiber.pendingProps;
didNotFindHydratableContainerTextInstance(parentContainer, text);
break;
+ case SuspenseComponent:
+ didNotFindHydratableContainerSuspenseInstance(parentContainer);
+ break;
}
break;
}
@@ -10557,6 +10414,13 @@
_text
);
break;
+ case SuspenseComponent:
+ didNotFindHydratableSuspenseInstance(
+ parentType,
+ parentProps,
+ parentInstance
+ );
+ break;
}
break;
}
@@ -10587,6 +10451,18 @@
}
return false;
}
+ case SuspenseComponent: {
+ if (enableSuspenseServerRenderer) {
+ var suspenseInstance = canHydrateSuspenseInstance(nextInstance);
+ if (suspenseInstance !== null) {
+ // Downgrade the tag to a dehydrated component until we've hydrated it.
+ fiber.tag = DehydratedSuspenseComponent;
+ fiber.stateNode = suspenseInstance;
+ return true;
+ }
+ }
+ return false;
+ }
default:
return false;
}
@@ -10707,12 +10583,32 @@
return shouldUpdate;
}
+function skipPastDehydratedSuspenseInstance(fiber) {
+ if (!supportsHydration) {
+ invariant(
+ false,
+ "Expected skipPastDehydratedSuspenseInstance() to never be called. " +
+ "This error is likely caused by a bug in React. Please file an issue."
+ );
+ }
+ var suspenseInstance = fiber.stateNode;
+ invariant(
+ suspenseInstance,
+ "Expected to have a hydrated suspense instance. " +
+ "This error is likely caused by a bug in React. Please file an issue."
+ );
+ nextHydratableInstance = getNextHydratableInstanceAfterSuspenseInstance(
+ suspenseInstance
+ );
+}
+
function popToNextHostParent(fiber) {
var parent = fiber.return;
while (
parent !== null &&
parent.tag !== HostComponent &&
- parent.tag !== HostRoot
+ parent.tag !== HostRoot &&
+ parent.tag !== DehydratedSuspenseComponent
) {
parent = parent.return;
}
@@ -10776,6 +10672,8 @@
var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner;
+var didReceiveUpdate = false;
+
var didWarnAboutBadClass = void 0;
var didWarnAboutContextTypeOnFunctionComponent = void 0;
var didWarnAboutGetDerivedStateOnFunctionComponent = void 0;
@@ -10862,6 +10760,10 @@
nextProps,
renderExpirationTime
) {
+ // TODO: current can be non-null here even if the component
+ // hasn't yet mounted. This happens after the first render suspends.
+ // We'll need to figure out if this is fine or can cause issues.
+
{
if (workInProgress.type !== workInProgress.elementType) {
// Lazy component props can't be validated in createElement
@@ -10885,14 +10787,45 @@
// The rest is a fork of updateFunctionComponent
var nextChildren = void 0;
prepareToReadContext(workInProgress, renderExpirationTime);
- prepareToUseHooks(current$$1, workInProgress, renderExpirationTime);
{
ReactCurrentOwner$3.current = workInProgress;
setCurrentPhase("render");
- nextChildren = render(nextProps, ref);
+ nextChildren = renderWithHooks(
+ current$$1,
+ workInProgress,
+ render,
+ nextProps,
+ ref,
+ renderExpirationTime
+ );
+ if (
+ debugRenderPhaseSideEffects ||
+ (debugRenderPhaseSideEffectsForStrictMode &&
+ workInProgress.mode & StrictMode)
+ ) {
+ // Only double-render components with Hooks
+ if (workInProgress.memoizedState !== null) {
+ nextChildren = renderWithHooks(
+ current$$1,
+ workInProgress,
+ render,
+ nextProps,
+ ref,
+ renderExpirationTime
+ );
+ }
+ }
setCurrentPhase(null);
}
- nextChildren = finishHooks(render, nextProps, nextChildren, ref);
+
+ if (current$$1 !== null && !didReceiveUpdate) {
+ bailoutHooks(current$$1, workInProgress, renderExpirationTime);
+ return bailoutOnAlreadyFinishedWork(
+ current$$1,
+ workInProgress,
+ renderExpirationTime
+ );
+ }
// React DevTools reads this flag.
workInProgress.effectTag |= PerformedWork;
@@ -11020,6 +10953,10 @@
updateExpirationTime,
renderExpirationTime
) {
+ // TODO: current can be non-null here even if the component
+ // hasn't yet mounted. This happens when the inner render suspends.
+ // We'll need to figure out if this is fine or can cause issues.
+
{
if (workInProgress.type !== workInProgress.elementType) {
// Lazy component props can't be validated in createElement
@@ -11044,12 +10981,14 @@
// Inner propTypes will be validated in the function component path.
}
}
- if (current$$1 !== null && updateExpirationTime < renderExpirationTime) {
+ if (current$$1 !== null) {
var prevProps = current$$1.memoizedProps;
if (
shallowEqual(prevProps, nextProps) &&
current$$1.ref === workInProgress.ref
) {
+ didReceiveUpdate = false;
+ if (updateExpirationTime < renderExpirationTime) {
return bailoutOnAlreadyFinishedWork(
current$$1,
workInProgress,
@@ -11057,6 +10996,7 @@
);
}
}
+ }
return updateFunctionComponent(
current$$1,
workInProgress,
@@ -11143,14 +11083,45 @@
var nextChildren = void 0;
prepareToReadContext(workInProgress, renderExpirationTime);
- prepareToUseHooks(current$$1, workInProgress, renderExpirationTime);
{
ReactCurrentOwner$3.current = workInProgress;
setCurrentPhase("render");
- nextChildren = Component(nextProps, context);
+ nextChildren = renderWithHooks(
+ current$$1,
+ workInProgress,
+ Component,
+ nextProps,
+ context,
+ renderExpirationTime
+ );
+ if (
+ debugRenderPhaseSideEffects ||
+ (debugRenderPhaseSideEffectsForStrictMode &&
+ workInProgress.mode & StrictMode)
+ ) {
+ // Only double-render components with Hooks
+ if (workInProgress.memoizedState !== null) {
+ nextChildren = renderWithHooks(
+ current$$1,
+ workInProgress,
+ Component,
+ nextProps,
+ context,
+ renderExpirationTime
+ );
+ }
+ }
setCurrentPhase(null);
}
- nextChildren = finishHooks(Component, nextProps, nextChildren, context);
+
+ if (current$$1 !== null && !didReceiveUpdate) {
+ bailoutHooks(current$$1, workInProgress, renderExpirationTime);
+ return bailoutOnAlreadyFinishedWork(
+ current$$1,
+ workInProgress,
+ renderExpirationTime
+ );
+ }
// React DevTools reads this flag.
workInProgress.effectTag |= PerformedWork;
@@ -11485,7 +11456,7 @@
shouldDeprioritizeSubtree(type, nextProps)
) {
// Schedule this fiber to re-render at offscreen priority. Then bailout.
- workInProgress.expirationTime = Never;
+ workInProgress.expirationTime = workInProgress.childExpirationTime = Never;
return null;
}
@@ -11538,6 +11509,9 @@
var child = void 0;
switch (resolvedTag) {
case FunctionComponent: {
+ {
+ validateFunctionComponentInDev(workInProgress, Component);
+ }
child = updateFunctionComponent(
null,
workInProgress,
@@ -11698,7 +11672,6 @@
var context = getMaskedContext(workInProgress, unmaskedContext);
prepareToReadContext(workInProgress, renderExpirationTime);
- prepareToUseHooks(null, workInProgress, renderExpirationTime);
var value = void 0;
@@ -11726,7 +11699,14 @@
}
ReactCurrentOwner$3.current = workInProgress;
- value = Component(props, context);
+ value = renderWithHooks(
+ null,
+ workInProgress,
+ Component,
+ props,
+ context,
+ renderExpirationTime
+ );
}
// React DevTools reads this flag.
workInProgress.effectTag |= PerformedWork;
@@ -11780,7 +11760,25 @@
} else {
// Proceed under the assumption that this is a function component
workInProgress.tag = FunctionComponent;
- value = finishHooks(Component, props, value, context);
+ {
+ if (
+ debugRenderPhaseSideEffects ||
+ (debugRenderPhaseSideEffectsForStrictMode &&
+ workInProgress.mode & StrictMode)
+ ) {
+ // Only double-render components with Hooks
+ if (workInProgress.memoizedState !== null) {
+ value = renderWithHooks(
+ null,
+ workInProgress,
+ Component,
+ props,
+ context,
+ renderExpirationTime
+ );
+ }
+ }
+ }
reconcileChildren(null, workInProgress, value, renderExpirationTime);
{
validateFunctionComponentInDev(workInProgress, Component);
@@ -11816,7 +11814,8 @@
warning$1(
false,
"Function components cannot be given refs. " +
- "Attempts to access this ref will fail.%s",
+ "Attempts to access this ref will fail. " +
+ "Did you mean to use React.forwardRef()?%s",
info
);
}
@@ -11911,6 +11910,22 @@
// children -- we skip over the primary children entirely.
var next = void 0;
if (current$$1 === null) {
+ if (enableSuspenseServerRenderer) {
+ // If we're currently hydrating, try to hydrate this boundary.
+ // But only if this has a fallback.
+ if (nextProps.fallback !== undefined) {
+ tryToClaimNextHydratableInstance(workInProgress);
+ // This could've changed the tag if this was a dehydrated suspense component.
+ if (workInProgress.tag === DehydratedSuspenseComponent) {
+ return updateDehydratedSuspenseComponent(
+ null,
+ workInProgress,
+ renderExpirationTime
+ );
+ }
+ }
+ }
+
// This is the initial mount. This branch is pretty simple because there's
// no previous state that needs to be preserved.
if (nextDidTimeout) {
@@ -12105,6 +12120,7 @@
);
}
}
+ workInProgress.stateNode = current$$1.stateNode;
}
workInProgress.memoizedState = nextState;
@@ -12112,6 +12128,107 @@
return next;
}
+function updateDehydratedSuspenseComponent(
+ current$$1,
+ workInProgress,
+ renderExpirationTime
+) {
+ if (current$$1 === null) {
+ // During the first pass, we'll bail out and not drill into the children.
+ // Instead, we'll leave the content in place and try to hydrate it later.
+ workInProgress.expirationTime = Never;
+ return null;
+ }
+ if ((workInProgress.effectTag & DidCapture) !== NoEffect) {
+ // Something suspended. Leave the existing children in place.
+ // TODO: In non-concurrent mode, should we commit the nodes we have hydrated so far?
+ workInProgress.child = null;
+ return null;
+ }
+ // We use childExpirationTime to indicate that a child might depend on context, so if
+ // any context has changed, we need to treat is as if the input might have changed.
+ var hasContextChanged$$1 =
+ current$$1.childExpirationTime >= renderExpirationTime;
+ var suspenseInstance = current$$1.stateNode;
+ if (
+ didReceiveUpdate ||
+ hasContextChanged$$1 ||
+ isSuspenseInstanceFallback(suspenseInstance)
+ ) {
+ // This boundary has changed since the first render. This means that we are now unable to
+ // hydrate it. We might still be able to hydrate it using an earlier expiration time but
+ // during this render we can't. Instead, we're going to delete the whole subtree and
+ // instead inject a new real Suspense boundary to take its place, which may render content
+ // or fallback. The real Suspense boundary will suspend for a while so we have some time
+ // to ensure it can produce real content, but all state and pending events will be lost.
+
+ // Alternatively, this boundary is in a permanent fallback state. In this case, we'll never
+ // get an update and we'll never be able to hydrate the final content. Let's just try the
+ // client side render instead.
+
+ // Detach from the current dehydrated boundary.
+ current$$1.alternate = null;
+ workInProgress.alternate = null;
+
+ // Insert a deletion in the effect list.
+ var returnFiber = workInProgress.return;
+ invariant(
+ returnFiber !== null,
+ "Suspense boundaries are never on the root. " +
+ "This is probably a bug in React."
+ );
+ var last = returnFiber.lastEffect;
+ if (last !== null) {
+ last.nextEffect = current$$1;
+ returnFiber.lastEffect = current$$1;
+ } else {
+ returnFiber.firstEffect = returnFiber.lastEffect = current$$1;
+ }
+ current$$1.nextEffect = null;
+ current$$1.effectTag = Deletion;
+
+ // Upgrade this work in progress to a real Suspense component.
+ workInProgress.tag = SuspenseComponent;
+ workInProgress.stateNode = null;
+ workInProgress.memoizedState = null;
+ // This is now an insertion.
+ workInProgress.effectTag |= Placement;
+ // Retry as a real Suspense component.
+ return updateSuspenseComponent(null, workInProgress, renderExpirationTime);
+ } else if (isSuspenseInstancePending(suspenseInstance)) {
+ // This component is still pending more data from the server, so we can't hydrate its
+ // content. We treat it as if this component suspended itself. It might seem as if
+ // we could just try to render it client-side instead. However, this will perform a
+ // lot of unnecessary work and is unlikely to complete since it often will suspend
+ // on missing data anyway. Additionally, the server might be able to render more
+ // than we can on the client yet. In that case we'd end up with more fallback states
+ // on the client than if we just leave it alone. If the server times out or errors
+ // these should update this boundary to the permanent Fallback state instead.
+ // Mark it as having captured (i.e. suspended).
+ workInProgress.effectTag |= DidCapture;
+ // Leave the children in place. I.e. empty.
+ workInProgress.child = null;
+ // Register a callback to retry this boundary once the server has sent the result.
+ registerSuspenseInstanceRetry(
+ suspenseInstance,
+ retryTimedOutBoundary.bind(null, current$$1)
+ );
+ return null;
+ } else {
+ // This is the first attempt.
+ reenterHydrationStateFromDehydratedSuspenseInstance(workInProgress);
+ var nextProps = workInProgress.pendingProps;
+ var nextChildren = nextProps.children;
+ workInProgress.child = mountChildFibers(
+ workInProgress,
+ null,
+ nextChildren,
+ renderExpirationTime
+ );
+ return workInProgress.child;
+ }
+}
+
function updatePortalComponent(
current$$1,
workInProgress,
@@ -12275,6 +12392,10 @@
return workInProgress.child;
}
+function markWorkInProgressReceivedUpdate() {
+ didReceiveUpdate = true;
+}
+
function bailoutOnAlreadyFinishedWork(
current$$1,
workInProgress,
@@ -12284,7 +12405,7 @@
if (current$$1 !== null) {
// Reuse previous context list
- workInProgress.firstContextDependency = current$$1.firstContextDependency;
+ workInProgress.contextDependencies = current$$1.contextDependencies;
}
if (enableProfilerTimer) {
@@ -12313,11 +12434,13 @@
if (current$$1 !== null) {
var oldProps = current$$1.memoizedProps;
var newProps = workInProgress.pendingProps;
- if (
- oldProps === newProps &&
- !hasContextChanged() &&
- updateExpirationTime < renderExpirationTime
- ) {
+
+ if (oldProps !== newProps || hasContextChanged()) {
+ // If props or context changed, mark the fiber as having performed work.
+ // This may be unset if the props are determined to be equal later (memo).
+ didReceiveUpdate = true;
+ } else if (updateExpirationTime < renderExpirationTime) {
+ didReceiveUpdate = false;
// This fiber does not have any pending work. Bailout without entering
// the begin phase. There's still some bookkeeping we that needs to be done
// in this optimized path, mostly pushing stuff onto the stack.
@@ -12392,6 +12515,15 @@
}
break;
}
+ case DehydratedSuspenseComponent: {
+ if (enableSuspenseServerRenderer) {
+ // We know that this component will suspend again because if it has
+ // been unsuspended it has committed as a regular Suspense component.
+ // If it needs to be retried, it should have work scheduled on it.
+ workInProgress.effectTag |= DidCapture;
+ break;
+ }
+ }
}
return bailoutOnAlreadyFinishedWork(
current$$1,
@@ -12399,6 +12531,8 @@
renderExpirationTime
);
}
+ } else {
+ didReceiveUpdate = false;
}
// Before entering the begin phase, clear the expiration time.
@@ -12563,13 +12697,930 @@
renderExpirationTime
);
}
- default:
+ case DehydratedSuspenseComponent: {
+ if (enableSuspenseServerRenderer) {
+ return updateDehydratedSuspenseComponent(
+ current$$1,
+ workInProgress,
+ renderExpirationTime
+ );
+ }
+ break;
+ }
+ }
invariant(
false,
"Unknown unit of work tag. This error is likely caused by a bug in " +
"React. Please file an issue."
);
+}
+
+var valueCursor = createCursor(null);
+
+var rendererSigil = void 0;
+{
+ // Use this to detect multiple renderers using the same context
+ rendererSigil = {};
+}
+
+var currentlyRenderingFiber = null;
+var lastContextDependency = null;
+var lastContextWithAllBitsObserved = null;
+
+var isDisallowedContextReadInDEV = false;
+
+function resetContextDependences() {
+ // This is called right before React yields execution, to ensure `readContext`
+ // cannot be called outside the render phase.
+ currentlyRenderingFiber = null;
+ lastContextDependency = null;
+ lastContextWithAllBitsObserved = null;
+ {
+ isDisallowedContextReadInDEV = false;
+ }
+}
+
+function enterDisallowedContextReadInDEV() {
+ {
+ isDisallowedContextReadInDEV = true;
+ }
+}
+
+function exitDisallowedContextReadInDEV() {
+ {
+ isDisallowedContextReadInDEV = false;
+ }
+}
+
+function pushProvider(providerFiber, nextValue) {
+ var context = providerFiber.type._context;
+
+ if (isPrimaryRenderer) {
+ push(valueCursor, context._currentValue, providerFiber);
+
+ context._currentValue = nextValue;
+ {
+ !(
+ context._currentRenderer === undefined ||
+ context._currentRenderer === null ||
+ context._currentRenderer === rendererSigil
+ )
+ ? warningWithoutStack$1(
+ false,
+ "Detected multiple renderers concurrently rendering the " +
+ "same context provider. This is currently unsupported."
+ )
+ : void 0;
+ context._currentRenderer = rendererSigil;
+ }
+ } else {
+ push(valueCursor, context._currentValue2, providerFiber);
+
+ context._currentValue2 = nextValue;
+ {
+ !(
+ context._currentRenderer2 === undefined ||
+ context._currentRenderer2 === null ||
+ context._currentRenderer2 === rendererSigil
+ )
+ ? warningWithoutStack$1(
+ false,
+ "Detected multiple renderers concurrently rendering the " +
+ "same context provider. This is currently unsupported."
+ )
+ : void 0;
+ context._currentRenderer2 = rendererSigil;
+ }
+ }
+}
+
+function popProvider(providerFiber) {
+ var currentValue = valueCursor.current;
+
+ pop(valueCursor, providerFiber);
+
+ var context = providerFiber.type._context;
+ if (isPrimaryRenderer) {
+ context._currentValue = currentValue;
+ } else {
+ context._currentValue2 = currentValue;
+ }
+}
+
+function calculateChangedBits(context, newValue, oldValue) {
+ if (is(oldValue, newValue)) {
+ // No change
+ return 0;
+ } else {
+ var changedBits =
+ typeof context._calculateChangedBits === "function"
+ ? context._calculateChangedBits(oldValue, newValue)
+ : maxSigned31BitInt;
+
+ {
+ !((changedBits & maxSigned31BitInt) === changedBits)
+ ? warning$1(
+ false,
+ "calculateChangedBits: Expected the return value to be a " +
+ "31-bit integer. Instead received: %s",
+ changedBits
+ )
+ : void 0;
+ }
+ return changedBits | 0;
+ }
+}
+
+function scheduleWorkOnParentPath(parent, renderExpirationTime) {
+ // Update the child expiration time of all the ancestors, including
+ // the alternates.
+ var node = parent;
+ while (node !== null) {
+ var alternate = node.alternate;
+ if (node.childExpirationTime < renderExpirationTime) {
+ node.childExpirationTime = renderExpirationTime;
+ if (
+ alternate !== null &&
+ alternate.childExpirationTime < renderExpirationTime
+ ) {
+ alternate.childExpirationTime = renderExpirationTime;
+ }
+ } else if (
+ alternate !== null &&
+ alternate.childExpirationTime < renderExpirationTime
+ ) {
+ alternate.childExpirationTime = renderExpirationTime;
+ } else {
+ // Neither alternate was updated, which means the rest of the
+ // ancestor path already has sufficient priority.
+ break;
+ }
+ node = node.return;
+ }
+}
+
+function propagateContextChange(
+ workInProgress,
+ context,
+ changedBits,
+ renderExpirationTime
+) {
+ var fiber = workInProgress.child;
+ if (fiber !== null) {
+ // Set the return pointer of the child to the work-in-progress fiber.
+ fiber.return = workInProgress;
+ }
+ while (fiber !== null) {
+ var nextFiber = void 0;
+
+ // Visit this fiber.
+ var list = fiber.contextDependencies;
+ if (list !== null) {
+ nextFiber = fiber.child;
+
+ var dependency = list.first;
+ while (dependency !== null) {
+ // Check if the context matches.
+ if (
+ dependency.context === context &&
+ (dependency.observedBits & changedBits) !== 0
+ ) {
+ // Match! Schedule an update on this fiber.
+
+ if (fiber.tag === ClassComponent) {
+ // Schedule a force update on the work-in-progress.
+ var update = createUpdate(renderExpirationTime);
+ update.tag = ForceUpdate;
+ // TODO: Because we don't have a work-in-progress, this will add the
+ // update to the current fiber, too, which means it will persist even if
+ // this render is thrown away. Since it's a race condition, not sure it's
+ // worth fixing.
+ enqueueUpdate(fiber, update);
+ }
+
+ if (fiber.expirationTime < renderExpirationTime) {
+ fiber.expirationTime = renderExpirationTime;
+ }
+ var alternate = fiber.alternate;
+ if (
+ alternate !== null &&
+ alternate.expirationTime < renderExpirationTime
+ ) {
+ alternate.expirationTime = renderExpirationTime;
+ }
+
+ scheduleWorkOnParentPath(fiber.return, renderExpirationTime);
+
+ // Mark the expiration time on the list, too.
+ if (list.expirationTime < renderExpirationTime) {
+ list.expirationTime = renderExpirationTime;
+ }
+
+ // Since we already found a match, we can stop traversing the
+ // dependency list.
+ break;
+ }
+ dependency = dependency.next;
+ }
+ } else if (fiber.tag === ContextProvider) {
+ // Don't scan deeper if this is a matching provider
+ nextFiber = fiber.type === workInProgress.type ? null : fiber.child;
+ } else if (
+ enableSuspenseServerRenderer &&
+ fiber.tag === DehydratedSuspenseComponent
+ ) {
+ // If a dehydrated suspense component is in this subtree, we don't know
+ // if it will have any context consumers in it. The best we can do is
+ // mark it as having updates on its children.
+ if (fiber.expirationTime < renderExpirationTime) {
+ fiber.expirationTime = renderExpirationTime;
+ }
+ var _alternate = fiber.alternate;
+ if (
+ _alternate !== null &&
+ _alternate.expirationTime < renderExpirationTime
+ ) {
+ _alternate.expirationTime = renderExpirationTime;
+ }
+ // This is intentionally passing this fiber as the parent
+ // because we want to schedule this fiber as having work
+ // on its children. We'll use the childExpirationTime on
+ // this fiber to indicate that a context has changed.
+ scheduleWorkOnParentPath(fiber, renderExpirationTime);
+ nextFiber = fiber.sibling;
+ } else {
+ // Traverse down.
+ nextFiber = fiber.child;
+ }
+
+ if (nextFiber !== null) {
+ // Set the return pointer of the child to the work-in-progress fiber.
+ nextFiber.return = fiber;
+ } else {
+ // No child. Traverse to next sibling.
+ nextFiber = fiber;
+ while (nextFiber !== null) {
+ if (nextFiber === workInProgress) {
+ // We're back to the root of this subtree. Exit.
+ nextFiber = null;
+ break;
+ }
+ var sibling = nextFiber.sibling;
+ if (sibling !== null) {
+ // Set the return pointer of the sibling to the work-in-progress fiber.
+ sibling.return = nextFiber.return;
+ nextFiber = sibling;
+ break;
+ }
+ // No more siblings. Traverse up.
+ nextFiber = nextFiber.return;
+ }
+ }
+ fiber = nextFiber;
+ }
+}
+
+function prepareToReadContext(workInProgress, renderExpirationTime) {
+ currentlyRenderingFiber = workInProgress;
+ lastContextDependency = null;
+ lastContextWithAllBitsObserved = null;
+
+ var currentDependencies = workInProgress.contextDependencies;
+ if (
+ currentDependencies !== null &&
+ currentDependencies.expirationTime >= renderExpirationTime
+ ) {
+ // Context list has a pending update. Mark that this fiber performed work.
+ markWorkInProgressReceivedUpdate();
+ }
+
+ // Reset the work-in-progress list
+ workInProgress.contextDependencies = null;
+}
+
+function readContext(context, observedBits) {
+ {
+ // This warning would fire if you read context inside a Hook like useMemo.
+ // Unlike the class check below, it's not enforced in production for perf.
+ !!isDisallowedContextReadInDEV
+ ? warning$1(
+ false,
+ "Context can only be read while React is rendering. " +
+ "In classes, you can read it in the render method or getDerivedStateFromProps. " +
+ "In function components, you can read it directly in the function body, but not " +
+ "inside Hooks like useReducer() or useMemo()."
+ )
+ : void 0;
+ }
+
+ if (lastContextWithAllBitsObserved === context) {
+ // Nothing to do. We already observe everything in this context.
+ } else if (observedBits === false || observedBits === 0) {
+ // Do not observe any updates.
+ } else {
+ var resolvedObservedBits = void 0; // Avoid deopting on observable arguments or heterogeneous types.
+ if (
+ typeof observedBits !== "number" ||
+ observedBits === maxSigned31BitInt
+ ) {
+ // Observe all updates.
+ lastContextWithAllBitsObserved = context;
+ resolvedObservedBits = maxSigned31BitInt;
+ } else {
+ resolvedObservedBits = observedBits;
+ }
+
+ var contextItem = {
+ context: context,
+ observedBits: resolvedObservedBits,
+ next: null
+ };
+
+ if (lastContextDependency === null) {
+ invariant(
+ currentlyRenderingFiber !== null,
+ "Context can only be read while React is rendering. " +
+ "In classes, you can read it in the render method or getDerivedStateFromProps. " +
+ "In function components, you can read it directly in the function body, but not " +
+ "inside Hooks like useReducer() or useMemo()."
+ );
+
+ // This is the first dependency for this component. Create a new list.
+ lastContextDependency = contextItem;
+ currentlyRenderingFiber.contextDependencies = {
+ first: contextItem,
+ expirationTime: NoWork
+ };
+ } else {
+ // Append a new context item.
+ lastContextDependency = lastContextDependency.next = contextItem;
+ }
+ }
+ return isPrimaryRenderer ? context._currentValue : context._currentValue2;
+}
+
+// UpdateQueue is a linked list of prioritized updates.
+//
+// Like fibers, update queues come in pairs: a current queue, which represents
+// the visible state of the screen, and a work-in-progress queue, which can be
+// mutated and processed asynchronously before it is committed — a form of
+// double buffering. If a work-in-progress render is discarded before finishing,
+// we create a new work-in-progress by cloning the current queue.
+//
+// Both queues share a persistent, singly-linked list structure. To schedule an
+// update, we append it to the end of both queues. Each queue maintains a
+// pointer to first update in the persistent list that hasn't been processed.
+// The work-in-progress pointer always has a position equal to or greater than
+// the current queue, since we always work on that one. The current queue's
+// pointer is only updated during the commit phase, when we swap in the
+// work-in-progress.
+//
+// For example:
+//
+// Current pointer: A - B - C - D - E - F
+// Work-in-progress pointer: D - E - F
+// ^
+// The work-in-progress queue has
+// processed more updates than current.
+//
+// The reason we append to both queues is because otherwise we might drop
+// updates without ever processing them. For example, if we only add updates to
+// the work-in-progress queue, some updates could be lost whenever a work-in
+// -progress render restarts by cloning from current. Similarly, if we only add
+// updates to the current queue, the updates will be lost whenever an already
+// in-progress queue commits and swaps with the current queue. However, by
+// adding to both queues, we guarantee that the update will be part of the next
+// work-in-progress. (And because the work-in-progress queue becomes the
+// current queue once it commits, there's no danger of applying the same
+// update twice.)
+//
+// Prioritization
+// --------------
+//
+// Updates are not sorted by priority, but by insertion; new updates are always
+// appended to the end of the list.
+//
+// The priority is still important, though. When processing the update queue
+// during the render phase, only the updates with sufficient priority are
+// included in the result. If we skip an update because it has insufficient
+// priority, it remains in the queue to be processed later, during a lower
+// priority render. Crucially, all updates subsequent to a skipped update also
+// remain in the queue *regardless of their priority*. That means high priority
+// updates are sometimes processed twice, at two separate priorities. We also
+// keep track of a base state, that represents the state before the first
+// update in the queue is applied.
+//
+// For example:
+//
+// Given a base state of '', and the following queue of updates
+//
+// A1 - B2 - C1 - D2
+//
+// where the number indicates the priority, and the update is applied to the
+// previous state by appending a letter, React will process these updates as
+// two separate renders, one per distinct priority level:
+//
+// First render, at priority 1:
+// Base state: ''
+// Updates: [A1, C1]
+// Result state: 'AC'
+//
+// Second render, at priority 2:
+// Base state: 'A' <- The base state does not include C1,
+// because B2 was skipped.
+// Updates: [B2, C1, D2] <- C1 was rebased on top of B2
+// Result state: 'ABCD'
+//
+// Because we process updates in insertion order, and rebase high priority
+// updates when preceding updates are skipped, the final result is deterministic
+// regardless of priority. Intermediate state may vary according to system
+// resources, but the final state is always the same.
+
+var UpdateState = 0;
+var ReplaceState = 1;
+var ForceUpdate = 2;
+var CaptureUpdate = 3;
+
+// Global state that is reset at the beginning of calling `processUpdateQueue`.
+// It should only be read right after calling `processUpdateQueue`, via
+// `checkHasForceUpdateAfterProcessing`.
+var hasForceUpdate = false;
+
+var didWarnUpdateInsideUpdate = void 0;
+var currentlyProcessingQueue = void 0;
+var resetCurrentlyProcessingQueue = void 0;
+{
+ didWarnUpdateInsideUpdate = false;
+ currentlyProcessingQueue = null;
+ resetCurrentlyProcessingQueue = function() {
+ currentlyProcessingQueue = null;
+ };
+}
+
+function createUpdateQueue(baseState) {
+ var queue = {
+ baseState: baseState,
+ firstUpdate: null,
+ lastUpdate: null,
+ firstCapturedUpdate: null,
+ lastCapturedUpdate: null,
+ firstEffect: null,
+ lastEffect: null,
+ firstCapturedEffect: null,
+ lastCapturedEffect: null
+ };
+ return queue;
+}
+
+function cloneUpdateQueue(currentQueue) {
+ var queue = {
+ baseState: currentQueue.baseState,
+ firstUpdate: currentQueue.firstUpdate,
+ lastUpdate: currentQueue.lastUpdate,
+
+ // TODO: With resuming, if we bail out and resuse the child tree, we should
+ // keep these effects.
+ firstCapturedUpdate: null,
+ lastCapturedUpdate: null,
+
+ firstEffect: null,
+ lastEffect: null,
+
+ firstCapturedEffect: null,
+ lastCapturedEffect: null
+ };
+ return queue;
+}
+
+function createUpdate(expirationTime) {
+ return {
+ expirationTime: expirationTime,
+
+ tag: UpdateState,
+ payload: null,
+ callback: null,
+
+ next: null,
+ nextEffect: null
+ };
+}
+
+function appendUpdateToQueue(queue, update) {
+ // Append the update to the end of the list.
+ if (queue.lastUpdate === null) {
+ // Queue is empty
+ queue.firstUpdate = queue.lastUpdate = update;
+ } else {
+ queue.lastUpdate.next = update;
+ queue.lastUpdate = update;
+ }
+}
+
+function enqueueUpdate(fiber, update) {
+ // Update queues are created lazily.
+ var alternate = fiber.alternate;
+ var queue1 = void 0;
+ var queue2 = void 0;
+ if (alternate === null) {
+ // There's only one fiber.
+ queue1 = fiber.updateQueue;
+ queue2 = null;
+ if (queue1 === null) {
+ queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState);
+ }
+ } else {
+ // There are two owners.
+ queue1 = fiber.updateQueue;
+ queue2 = alternate.updateQueue;
+ if (queue1 === null) {
+ if (queue2 === null) {
+ // Neither fiber has an update queue. Create new ones.
+ queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState);
+ queue2 = alternate.updateQueue = createUpdateQueue(
+ alternate.memoizedState
+ );
+ } else {
+ // Only one fiber has an update queue. Clone to create a new one.
+ queue1 = fiber.updateQueue = cloneUpdateQueue(queue2);
+ }
+ } else {
+ if (queue2 === null) {
+ // Only one fiber has an update queue. Clone to create a new one.
+ queue2 = alternate.updateQueue = cloneUpdateQueue(queue1);
+ } else {
+ // Both owners have an update queue.
+ }
+ }
+ }
+ if (queue2 === null || queue1 === queue2) {
+ // There's only a single queue.
+ appendUpdateToQueue(queue1, update);
+ } else {
+ // There are two queues. We need to append the update to both queues,
+ // while accounting for the persistent structure of the list — we don't
+ // want the same update to be added multiple times.
+ if (queue1.lastUpdate === null || queue2.lastUpdate === null) {
+ // One of the queues is not empty. We must add the update to both queues.
+ appendUpdateToQueue(queue1, update);
+ appendUpdateToQueue(queue2, update);
+ } else {
+ // Both queues are non-empty. The last update is the same in both lists,
+ // because of structural sharing. So, only append to one of the lists.
+ appendUpdateToQueue(queue1, update);
+ // But we still need to update the `lastUpdate` pointer of queue2.
+ queue2.lastUpdate = update;
+ }
+ }
+
+ {
+ if (
+ fiber.tag === ClassComponent &&
+ (currentlyProcessingQueue === queue1 ||
+ (queue2 !== null && currentlyProcessingQueue === queue2)) &&
+ !didWarnUpdateInsideUpdate
+ ) {
+ warningWithoutStack$1(
+ false,
+ "An update (setState, replaceState, or forceUpdate) was scheduled " +
+ "from inside an update function. Update functions should be pure, " +
+ "with zero side-effects. Consider using componentDidUpdate or a " +
+ "callback."
+ );
+ didWarnUpdateInsideUpdate = true;
+ }
+ }
+}
+
+function enqueueCapturedUpdate(workInProgress, update) {
+ // Captured updates go into a separate list, and only on the work-in-
+ // progress queue.
+ var workInProgressQueue = workInProgress.updateQueue;
+ if (workInProgressQueue === null) {
+ workInProgressQueue = workInProgress.updateQueue = createUpdateQueue(
+ workInProgress.memoizedState
+ );
+ } else {
+ // TODO: I put this here rather than createWorkInProgress so that we don't
+ // clone the queue unnecessarily. There's probably a better way to
+ // structure this.
+ workInProgressQueue = ensureWorkInProgressQueueIsAClone(
+ workInProgress,
+ workInProgressQueue
+ );
+ }
+
+ // Append the update to the end of the list.
+ if (workInProgressQueue.lastCapturedUpdate === null) {
+ // This is the first render phase update
+ workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update;
+ } else {
+ workInProgressQueue.lastCapturedUpdate.next = update;
+ workInProgressQueue.lastCapturedUpdate = update;
+ }
+}
+
+function ensureWorkInProgressQueueIsAClone(workInProgress, queue) {
+ var current = workInProgress.alternate;
+ if (current !== null) {
+ // If the work-in-progress queue is equal to the current queue,
+ // we need to clone it first.
+ if (queue === current.updateQueue) {
+ queue = workInProgress.updateQueue = cloneUpdateQueue(queue);
+ }
+ }
+ return queue;
+}
+
+function getStateFromUpdate(
+ workInProgress,
+ queue,
+ update,
+ prevState,
+ nextProps,
+ instance
+) {
+ switch (update.tag) {
+ case ReplaceState: {
+ var _payload = update.payload;
+ if (typeof _payload === "function") {
+ // Updater function
+ {
+ enterDisallowedContextReadInDEV();
+ if (
+ debugRenderPhaseSideEffects ||
+ (debugRenderPhaseSideEffectsForStrictMode &&
+ workInProgress.mode & StrictMode)
+ ) {
+ _payload.call(instance, prevState, nextProps);
+ }
+ }
+ var nextState = _payload.call(instance, prevState, nextProps);
+ {
+ exitDisallowedContextReadInDEV();
+ }
+ return nextState;
+ }
+ // State object
+ return _payload;
+ }
+ case CaptureUpdate: {
+ workInProgress.effectTag =
+ (workInProgress.effectTag & ~ShouldCapture) | DidCapture;
+ }
+ // Intentional fallthrough
+ case UpdateState: {
+ var _payload2 = update.payload;
+ var partialState = void 0;
+ if (typeof _payload2 === "function") {
+ // Updater function
+ {
+ enterDisallowedContextReadInDEV();
+ if (
+ debugRenderPhaseSideEffects ||
+ (debugRenderPhaseSideEffectsForStrictMode &&
+ workInProgress.mode & StrictMode)
+ ) {
+ _payload2.call(instance, prevState, nextProps);
+ }
+ }
+ partialState = _payload2.call(instance, prevState, nextProps);
+ {
+ exitDisallowedContextReadInDEV();
+ }
+ } else {
+ // Partial state object
+ partialState = _payload2;
+ }
+ if (partialState === null || partialState === undefined) {
+ // Null and undefined are treated as no-ops.
+ return prevState;
+ }
+ // Merge the partial state and the previous state.
+ return Object.assign({}, prevState, partialState);
+ }
+ case ForceUpdate: {
+ hasForceUpdate = true;
+ return prevState;
+ }
+ }
+ return prevState;
+}
+
+function processUpdateQueue(
+ workInProgress,
+ queue,
+ props,
+ instance,
+ renderExpirationTime
+) {
+ hasForceUpdate = false;
+
+ queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue);
+
+ {
+ currentlyProcessingQueue = queue;
+ }
+
+ // These values may change as we process the queue.
+ var newBaseState = queue.baseState;
+ var newFirstUpdate = null;
+ var newExpirationTime = NoWork;
+
+ // Iterate through the list of updates to compute the result.
+ var update = queue.firstUpdate;
+ var resultState = newBaseState;
+ while (update !== null) {
+ var updateExpirationTime = update.expirationTime;
+ if (updateExpirationTime < renderExpirationTime) {
+ // This update does not have sufficient priority. Skip it.
+ if (newFirstUpdate === null) {
+ // This is the first skipped update. It will be the first update in
+ // the new list.
+ newFirstUpdate = update;
+ // Since this is the first update that was skipped, the current result
+ // is the new base state.
+ newBaseState = resultState;
+ }
+ // Since this update will remain in the list, update the remaining
+ // expiration time.
+ if (newExpirationTime < updateExpirationTime) {
+ newExpirationTime = updateExpirationTime;
+ }
+ } else {
+ // This update does have sufficient priority. Process it and compute
+ // a new result.
+ resultState = getStateFromUpdate(
+ workInProgress,
+ queue,
+ update,
+ resultState,
+ props,
+ instance
+ );
+ var _callback = update.callback;
+ if (_callback !== null) {
+ workInProgress.effectTag |= Callback;
+ // Set this to null, in case it was mutated during an aborted render.
+ update.nextEffect = null;
+ if (queue.lastEffect === null) {
+ queue.firstEffect = queue.lastEffect = update;
+ } else {
+ queue.lastEffect.nextEffect = update;
+ queue.lastEffect = update;
+ }
+ }
+ }
+ // Continue to the next update.
+ update = update.next;
+ }
+
+ // Separately, iterate though the list of captured updates.
+ var newFirstCapturedUpdate = null;
+ update = queue.firstCapturedUpdate;
+ while (update !== null) {
+ var _updateExpirationTime = update.expirationTime;
+ if (_updateExpirationTime < renderExpirationTime) {
+ // This update does not have sufficient priority. Skip it.
+ if (newFirstCapturedUpdate === null) {
+ // This is the first skipped captured update. It will be the first
+ // update in the new list.
+ newFirstCapturedUpdate = update;
+ // If this is the first update that was skipped, the current result is
+ // the new base state.
+ if (newFirstUpdate === null) {
+ newBaseState = resultState;
+ }
}
+ // Since this update will remain in the list, update the remaining
+ // expiration time.
+ if (newExpirationTime < _updateExpirationTime) {
+ newExpirationTime = _updateExpirationTime;
+ }
+ } else {
+ // This update does have sufficient priority. Process it and compute
+ // a new result.
+ resultState = getStateFromUpdate(
+ workInProgress,
+ queue,
+ update,
+ resultState,
+ props,
+ instance
+ );
+ var _callback2 = update.callback;
+ if (_callback2 !== null) {
+ workInProgress.effectTag |= Callback;
+ // Set this to null, in case it was mutated during an aborted render.
+ update.nextEffect = null;
+ if (queue.lastCapturedEffect === null) {
+ queue.firstCapturedEffect = queue.lastCapturedEffect = update;
+ } else {
+ queue.lastCapturedEffect.nextEffect = update;
+ queue.lastCapturedEffect = update;
+ }
+ }
+ }
+ update = update.next;
+ }
+
+ if (newFirstUpdate === null) {
+ queue.lastUpdate = null;
+ }
+ if (newFirstCapturedUpdate === null) {
+ queue.lastCapturedUpdate = null;
+ } else {
+ workInProgress.effectTag |= Callback;
+ }
+ if (newFirstUpdate === null && newFirstCapturedUpdate === null) {
+ // We processed every update, without skipping. That means the new base
+ // state is the same as the result state.
+ newBaseState = resultState;
+ }
+
+ queue.baseState = newBaseState;
+ queue.firstUpdate = newFirstUpdate;
+ queue.firstCapturedUpdate = newFirstCapturedUpdate;
+
+ // Set the remaining expiration time to be whatever is remaining in the queue.
+ // This should be fine because the only two other things that contribute to
+ // expiration time are props and context. We're already in the middle of the
+ // begin phase by the time we start processing the queue, so we've already
+ // dealt with the props. Context in components that specify
+ // shouldComponentUpdate is tricky; but we'll have to account for
+ // that regardless.
+ workInProgress.expirationTime = newExpirationTime;
+ workInProgress.memoizedState = resultState;
+
+ {
+ currentlyProcessingQueue = null;
+ }
+}
+
+function callCallback(callback, context) {
+ invariant(
+ typeof callback === "function",
+ "Invalid argument passed as callback. Expected a function. Instead " +
+ "received: %s",
+ callback
+ );
+ callback.call(context);
+}
+
+function resetHasForceUpdateBeforeProcessing() {
+ hasForceUpdate = false;
+}
+
+function checkHasForceUpdateAfterProcessing() {
+ return hasForceUpdate;
+}
+
+function commitUpdateQueue(
+ finishedWork,
+ finishedQueue,
+ instance,
+ renderExpirationTime
+) {
+ // If the finished render included captured updates, and there are still
+ // lower priority updates left over, we need to keep the captured updates
+ // in the queue so that they are rebased and not dropped once we process the
+ // queue again at the lower priority.
+ if (finishedQueue.firstCapturedUpdate !== null) {
+ // Join the captured update list to the end of the normal list.
+ if (finishedQueue.lastUpdate !== null) {
+ finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate;
+ finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate;
+ }
+ // Clear the list of captured updates.
+ finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null;
+ }
+
+ // Commit the effects
+ commitUpdateEffects(finishedQueue.firstEffect, instance);
+ finishedQueue.firstEffect = finishedQueue.lastEffect = null;
+
+ commitUpdateEffects(finishedQueue.firstCapturedEffect, instance);
+ finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null;
+}
+
+function commitUpdateEffects(effect, instance) {
+ while (effect !== null) {
+ var _callback3 = effect.callback;
+ if (_callback3 !== null) {
+ effect.callback = null;
+ callCallback(_callback3, instance);
+ }
+ effect = effect.nextEffect;
+ }
+}
+
+function createCapturedValue(value, source) {
+ // If the value is an error, call this function immediately after it is thrown
+ // so the stack is accurate.
+ return {
+ value: value,
+ source: source,
+ stack: getStackByFiberInDevAndProd(source)
+ };
}
function markUpdate(workInProgress) {
@@ -13173,7 +14224,12 @@
var nextDidTimeout = nextState !== null;
var prevDidTimeout = current !== null && current.memoizedState !== null;
- if (current !== null && !nextDidTimeout && prevDidTimeout) {
+ if (current === null) {
+ // In cases where we didn't find a suitable hydration boundary we never
+ // downgraded this to a DehydratedSuspenseComponent, but we still need to
+ // pop the hydration state since we might be inside the insertion tree.
+ popHydrationState(workInProgress);
+ } else if (!nextDidTimeout && prevDidTimeout) {
// We just switched from the fallback to the normal children. Delete
// the fallback.
// TODO: Would it be better to store the fallback fragment on
@@ -13192,18 +14248,10 @@
}
}
- // The children either timed out after previously being visible, or
- // were restored after previously being hidden. Schedule an effect
- // to update their visiblity.
- if (
- //
- nextDidTimeout !== prevDidTimeout ||
- // Outside concurrent mode, the primary children commit in an
- // inconsistent state, even if they are hidden. So if they are hidden,
- // we need to schedule an effect to re-hide them, just in case.
- ((workInProgress.effectTag & ConcurrentMode) === NoContext &&
- nextDidTimeout)
- ) {
+ if (nextDidTimeout || prevDidTimeout) {
+ // If the children are hidden, or if they were previous hidden, schedule
+ // an effect to toggle their visibility. This is also used to attach a
+ // retry listener to the promise.
workInProgress.effectTag |= Update;
}
break;
@@ -13235,6 +14283,29 @@
}
break;
}
+ case DehydratedSuspenseComponent: {
+ if (enableSuspenseServerRenderer) {
+ if (current === null) {
+ var _wasHydrated2 = popHydrationState(workInProgress);
+ invariant(
+ _wasHydrated2,
+ "A dehydrated suspense component was completed without a hydrated node. " +
+ "This is probably a bug in React."
+ );
+ skipPastDehydratedSuspenseInstance(workInProgress);
+ } else if ((workInProgress.effectTag & DidCapture) === NoEffect) {
+ // This boundary did not suspend so it's now hydrated.
+ // To handle any future suspense cases, we're going to now upgrade it
+ // to a Suspense component. We detach it from the existing current fiber.
+ current.alternate = null;
+ workInProgress.alternate = null;
+ workInProgress.tag = SuspenseComponent;
+ workInProgress.memoizedState = null;
+ workInProgress.stateNode = null;
+ }
+ }
+ break;
+ }
default:
invariant(
false,
@@ -13246,7 +14317,7 @@
return null;
}
-function shouldCaptureSuspense(current, workInProgress) {
+function shouldCaptureSuspense(workInProgress) {
// In order to capture, the Suspense component must have a fallback prop.
if (workInProgress.memoizedProps.fallback === undefined) {
return false;
@@ -13378,6 +14449,8 @@
didWarnAboutUndefinedSnapshotBeforeUpdate = new Set();
}
+var PossiblyWeakSet$1 = typeof WeakSet === "function" ? WeakSet : Set;
+
function logError(boundary, errorInfo) {
var source = errorInfo.source;
var stack = errorInfo.stack;
@@ -13556,9 +14629,6 @@
}
function commitHookEffectList(unmountTag, mountTag, finishedWork) {
- if (!enableHooks) {
- return;
- }
var updateQueue = finishedWork.updateQueue;
var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;
if (lastEffect !== null) {
@@ -13568,24 +14638,27 @@
if ((effect.tag & unmountTag) !== NoEffect$1) {
// Unmount
var destroy = effect.destroy;
- effect.destroy = null;
- if (destroy !== null) {
+ effect.destroy = undefined;
+ if (destroy !== undefined) {
destroy();
}
}
if ((effect.tag & mountTag) !== NoEffect$1) {
// Mount
var create = effect.create;
- var _destroy = create();
- if (typeof _destroy !== "function") {
+ effect.destroy = create();
+
{
- if (_destroy !== null && _destroy !== undefined) {
- warningWithoutStack$1(
- false,
- "useEffect function must return a cleanup function or " +
- "nothing.%s%s",
- typeof _destroy.then === "function"
- ? "\n\nIt looks like you wrote useEffect(async () => ...) or returned a Promise. " +
+ var _destroy = effect.destroy;
+ if (_destroy !== undefined && typeof _destroy !== "function") {
+ var addendum = void 0;
+ if (_destroy === null) {
+ addendum =
+ " You returned null. If your effect does not require clean " +
+ "up, return undefined (or nothing).";
+ } else if (typeof _destroy.then === "function") {
+ addendum =
+ "\n\nIt looks like you wrote useEffect(async () => ...) or returned a Promise. " +
"Instead, you may write an async function separately " +
"and then call it from inside the effect:\n\n" +
"async function fetchComment(commentId) {\n" +
@@ -13595,15 +14668,19 @@
" fetchComment(commentId);\n" +
"}, [commentId]);\n\n" +
"In the future, React will provide a more idiomatic solution for data fetching " +
- "that doesn't involve writing effects manually."
- : "",
+ "that doesn't involve writing effects manually.";
+ } else {
+ addendum = " You returned: " + _destroy;
+ }
+ warningWithoutStack$1(
+ false,
+ "An Effect function must not return anything besides a function, " +
+ "which is used for clean-up.%s%s",
+ addendum,
getStackByFiberInDevAndProd(finishedWork)
);
}
}
- _destroy = null;
- }
- effect.destroy = _destroy;
}
effect = effect.next;
} while (effect !== firstEffect);
@@ -13849,7 +14926,7 @@
function hideOrUnhideAllChildren(finishedWork, isHidden) {
if (supportsMutation) {
- // We only have the top Fiber that was inserted but we need recurse down its
+ // We only have the top Fiber that was inserted but we need to recurse down its
var node = finishedWork;
while (true) {
if (node.tag === HostComponent) {
@@ -13957,7 +15034,7 @@
var effect = firstEffect;
do {
var destroy = effect.destroy;
- if (destroy !== null) {
+ if (destroy !== undefined) {
safelyCallDestroy(current$$1, destroy);
}
effect = effect.next;
@@ -14129,7 +15206,11 @@
}
node.sibling.return = node.return;
node = node.sibling;
- while (node.tag !== HostComponent && node.tag !== HostText) {
+ while (
+ node.tag !== HostComponent &&
+ node.tag !== HostText &&
+ node.tag !== DehydratedSuspenseComponent
+ ) {
// If it is not host node and, we might have a host node inside it.
// Try to search down until we find one.
if (node.effectTag & Placement) {
@@ -14193,7 +15274,7 @@
}
var before = getHostSibling(finishedWork);
- // We only have the top Fiber that was inserted but we need recurse down its
+ // We only have the top Fiber that was inserted but we need to recurse down its
// children to find all the terminal nodes.
var node = finishedWork;
while (true) {
@@ -14235,7 +15316,7 @@
}
function unmountHostComponents(current$$1) {
- // We only have the top Fiber that was deleted but we need recurse down its
+ // We only have the top Fiber that was deleted but we need to recurse down its
var node = current$$1;
// Each iteration, currentParent is populated with node's host parent if not
@@ -14284,13 +15365,23 @@
removeChild(currentParent, node.stateNode);
}
// Don't visit children because we already visited them.
+ } else if (
+ enableSuspenseServerRenderer &&
+ node.tag === DehydratedSuspenseComponent
+ ) {
+ // Delete the dehydrated suspense boundary and all of its content.
+ if (currentParentIsContainer) {
+ clearSuspenseBoundaryFromContainer(currentParent, node.stateNode);
+ } else {
+ clearSuspenseBoundary(currentParent, node.stateNode);
+ }
} else if (node.tag === HostPortal) {
+ if (node.child !== null) {
// When we go into a portal, it becomes the parent to remove from.
// We will reassign it back when we pop the portal on the way up.
currentParent = node.stateNode.containerInfo;
currentParentIsContainer = true;
// Visit children because portals might contain host components.
- if (node.child !== null) {
node.child.return = node;
node = node.child;
continue;
@@ -14435,6 +15526,30 @@
if (primaryChildParent !== null) {
hideOrUnhideAllChildren(primaryChildParent, newDidTimeout);
}
+
+ // If this boundary just timed out, then it will have a set of thenables.
+ // For each thenable, attach a listener so that when it resolves, React
+ // attempts to re-render the boundary in the primary (pre-timeout) state.
+ var thenables = finishedWork.updateQueue;
+ if (thenables !== null) {
+ finishedWork.updateQueue = null;
+ var retryCache = finishedWork.stateNode;
+ if (retryCache === null) {
+ retryCache = finishedWork.stateNode = new PossiblyWeakSet$1();
+ }
+ thenables.forEach(function(thenable) {
+ // Memoize using the boundary fiber to prevent redundant listeners.
+ var retry = resolveRetryThenable.bind(null, finishedWork, thenable);
+ if (enableSchedulerTracing) {
+ retry = tracing.unstable_wrap(retry);
+ }
+ if (!retryCache.has(thenable)) {
+ retryCache.add(thenable);
+ thenable.then(retry, retry);
+ }
+ });
+ }
+
return;
}
case IncompleteClassComponent: {
@@ -14457,6 +15572,9 @@
resetTextContent(current$$1.stateNode);
}
+var PossiblyWeakSet = typeof WeakSet === "function" ? WeakSet : Set;
+var PossiblyWeakMap = typeof WeakMap === "function" ? WeakMap : Map;
+
function createRootErrorUpdate(fiber, errorInfo, expirationTime) {
var update = createUpdate(expirationTime);
// Unmount the root by rendering null.
@@ -14520,6 +15638,39 @@
return update;
}
+function attachPingListener(root, renderExpirationTime, thenable) {
+ // Attach a listener to the promise to "ping" the root and retry. But
+ // only if one does not already exist for the current render expiration
+ // time (which acts like a "thread ID" here).
+ var pingCache = root.pingCache;
+ var threadIDs = void 0;
+ if (pingCache === null) {
+ pingCache = root.pingCache = new PossiblyWeakMap();
+ threadIDs = new Set();
+ pingCache.set(thenable, threadIDs);
+ } else {
+ threadIDs = pingCache.get(thenable);
+ if (threadIDs === undefined) {
+ threadIDs = new Set();
+ pingCache.set(thenable, threadIDs);
+ }
+ }
+ if (!threadIDs.has(renderExpirationTime)) {
+ // Memoize using the thread ID to prevent redundant listeners.
+ threadIDs.add(renderExpirationTime);
+ var ping = pingSuspendedRoot.bind(
+ null,
+ root,
+ thenable,
+ renderExpirationTime
+ );
+ if (enableSchedulerTracing) {
+ ping = tracing.unstable_wrap(ping);
+ }
+ thenable.then(ping, ping);
+ }
+}
+
function throwException(
root,
returnFiber,
@@ -14574,6 +15725,9 @@
}
}
}
+ // If there is a DehydratedSuspenseComponent we don't have to do anything because
+ // if something suspends inside it, we will simply leave that as dehydrated. It
+ // will never timeout.
_workInProgress = _workInProgress.return;
} while (_workInProgress !== null);
@@ -14582,29 +15736,19 @@
do {
if (
_workInProgress.tag === SuspenseComponent &&
- shouldCaptureSuspense(_workInProgress.alternate, _workInProgress)
+ shouldCaptureSuspense(_workInProgress)
) {
// Found the nearest boundary.
- // If the boundary is not in concurrent mode, we should not suspend, and
- // likewise, when the promise resolves, we should ping synchronously.
- var pingTime =
- (_workInProgress.mode & ConcurrentMode) === NoEffect
- ? Sync
- : renderExpirationTime;
-
- // Attach a listener to the promise to "ping" the root and retry.
- var onResolveOrReject = retrySuspendedRoot.bind(
- null,
- root,
- _workInProgress,
- sourceFiber,
- pingTime
- );
- if (enableSchedulerTracing) {
- onResolveOrReject = tracing.unstable_wrap(onResolveOrReject);
+ // Stash the promise on the boundary fiber. If the boundary times out, we'll
+ var thenables = _workInProgress.updateQueue;
+ if (thenables === null) {
+ var updateQueue = new Set();
+ updateQueue.add(thenable);
+ _workInProgress.updateQueue = updateQueue;
+ } else {
+ thenables.add(thenable);
}
- thenable.then(onResolveOrReject, onResolveOrReject);
// If the boundary is outside of concurrent mode, we should *not*
// suspend the commit. Pretend as if the suspended component rendered
@@ -14623,18 +15767,25 @@
sourceFiber.effectTag &= ~(LifecycleEffectMask | Incomplete);
if (sourceFiber.tag === ClassComponent) {
- var _current = sourceFiber.alternate;
- if (_current === null) {
+ var currentSourceFiber = sourceFiber.alternate;
+ if (currentSourceFiber === null) {
// This is a new mount. Change the tag so it's not mistaken for a
// completed class component. For example, we should not call
// componentWillUnmount if it is deleted.
sourceFiber.tag = IncompleteClassComponent;
+ } else {
+ // When we try rendering again, we should not reuse the current fiber,
+ // since it's known to be in an inconsistent state. Use a force updte to
+ // prevent a bail out.
+ var update = createUpdate(Sync);
+ update.tag = ForceUpdate;
+ enqueueUpdate(sourceFiber, update);
}
}
- // The source fiber did not complete. Mark it with the current
- // render priority to indicate that it still has pending work.
- sourceFiber.expirationTime = renderExpirationTime;
+ // The source fiber did not complete. Mark it with Sync priority to
+ // indicate that it still has pending work.
+ sourceFiber.expirationTime = Sync;
// Exit without suspending.
return;
@@ -14643,9 +15794,11 @@
// Confirmed that the boundary is in a concurrent mode tree. Continue
// with the normal suspend path.
+ attachPingListener(root, renderExpirationTime, thenable);
+
var absoluteTimeoutMs = void 0;
if (earliestTimeoutMs === -1) {
- // If no explicit threshold is given, default to an abitrarily large
+ // If no explicit threshold is given, default to an arbitrarily large
// value. The actual size doesn't matter because the threshold for the
// whole tree will be clamped to the expiration time.
absoluteTimeoutMs = maxSigned31BitInt;
@@ -14681,6 +15834,40 @@
_workInProgress.effectTag |= ShouldCapture;
_workInProgress.expirationTime = renderExpirationTime;
return;
+ } else if (
+ enableSuspenseServerRenderer &&
+ _workInProgress.tag === DehydratedSuspenseComponent
+ ) {
+ attachPingListener(root, renderExpirationTime, thenable);
+
+ // Since we already have a current fiber, we can eagerly add a retry listener.
+ var retryCache = _workInProgress.memoizedState;
+ if (retryCache === null) {
+ retryCache = _workInProgress.memoizedState = new PossiblyWeakSet();
+ var _current = _workInProgress.alternate;
+ invariant(
+ _current,
+ "A dehydrated suspense boundary must commit before trying to render. " +
+ "This is probably a bug in React."
+ );
+ _current.memoizedState = retryCache;
+ }
+ // Memoize using the boundary fiber to prevent redundant listeners.
+ if (!retryCache.has(thenable)) {
+ retryCache.add(thenable);
+ var retry = resolveRetryThenable.bind(
+ null,
+ _workInProgress,
+ thenable
+ );
+ if (enableSchedulerTracing) {
+ retry = tracing.unstable_wrap(retry);
+ }
+ thenable.then(retry, retry);
+ }
+ _workInProgress.effectTag |= ShouldCapture;
+ _workInProgress.expirationTime = renderExpirationTime;
+ return;
}
// This boundary already captured during this render. Continue to the next
// boundary.
@@ -14710,12 +15897,12 @@
var _errorInfo = value;
workInProgress.effectTag |= ShouldCapture;
workInProgress.expirationTime = renderExpirationTime;
- var update = createRootErrorUpdate(
+ var _update = createRootErrorUpdate(
workInProgress,
_errorInfo,
renderExpirationTime
);
- enqueueCapturedUpdate(workInProgress, update);
+ enqueueCapturedUpdate(workInProgress, _update);
return;
}
case ClassComponent:
@@ -14733,12 +15920,12 @@
workInProgress.effectTag |= ShouldCapture;
workInProgress.expirationTime = renderExpirationTime;
// Schedule the error boundary to re-render using updated state
- var _update = createClassErrorUpdate(
+ var _update2 = createClassErrorUpdate(
workInProgress,
errorInfo,
renderExpirationTime
);
- enqueueCapturedUpdate(workInProgress, _update);
+ enqueueCapturedUpdate(workInProgress, _update2);
return;
}
break;
@@ -14776,6 +15963,7 @@
return workInProgress;
}
case HostComponent: {
+ // TODO: popHydrationState
popHostContext(workInProgress);
return null;
}
@@ -14788,6 +15976,19 @@
}
return null;
}
+ case DehydratedSuspenseComponent: {
+ if (enableSuspenseServerRenderer) {
+ // TODO: popHydrationState
+ var _effectTag3 = workInProgress.effectTag;
+ if (_effectTag3 & ShouldCapture) {
+ workInProgress.effectTag =
+ (_effectTag3 & ~ShouldCapture) | DidCapture;
+ // Captured a suspense effect. Re-render the boundary.
+ return workInProgress;
+ }
+ }
+ return null;
+ }
case HostPortal:
popHostContainer(workInProgress);
return null;
@@ -14828,22 +16029,7 @@
}
}
-var Dispatcher = {
- readContext: readContext,
- useCallback: useCallback,
- useContext: useContext,
- useEffect: useEffect,
- useImperativeMethods: useImperativeMethods,
- useLayoutEffect: useLayoutEffect,
- useMemo: useMemo,
- useReducer: useReducer,
- useRef: useRef,
- useState: useState
-};
-var DispatcherWithoutHooks = {
- readContext: readContext
-};
-
+var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
var ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner;
var didWarnAboutStateTransition = void 0;
@@ -14916,11 +16102,6 @@
};
}
-// Represents the expiration time that incoming updates should use. (If this
-// is NoWork, use the default strategy: async updates in async mode, sync
-// updates in sync mode.)
-var expirationContext = NoWork;
-
var isWorking = false;
// The next work in progress fiber that we're currently working on.
@@ -15153,6 +16334,9 @@
}
}
while (nextEffect !== null) {
+ {
+ setCurrentFiber(nextEffect);
+ }
var effectTag = nextEffect.effectTag;
if (effectTag & (Update | Callback)) {
@@ -15171,12 +16355,15 @@
commitAttachRef(nextEffect);
}
- if (enableHooks && effectTag & Passive) {
+ if (effectTag & Passive) {
rootWithPendingPassiveEffects = finishedRoot;
}
nextEffect = nextEffect.nextEffect;
}
+ {
+ resetCurrentFiber();
+ }
}
function commitPassiveEffects(root, firstEffect) {
@@ -15190,6 +16377,10 @@
var effect = firstEffect;
do {
+ {
+ setCurrentFiber(effect);
+ }
+
if (effect.effectTag & Passive) {
var didError = false;
var error = void 0;
@@ -15206,6 +16397,9 @@
}
effect = effect.nextEffect;
} while (effect !== null);
+ {
+ resetCurrentFiber();
+ }
isRendering = previousIsRendering;
@@ -15214,6 +16408,10 @@
if (rootExpirationTime !== NoWork) {
requestWork(root, rootExpirationTime);
}
+ // Flush any sync work that was scheduled by effects
+ if (!isBatchingUpdates && !isRendering) {
+ performSyncWork();
+ }
}
function isAlreadyFailedLegacyErrorBoundary(instance) {
@@ -15232,8 +16430,10 @@
}
function flushPassiveEffects() {
+ if (passiveEffectCallbackHandle !== null) {
+ cancelPassiveEffects(passiveEffectCallbackHandle);
+ }
if (passiveEffectCallback !== null) {
- scheduler.unstable_cancelCallback(passiveEffectCallbackHandle);
// We call the scheduled callback instead of commitPassiveEffects directly
// to ensure tracing works correctly.
passiveEffectCallback();
@@ -15407,11 +16607,7 @@
}
}
- if (
- enableHooks &&
- firstEffect !== null &&
- rootWithPendingPassiveEffects !== null
- ) {
+ if (firstEffect !== null && rootWithPendingPassiveEffects !== null) {
// This commit included a passive effect. These do not need to fire until
// after the next paint. Schedule an callback to fire them in an async
// event. To ensure serial execution, the callback will be flushed early if
@@ -15423,7 +16619,12 @@
// here because that code is still in flux.
callback = tracing.unstable_wrap(callback);
}
- passiveEffectCallbackHandle = scheduler.unstable_scheduleCallback(callback);
+ passiveEffectCallbackHandle = scheduler.unstable_runWithPriority(
+ scheduler.unstable_NormalPriority,
+ function() {
+ return schedulePassiveEffects(callback);
+ }
+ );
passiveEffectCallback = callback;
}
@@ -15826,7 +17027,7 @@
}
} else {
// Flush asynchronous work until there's a higher priority event
- while (nextUnitOfWork !== null && !shouldYieldToRenderer()) {
+ while (nextUnitOfWork !== null && !shouldYield$$1()) {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
}
}
@@ -15842,11 +17043,8 @@
flushPassiveEffects();
isWorking = true;
- if (enableHooks) {
- ReactCurrentOwner$2.currentDispatcher = Dispatcher;
- } else {
- ReactCurrentOwner$2.currentDispatcher = DispatcherWithoutHooks;
- }
+ var previousDispatcher = ReactCurrentDispatcher.current;
+ ReactCurrentDispatcher.current = ContextOnlyDispatcher;
var expirationTime = root.nextExpirationTimeToWorkOn;
@@ -15900,7 +17098,7 @@
subscriber.onWorkStarted(interactions, threadID);
} catch (error) {
// Work thrown by an interaction tracing subscriber should be rethrown,
- // But only once it's safe (to avoid leaveing the scheduler in an invalid state).
+ // But only once it's safe (to avoid leaving the scheduler in an invalid state).
// Store the error for now and we'll re-throw in finishRendering().
if (!hasUnhandledError) {
hasUnhandledError = true;
@@ -16007,7 +17205,7 @@
// We're done performing work. Time to clean up.
isWorking = false;
- ReactCurrentOwner$2.currentDispatcher = null;
+ ReactCurrentDispatcher.current = previousDispatcher;
resetContextDependences();
resetHooks();
@@ -16077,7 +17275,7 @@
return;
} else if (
// There's no lower priority work, but we're rendering asynchronously.
- // Synchronsouly attempt to render the same level one more time. This is
+ // Synchronously attempt to render the same level one more time. This is
// similar to a suspend, but without a timeout because we're not waiting
// for a promise to resolve.
!root.didError &&
@@ -16191,52 +17389,58 @@
}
function computeExpirationForFiber(currentTime, fiber) {
+ var priorityLevel = scheduler.unstable_getCurrentPriorityLevel();
+
var expirationTime = void 0;
- if (expirationContext !== NoWork) {
- // An explicit expiration context was set;
- expirationTime = expirationContext;
- } else if (isWorking) {
- if (isCommitting$1) {
- // Updates that occur during the commit phase should have sync priority
- // by default.
+ if ((fiber.mode & ConcurrentMode) === NoContext) {
+ // Outside of concurrent mode, updates are always synchronous.
expirationTime = Sync;
- } else {
- // Updates during the render phase should expire at the same time as
- // the work that is being rendered.
+ } else if (isWorking && !isCommitting$1) {
+ // During render phase, updates expire during as the current render.
expirationTime = nextRenderExpirationTime;
- }
} else {
- // No explicit expiration context was set, and we're not currently
- // performing work. Calculate a new expiration time.
- if (fiber.mode & ConcurrentMode) {
- if (isBatchingInteractiveUpdates) {
- // This is an interactive update
+ switch (priorityLevel) {
+ case scheduler.unstable_ImmediatePriority:
+ expirationTime = Sync;
+ break;
+ case scheduler.unstable_UserBlockingPriority:
expirationTime = computeInteractiveExpiration(currentTime);
- } else {
- // This is an async update
+ break;
+ case scheduler.unstable_NormalPriority:
+ // This is a normal, concurrent update
expirationTime = computeAsyncExpiration(currentTime);
+ break;
+ case scheduler.unstable_LowPriority:
+ case scheduler.unstable_IdlePriority:
+ expirationTime = Never;
+ break;
+ default:
+ invariant(
+ false,
+ "Unknown priority level. This error is likely caused by a bug in " +
+ "React. Please file an issue."
+ );
}
+
// If we're in the middle of rendering a tree, do not update at the same
// expiration time that is already rendering.
if (nextRoot !== null && expirationTime === nextRenderExpirationTime) {
expirationTime -= 1;
}
- } else {
- // This is a sync update
- expirationTime = Sync;
- }
}
- if (isBatchingInteractiveUpdates) {
- // This is an interactive update. Keep track of the lowest pending
- // interactive expiration time. This allows us to synchronously flush
- // all interactive updates when needed.
- if (
- lowestPriorityPendingInteractiveExpirationTime === NoWork ||
- expirationTime < lowestPriorityPendingInteractiveExpirationTime
+
+ // Keep track of the lowest pending interactive expiration time. This
+ // allows us to synchronously flush all interactive updates
+ // when needed.
+ // TODO: Move this to renderer?
+ if (
+ priorityLevel === scheduler.unstable_UserBlockingPriority &&
+ (lowestPriorityPendingInteractiveExpirationTime === NoWork ||
+ expirationTime < lowestPriorityPendingInteractiveExpirationTime)
) {
lowestPriorityPendingInteractiveExpirationTime = expirationTime;
}
- }
+
return expirationTime;
}
@@ -16254,57 +17458,77 @@
nextRenderDidError = true;
}
-function retrySuspendedRoot(root, boundaryFiber, sourceFiber, suspendedTime) {
- var retryTime = void 0;
-
- if (isPriorityLevelSuspended(root, suspendedTime)) {
- // Ping at the original level
- retryTime = suspendedTime;
-
- markPingedPriorityLevel(root, retryTime);
- } else {
- // Suspense already timed out. Compute a new expiration time
- var currentTime = requestCurrentTime();
- retryTime = computeExpirationForFiber(currentTime, boundaryFiber);
- markPendingPriorityLevel(root, retryTime);
+function pingSuspendedRoot(root, thenable, pingTime) {
+ // A promise that previously suspended React from committing has resolved.
+ // If React is still suspended, try again at the previous level (pingTime).
+
+ var pingCache = root.pingCache;
+ if (pingCache !== null) {
+ // The thenable resolved, so we no longer need to memoize, because it will
+ // never be thrown again.
+ pingCache.delete(thenable);
}
- // TODO: If the suspense fiber has already rendered the primary children
- // without suspending (that is, all of the promises have already resolved),
- // we should not trigger another update here. One case this happens is when
- // we are in sync mode and a single promise is thrown both on initial render
- // and on update; we attach two .then(retrySuspendedRoot) callbacks and each
- // one performs Sync work, rerendering the Suspense.
-
- if ((boundaryFiber.mode & ConcurrentMode) !== NoContext) {
- if (root === nextRoot && nextRenderExpirationTime === suspendedTime) {
+ if (nextRoot !== null && nextRenderExpirationTime === pingTime) {
// Received a ping at the same priority level at which we're currently
// rendering. Restart from the root.
nextRoot = null;
+ } else {
+ // Confirm that the root is still suspended at this level. Otherwise exit.
+ if (isPriorityLevelSuspended(root, pingTime)) {
+ // Ping at the original level
+ markPingedPriorityLevel(root, pingTime);
+ var rootExpirationTime = root.expirationTime;
+ if (rootExpirationTime !== NoWork) {
+ requestWork(root, rootExpirationTime);
}
}
-
- scheduleWorkToRoot(boundaryFiber, retryTime);
- if ((boundaryFiber.mode & ConcurrentMode) === NoContext) {
- // Outside of concurrent mode, we must schedule an update on the source
- // fiber, too, since it already committed in an inconsistent state and
- // therefore does not have any pending work.
- scheduleWorkToRoot(sourceFiber, retryTime);
- var sourceTag = sourceFiber.tag;
- if (sourceTag === ClassComponent && sourceFiber.stateNode !== null) {
- // When we try rendering again, we should not reuse the current fiber,
- // since it's known to be in an inconsistent state. Use a force updte to
- // prevent a bail out.
- var update = createUpdate(retryTime);
- update.tag = ForceUpdate;
- enqueueUpdate(sourceFiber, update);
- }
}
+}
+function retryTimedOutBoundary(boundaryFiber) {
+ var currentTime = requestCurrentTime();
+ var retryTime = computeExpirationForFiber(currentTime, boundaryFiber);
+ var root = scheduleWorkToRoot(boundaryFiber, retryTime);
+ if (root !== null) {
+ markPendingPriorityLevel(root, retryTime);
var rootExpirationTime = root.expirationTime;
if (rootExpirationTime !== NoWork) {
requestWork(root, rootExpirationTime);
}
+ }
+}
+
+function resolveRetryThenable(boundaryFiber, thenable) {
+ // The boundary fiber (a Suspense component) previously timed out and was
+ // rendered in its fallback state. One of the promises that suspended it has
+ // resolved, which means at least part of the tree was likely unblocked. Try
+ var retryCache = void 0;
+ if (enableSuspenseServerRenderer) {
+ switch (boundaryFiber.tag) {
+ case SuspenseComponent:
+ retryCache = boundaryFiber.stateNode;
+ break;
+ case DehydratedSuspenseComponent:
+ retryCache = boundaryFiber.memoizedState;
+ break;
+ default:
+ invariant(
+ false,
+ "Pinged unknown suspense boundary type. " +
+ "This is probably a bug in React."
+ );
+ }
+ } else {
+ retryCache = boundaryFiber.stateNode;
+ }
+ if (retryCache !== null) {
+ // The thenable resolved, so we no longer need to memoize, because it will
+ // never be thrown again.
+ retryCache.delete(thenable);
+ }
+
+ retryTimedOutBoundary(boundaryFiber);
}
function scheduleWorkToRoot(fiber, expirationTime) {
@@ -16393,6 +17617,27 @@
return root;
}
+function warnIfNotCurrentlyBatchingInDev(fiber) {
+ {
+ if (isRendering === false && isBatchingUpdates === false) {
+ warningWithoutStack$1(
+ false,
+ "An update to %s inside a test was not wrapped in act(...).\n\n" +
+ "When testing, code that causes React state updates should be wrapped into act(...):\n\n" +
+ "act(() => {\n" +
+ " /* fire events that update state */\n" +
+ "});\n" +
+ "/* assert on the output */\n\n" +
+ "This ensures that you're testing the behavior the user would see in the browser." +
+ " Learn more at https://fb.me/react-wrap-tests-with-act" +
+ "%s",
+ getComponentName(fiber.type),
+ getStackByFiberInDevAndProd(fiber)
+ );
+ }
+ }
+}
+
function scheduleWork(fiber, expirationTime) {
var root = scheduleWorkToRoot(fiber, expirationTime);
if (root === null) {
@@ -16464,7 +17709,6 @@
var isBatchingUpdates = false;
var isUnbatchingUpdates = false;
-var isBatchingInteractiveUpdates = false;
var completedBatches = null;
@@ -16530,7 +17774,7 @@
msUntilTimeout
) {
root.expirationTime = rootExpirationTime;
- if (msUntilTimeout === 0 && !shouldYieldToRenderer()) {
+ if (msUntilTimeout === 0 && !shouldYield$$1()) {
// Don't wait an additional tick. Commit the tree immediately.
root.pendingCommitExpirationTime = suspendedExpirationTime;
root.finishedWork = finishedWork;
@@ -16727,24 +17971,8 @@
nextFlushedExpirationTime = highestPriorityWork;
}
-// TODO: This wrapper exists because many of the older tests (the ones that use
-// flushDeferredPri) rely on the number of times `shouldYield` is called. We
-// should get rid of it.
-var didYield = false;
-function shouldYieldToRenderer() {
- if (didYield) {
- return true;
- }
- if (shouldYield$$1()) {
- didYield = true;
- return true;
- }
- return false;
-}
-
-function performAsyncWork() {
- try {
- if (!shouldYieldToRenderer()) {
+function performAsyncWork(didTimeout) {
+ if (didTimeout) {
// The callback timed out. That means at least one update has expired.
// Iterate through the root schedule. If they contain expired work, set
// the next render expiration time to the current time. This has the effect
@@ -16761,9 +17989,6 @@
}
}
performWork(NoWork, true);
- } finally {
- didYield = false;
- }
}
function performSyncWork() {
@@ -16789,7 +18014,7 @@
nextFlushedRoot !== null &&
nextFlushedExpirationTime !== NoWork &&
minExpirationTime <= nextFlushedExpirationTime &&
- !(didYield && currentRendererTime > nextFlushedExpirationTime)
+ !(shouldYield$$1() && currentRendererTime > nextFlushedExpirationTime)
) {
performWorkOnRoot(
nextFlushedRoot,
@@ -16933,7 +18158,7 @@
if (_finishedWork !== null) {
// We've completed the root. Check the if we should yield one more time
// before committing.
- if (!shouldYieldToRenderer()) {
+ if (!shouldYield$$1()) {
// Still time left. Commit the root.
completeRoot$1(root, _finishedWork, expirationTime);
} else {
@@ -16980,7 +18205,12 @@
lastCommittedRootDuringThisBatch = root;
nestedUpdateCount = 0;
}
+ scheduler.unstable_runWithPriority(
+ scheduler.unstable_ImmediatePriority,
+ function() {
commitRoot(root, finishedWork);
+ }
+ );
}
function onUncaughtError(error) {
@@ -17014,9 +18244,6 @@
}
function interactiveUpdates$1(fn, a, b) {
- if (isBatchingInteractiveUpdates) {
- return fn(a, b);
- }
// If there are any pending interactive updates, synchronously flush them.
// This needs to happen before we read any handlers, because the effect of
// the previous event may influence which handlers are called during
@@ -17030,14 +18257,16 @@
performWork(lowestPriorityPendingInteractiveExpirationTime, false);
lowestPriorityPendingInteractiveExpirationTime = NoWork;
}
- var previousIsBatchingInteractiveUpdates = isBatchingInteractiveUpdates;
var previousIsBatchingUpdates = isBatchingUpdates;
- isBatchingInteractiveUpdates = true;
isBatchingUpdates = true;
try {
+ return scheduler.unstable_runWithPriority(
+ scheduler.unstable_UserBlockingPriority,
+ function() {
return fn(a, b);
+ }
+ );
} finally {
- isBatchingInteractiveUpdates = previousIsBatchingInteractiveUpdates;
isBatchingUpdates = previousIsBatchingUpdates;
if (!isBatchingUpdates && !isRendering) {
performSyncWork();
@@ -17265,11 +18494,43 @@
}
}
+var overrideProps = null;
+
+{
+ var copyWithSetImpl = function(obj, path, idx, value) {
+ if (idx >= path.length) {
+ return value;
+ }
+ var key = path[idx];
+ var updated = Array.isArray(obj) ? obj.slice() : Object.assign({}, obj);
+ // $FlowFixMe number or string is fine here
+ updated[key] = copyWithSetImpl(obj[key], path, idx + 1, value);
+ return updated;
+ };
+
+ var copyWithSet = function(obj, path, value) {
+ return copyWithSetImpl(obj, path, 0, value);
+ };
+
+ // Support DevTools props for function components, forwardRef, memo, host components, etc.
+ overrideProps = function(fiber, path, value) {
+ flushPassiveEffects();
+ fiber.pendingProps = copyWithSet(fiber.memoizedProps, path, value);
+ if (fiber.alternate) {
+ fiber.alternate.pendingProps = fiber.pendingProps;
+ }
+ scheduleWork(fiber, Sync);
+ };
+}
+
function injectIntoDevTools(devToolsConfig) {
var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance;
+ var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
return injectInternals(
Object.assign({}, devToolsConfig, {
+ overrideProps: overrideProps,
+ currentDispatcherRef: ReactCurrentDispatcher,
findHostInstanceByFiber: function(fiber) {
var hostFiber = findCurrentHostFiber(fiber);
if (hostFiber === null) {
@@ -17312,7 +18573,7 @@
// TODO: this is special because it gets imported during build.
-var ReactVersion = "16.6.1";
+var ReactVersion = "16.8.3";
// Modules provided by RN:
var NativeMethodsMixin = function(findNodeHandle, findHostInstance) {
@@ -17406,6 +18667,17 @@
* Manipulation](docs/direct-manipulation.html)).
*/
setNativeProps: function(nativeProps) {
+ {
+ if (warnAboutDeprecatedSetNativeProps) {
+ warningWithoutStack$1(
+ false,
+ "Warning: Calling ref.setNativeProps(nativeProps) " +
+ "is deprecated and will be removed in a future release. " +
+ "Use the setNativeProps export from the react-native package instead." +
+ "\n\timport {setNativeProps} from 'react-native';\n\tsetNativeProps(ref, nativeProps);\n"
+ );
+ }
+ }
// Class components don't have viewConfig -> validateAttributes.
// Nor does it make sense to set native props on a non-native component.
// Instead, find the nearest host component and set props on it.
@@ -17427,7 +18699,10 @@
return;
}
- var viewConfig = maybeInstance.viewConfig;
+ var nativeTag =
+ maybeInstance._nativeTag || maybeInstance.canonical._nativeTag;
+ var viewConfig =
+ maybeInstance.viewConfig || maybeInstance.canonical.viewConfig;
{
warnForStyleProps(nativeProps, viewConfig.validAttributes);
@@ -17440,7 +18715,7 @@
// view invalidation for certain components (eg RCTTextInput) on iOS.
if (updatePayload != null) {
UIManager.updateView(
- maybeInstance._nativeTag,
+ nativeTag,
viewConfig.uiViewClassName,
updatePayload
);
@@ -17661,6 +18936,18 @@
ReactNativeComponent.prototype.setNativeProps = function setNativeProps(
nativeProps
) {
+ {
+ if (warnAboutDeprecatedSetNativeProps) {
+ warningWithoutStack$1(
+ false,
+ "Warning: Calling ref.setNativeProps(nativeProps) " +
+ "is deprecated and will be removed in a future release. " +
+ "Use the setNativeProps export from the react-native package instead." +
+ "\n\timport {setNativeProps} from 'react-native';\n\tsetNativeProps(ref, nativeProps);\n"
+ );
+ }
+ }
+
// Class components don't have viewConfig -> validateAttributes.
// Nor does it make sense to set native props on a non-native component.
// Instead, find the nearest host component and set props on it.
@@ -17682,6 +18969,8 @@
return;
}
+ var nativeTag =
+ maybeInstance._nativeTag || maybeInstance.canonical._nativeTag;
var viewConfig =
maybeInstance.viewConfig || maybeInstance.canonical.viewConfig;
@@ -17692,7 +18981,7 @@
// view invalidation for certain components (eg RCTTextInput) on iOS.
if (updatePayload != null) {
UIManager.updateView(
- maybeInstance._nativeTag,
+ nativeTag,
viewConfig.uiViewClassName,
updatePayload
);
@@ -17820,6 +19109,36 @@
};
}
+// Module provided by RN:
+function setNativeProps(handle, nativeProps) {
+ if (handle._nativeTag == null) {
+ !(handle._nativeTag != null)
+ ? warningWithoutStack$1(
+ false,
+ "setNativeProps was called with a ref that isn't a " +
+ "native component. Use React.forwardRef to get access to the underlying native component"
+ )
+ : void 0;
+ return;
+ }
+
+ {
+ warnForStyleProps(nativeProps, handle.viewConfig.validAttributes);
+ }
+
+ var updatePayload = create(nativeProps, handle.viewConfig.validAttributes);
+ // Avoid the overhead of bridge calls if there's no update.
+ // This is an expensive no-op for Android, and causes an unnecessary
+ // view invalidation for certain components (eg RCTTextInput) on iOS.
+ if (updatePayload != null) {
+ UIManager.updateView(
+ handle._nativeTag,
+ handle.viewConfig.uiViewClassName,
+ updatePayload
+ );
+ }
+}
+
var ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
function findNodeHandle(componentOrHandle) {
@@ -17887,6 +19206,8 @@
findNodeHandle: findNodeHandle,
+ setNativeProps: setNativeProps,
+
render: function(element, containerTag, callback) {
var root = roots.get(containerTag);

Libraries/Renderer/oss/ReactFabric-prod.js

@@ -1019,8 +1019,10 @@
}
});
var ReactSharedInternals =
- React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
- hasSymbol = "function" === typeof Symbol && Symbol.for,
+ React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
+ReactSharedInternals.hasOwnProperty("ReactCurrentDispatcher") ||
+ (ReactSharedInternals.ReactCurrentDispatcher = { current: null });
+var hasSymbol = "function" === typeof Symbol && Symbol.for,
REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for("react.element") : 60103,
REACT_PORTAL_TYPE = hasSymbol ? Symbol.for("react.portal") : 60106,
REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for("react.fragment") : 60107,
@@ -1430,6 +1432,10 @@
scheduledCallback = null;
null !== callback && callback();
}
+function scheduleDeferredCallback$1(callback) {
+ scheduledCallback = callback;
+ return setTimeout(setTimeoutCallback, 1);
+}
var restoreTarget = null,
restoreQueue = null;
function restoreStateOfTarget(target) {
@@ -1777,7 +1783,7 @@
this.index = 0;
this.ref = null;
this.pendingProps = pendingProps;
- this.firstContextDependency = this.memoizedState = this.updateQueue = this.memoizedProps = null;
+ this.contextDependencies = this.memoizedState = this.updateQueue = this.memoizedProps = null;
this.mode = mode;
this.effectTag = 0;
this.lastEffect = this.firstEffect = this.nextEffect = null;
@@ -1826,7 +1832,7 @@
workInProgress.memoizedProps = current.memoizedProps;
workInProgress.memoizedState = current.memoizedState;
workInProgress.updateQueue = current.updateQueue;
- workInProgress.firstContextDependency = current.firstContextDependency;
+ workInProgress.contextDependencies = current.contextDependencies;
workInProgress.sibling = current.sibling;
workInProgress.index = current.index;
workInProgress.ref = current.ref;
@@ -1950,26 +1956,53 @@
(root.latestPendingTime = expirationTime);
findNextExpirationTimeToWorkOn(expirationTime, root);
}
-function markSuspendedPriorityLevel(root, suspendedTime) {
+function markCommittedPriorityLevels(root, earliestRemainingTime) {
root.didError = !1;
- var latestPingedTime = root.latestPingedTime;
- 0 !== latestPingedTime &&
- latestPingedTime >= suspendedTime &&
+ if (0 === earliestRemainingTime)
+ (root.earliestPendingTime = 0),
+ (root.latestPendingTime = 0),
+ (root.earliestSuspendedTime = 0),
+ (root.latestSuspendedTime = 0),
+ (root.latestPingedTime = 0);
+ else {
+ earliestRemainingTime < root.latestPingedTime &&
(root.latestPingedTime = 0);
- latestPingedTime = root.earliestPendingTime;
var latestPendingTime = root.latestPendingTime;
- latestPingedTime === suspendedTime
+ 0 !== latestPendingTime &&
+ (latestPendingTime > earliestRemainingTime
+ ? (root.earliestPendingTime = root.latestPendingTime = 0)
+ : root.earliestPendingTime > earliestRemainingTime &&
+ (root.earliestPendingTime = root.latestPendingTime));
+ latestPendingTime = root.earliestSuspendedTime;
+ 0 === latestPendingTime
+ ? markPendingPriorityLevel(root, earliestRemainingTime)
+ : earliestRemainingTime < root.latestSuspendedTime
+ ? ((root.earliestSuspendedTime = 0),
+ (root.latestSuspendedTime = 0),
+ (root.latestPingedTime = 0),
+ markPendingPriorityLevel(root, earliestRemainingTime))
+ : earliestRemainingTime > latestPendingTime &&
+ markPendingPriorityLevel(root, earliestRemainingTime);
+ }
+ findNextExpirationTimeToWorkOn(0, root);
+}
+function markSuspendedPriorityLevel(root, suspendedTime) {
+ root.didError = !1;
+ root.latestPingedTime >= suspendedTime && (root.latestPingedTime = 0);
+ var earliestPendingTime = root.earliestPendingTime,
+ latestPendingTime = root.latestPendingTime;
+ earliestPendingTime === suspendedTime
? (root.earliestPendingTime =
latestPendingTime === suspendedTime
? (root.latestPendingTime = 0)
: latestPendingTime)
: latestPendingTime === suspendedTime &&
- (root.latestPendingTime = latestPingedTime);
- latestPingedTime = root.earliestSuspendedTime;
+ (root.latestPendingTime = earliestPendingTime);
+ earliestPendingTime = root.earliestSuspendedTime;
latestPendingTime = root.latestSuspendedTime;
- 0 === latestPingedTime
+ 0 === earliestPendingTime
? (root.earliestSuspendedTime = root.latestSuspendedTime = suspendedTime)
- : latestPingedTime < suspendedTime
+ : earliestPendingTime < suspendedTime
? (root.earliestSuspendedTime = suspendedTime)
: latestPendingTime > suspendedTime &&
(root.latestSuspendedTime = suspendedTime);
@@ -2001,328 +2034,10 @@
root.nextExpirationTimeToWorkOn = earliestPendingTime;
root.expirationTime = completedExpirationTime;
}
-var hasForceUpdate = !1;
-function createUpdateQueue(baseState) {
- return {
- baseState: baseState,
- firstUpdate: null,
- lastUpdate: null,
- firstCapturedUpdate: null,
- lastCapturedUpdate: null,
- firstEffect: null,
- lastEffect: null,
- firstCapturedEffect: null,
- lastCapturedEffect: null
- };
-}
-function cloneUpdateQueue(currentQueue) {
- return {
- baseState: currentQueue.baseState,
- firstUpdate: currentQueue.firstUpdate,
- lastUpdate: currentQueue.lastUpdate,
- firstCapturedUpdate: null,
- lastCapturedUpdate: null,
- firstEffect: null,
- lastEffect: null,
- firstCapturedEffect: null,
- lastCapturedEffect: null
- };
-}
-function createUpdate(expirationTime) {
- return {
- expirationTime: expirationTime,
- tag: 0,
- payload: null,
- callback: null,
- next: null,
- nextEffect: null
- };
-}
-function appendUpdateToQueue(queue, update) {
- null === queue.lastUpdate
- ? (queue.firstUpdate = queue.lastUpdate = update)
- : ((queue.lastUpdate.next = update), (queue.lastUpdate = update));
-}
-function enqueueUpdate(fiber, update) {
- var alternate = fiber.alternate;
- if (null === alternate) {
- var queue1 = fiber.updateQueue;
- var queue2 = null;
- null === queue1 &&
- (queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState));
- } else
- (queue1 = fiber.updateQueue),
- (queue2 = alternate.updateQueue),
- null === queue1
- ? null === queue2
- ? ((queue1 = fiber.updateQueue = createUpdateQueue(
- fiber.memoizedState
- )),
- (queue2 = alternate.updateQueue = createUpdateQueue(
- alternate.memoizedState
- )))
- : (queue1 = fiber.updateQueue = cloneUpdateQueue(queue2))
- : null === queue2 &&
- (queue2 = alternate.updateQueue = cloneUpdateQueue(queue1));
- null === queue2 || queue1 === queue2
- ? appendUpdateToQueue(queue1, update)
- : null === queue1.lastUpdate || null === queue2.lastUpdate
- ? (appendUpdateToQueue(queue1, update),
- appendUpdateToQueue(queue2, update))
- : (appendUpdateToQueue(queue1, update), (queue2.lastUpdate = update));
-}
-function enqueueCapturedUpdate(workInProgress, update) {
- var workInProgressQueue = workInProgress.updateQueue;
- workInProgressQueue =
- null === workInProgressQueue
- ? (workInProgress.updateQueue = createUpdateQueue(
- workInProgress.memoizedState
- ))
- : ensureWorkInProgressQueueIsAClone(workInProgress, workInProgressQueue);
- null === workInProgressQueue.lastCapturedUpdate
- ? (workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update)
- : ((workInProgressQueue.lastCapturedUpdate.next = update),
- (workInProgressQueue.lastCapturedUpdate = update));
-}
-function ensureWorkInProgressQueueIsAClone(workInProgress, queue) {
- var current = workInProgress.alternate;
- null !== current &&
- queue === current.updateQueue &&
- (queue = workInProgress.updateQueue = cloneUpdateQueue(queue));
- return queue;
-}
-function getStateFromUpdate(
- workInProgress,
- queue,
- update,
- prevState,
- nextProps,
- instance
-) {
- switch (update.tag) {
- case 1:
- return (
- (workInProgress = update.payload),
- "function" === typeof workInProgress
- ? workInProgress.call(instance, prevState, nextProps)
- : workInProgress
- );
- case 3:
- workInProgress.effectTag = (workInProgress.effectTag & -2049) | 64;
- case 0:
- workInProgress = update.payload;
- nextProps =
- "function" === typeof workInProgress
- ? workInProgress.call(instance, prevState, nextProps)
- : workInProgress;
- if (null === nextProps || void 0 === nextProps) break;
- return Object.assign({}, prevState, nextProps);
- case 2:
- hasForceUpdate = !0;
- }
- return prevState;
-}
-function processUpdateQueue(
- workInProgress,
- queue,
- props,
- instance,
- renderExpirationTime
-) {
- hasForceUpdate = !1;
- queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue);
- for (
- var newBaseState = queue.baseState,
- newFirstUpdate = null,
- newExpirationTime = 0,
- update = queue.firstUpdate,
- resultState = newBaseState;
- null !== update;
-
- ) {
- var updateExpirationTime = update.expirationTime;
- updateExpirationTime < renderExpirationTime
- ? (null === newFirstUpdate &&
- ((newFirstUpdate = update), (newBaseState = resultState)),
- newExpirationTime < updateExpirationTime &&
- (newExpirationTime = updateExpirationTime))
- : ((resultState = getStateFromUpdate(
- workInProgress,
- queue,
- update,
- resultState,
- props,
- instance
- )),
- null !== update.callback &&
- ((workInProgress.effectTag |= 32),
- (update.nextEffect = null),
- null === queue.lastEffect
- ? (queue.firstEffect = queue.lastEffect = update)
- : ((queue.lastEffect.nextEffect = update),
- (queue.lastEffect = update))));
- update = update.next;
- }
- updateExpirationTime = null;
- for (update = queue.firstCapturedUpdate; null !== update; ) {
- var _updateExpirationTime = update.expirationTime;
- _updateExpirationTime < renderExpirationTime
- ? (null === updateExpirationTime &&
- ((updateExpirationTime = update),
- null === newFirstUpdate && (newBaseState = resultState)),
- newExpirationTime < _updateExpirationTime &&
- (newExpirationTime = _updateExpirationTime))
- : ((resultState = getStateFromUpdate(
- workInProgress,
- queue,
- update,
- resultState,
- props,
- instance
- )),
- null !== update.callback &&
- ((workInProgress.effectTag |= 32),
- (update.nextEffect = null),
- null === queue.lastCapturedEffect
- ? (queue.firstCapturedEffect = queue.lastCapturedEffect = update)
- : ((queue.lastCapturedEffect.nextEffect = update),
- (queue.lastCapturedEffect = update))));
- update = update.next;
- }
- null === newFirstUpdate && (queue.lastUpdate = null);
- null === updateExpirationTime
- ? (queue.lastCapturedUpdate = null)
- : (workInProgress.effectTag |= 32);
- null === newFirstUpdate &&
- null === updateExpirationTime &&
- (newBaseState = resultState);
- queue.baseState = newBaseState;
- queue.firstUpdate = newFirstUpdate;
- queue.firstCapturedUpdate = updateExpirationTime;
- workInProgress.expirationTime = newExpirationTime;
- workInProgress.memoizedState = resultState;
-}
-function commitUpdateQueue(finishedWork, finishedQueue, instance) {
- null !== finishedQueue.firstCapturedUpdate &&
- (null !== finishedQueue.lastUpdate &&
- ((finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate),
- (finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate)),
- (finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null));
- commitUpdateEffects(finishedQueue.firstEffect, instance);
- finishedQueue.firstEffect = finishedQueue.lastEffect = null;
- commitUpdateEffects(finishedQueue.firstCapturedEffect, instance);
- finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null;
-}
-function commitUpdateEffects(effect, instance) {
- for (; null !== effect; ) {
- var _callback3 = effect.callback;
- if (null !== _callback3) {
- effect.callback = null;
- var context = instance;
- invariant(
- "function" === typeof _callback3,
- "Invalid argument passed as callback. Expected a function. Instead received: %s",
- _callback3
- );
- _callback3.call(context);
- }
- effect = effect.nextEffect;
- }
-}
-function createCapturedValue(value, source) {
- return {
- value: value,
- source: source,
- stack: getStackByFiberInDevAndProd(source)
- };
-}
-var valueCursor = { current: null },
- currentlyRenderingFiber = null,
- lastContextDependency = null,
- lastContextWithAllBitsObserved = null;
-function pushProvider(providerFiber, nextValue) {
- var context = providerFiber.type._context;
- push(valueCursor, context._currentValue2, providerFiber);
- context._currentValue2 = nextValue;
-}
-function popProvider(providerFiber) {
- var currentValue = valueCursor.current;
- pop(valueCursor, providerFiber);
- providerFiber.type._context._currentValue2 = currentValue;
-}
-function prepareToReadContext(workInProgress) {
- currentlyRenderingFiber = workInProgress;
- lastContextWithAllBitsObserved = lastContextDependency = null;
- workInProgress.firstContextDependency = null;
-}
-function readContext(context, observedBits) {
- if (
- lastContextWithAllBitsObserved !== context &&
- !1 !== observedBits &&
- 0 !== observedBits
- ) {
- if ("number" !== typeof observedBits || 1073741823 === observedBits)
- (lastContextWithAllBitsObserved = context), (observedBits = 1073741823);
- observedBits = { context: context, observedBits: observedBits, next: null };
- null === lastContextDependency
- ? (invariant(
- null !== currentlyRenderingFiber,
- "Context can only be read while React is rendering, e.g. inside the render method or getDerivedStateFromProps."
- ),
- (currentlyRenderingFiber.firstContextDependency = lastContextDependency = observedBits))
- : (lastContextDependency = lastContextDependency.next = observedBits);
- }
- return context._currentValue2;
-}
-var NO_CONTEXT = {},
- contextStackCursor$1 = { current: NO_CONTEXT },
- contextFiberStackCursor = { current: NO_CONTEXT },
- rootInstanceStackCursor = { current: NO_CONTEXT };
-function requiredContext(c) {
- invariant(
- c !== NO_CONTEXT,
- "Expected host context to exist. This error is likely caused by a bug in React. Please file an issue."
- );
- return c;
-}
-function pushHostContainer(fiber, nextRootInstance) {
- push(rootInstanceStackCursor, nextRootInstance, fiber);
- push(contextFiberStackCursor, fiber, fiber);
- push(contextStackCursor$1, NO_CONTEXT, fiber);
- pop(contextStackCursor$1, fiber);
- push(contextStackCursor$1, { isInAParentText: !1 }, fiber);
-}
-function popHostContainer(fiber) {
- pop(contextStackCursor$1, fiber);
- pop(contextFiberStackCursor, fiber);
- pop(rootInstanceStackCursor, fiber);
-}
-function pushHostContext(fiber) {
- requiredContext(rootInstanceStackCursor.current);
- var context = requiredContext(contextStackCursor$1.current);
- var nextContext = fiber.type;
- nextContext =
- "AndroidTextInput" === nextContext ||
- "RCTMultilineTextInputView" === nextContext ||
- "RCTSinglelineTextInputView" === nextContext ||
- "RCTText" === nextContext ||
- "RCTVirtualText" === nextContext;
- nextContext =
- context.isInAParentText !== nextContext
- ? { isInAParentText: nextContext }
- : context;
- context !== nextContext &&
- (push(contextFiberStackCursor, fiber, fiber),
- push(contextStackCursor$1, nextContext, fiber));
-}
-function popHostContext(fiber) {
- contextFiberStackCursor.current === fiber &&
- (pop(contextStackCursor$1, fiber), pop(contextFiberStackCursor, fiber));
-}
-var hasOwnProperty = Object.prototype.hasOwnProperty;
function is(x, y) {
- return x === y ? 0 !== x || 0 !== y || 1 / x === 1 / y : x !== x && y !== y;
+ return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y);
}
+var hasOwnProperty = Object.prototype.hasOwnProperty;
function shallowEqual(objA, objB) {
if (is(objA, objB)) return !0;
if (
@@ -2363,9 +2078,9 @@
case 0:
throw result;
default:
- throw ((lazyComponent._status = 0),
- (result = lazyComponent._ctor),
- (result = result()),
+ lazyComponent._status = 0;
+ result = lazyComponent._ctor;
+ result = result();
result.then(
function(moduleObject) {
0 === lazyComponent._status &&
@@ -2377,13 +2092,18 @@
0 === lazyComponent._status &&
((lazyComponent._status = 2), (lazyComponent._result = error));
}
- ),
- (lazyComponent._result = result),
- result);
+ );
+ switch (lazyComponent._status) {
+ case 1:
+ return lazyComponent._result;
+ case 2:
+ throw lazyComponent._result;
+ }
+ lazyComponent._result = result;
+ throw result;
}
}
-var ReactCurrentOwner$4 = ReactSharedInternals.ReactCurrentOwner,
- emptyRefsObject = new React.Component().refs;
+var emptyRefsObject = new React.Component().refs;
function applyDerivedStateFromProps(
workInProgress,
ctor,
@@ -2424,7 +2144,7 @@
var currentTime = requestCurrentTime();
currentTime = computeExpirationForFiber(currentTime, inst);
var update = createUpdate(currentTime);
- update.tag = 1;
+ update.tag = ReplaceState;
update.payload = payload;
void 0 !== callback && null !== callback && (update.callback = callback);
flushPassiveEffects();
@@ -2436,7 +2156,7 @@
var currentTime = requestCurrentTime();
currentTime = computeExpirationForFiber(currentTime, inst);
var update = createUpdate(currentTime);
- update.tag = 2;
+ update.tag = ForceUpdate;
void 0 !== callback && null !== callback && (update.callback = callback);
flushPassiveEffects();
enqueueUpdate(inst, update);
@@ -2464,7 +2184,7 @@
unmaskedContext = emptyContextObject;
var context = ctor.contextType;
"object" === typeof context && null !== context
- ? (context = ReactCurrentOwner$4.currentDispatcher.readContext(context))
+ ? (context = readContext(context))
: ((unmaskedContext = isContextProvider(ctor)
? previousContext
: contextStackCursor.current),
@@ -2511,9 +2231,7 @@
instance.refs = emptyRefsObject;
var contextType = ctor.contextType;
"object" === typeof contextType && null !== contextType
- ? (instance.context = ReactCurrentOwner$4.currentDispatcher.readContext(
- contextType
- ))
+ ? (instance.context = readContext(contextType))
: ((contextType = isContextProvider(ctor)
? previousContext
: contextStackCursor.current),
@@ -2568,7 +2286,10 @@
element = element._owner;
var inst = void 0;
element &&
- (invariant(1 === element.tag, "Function components cannot have refs."),
+ (invariant(
+ 1 === element.tag,
+ "Function components cannot have refs. Did you mean to use React.forwardRef()?"
+ ),
(inst = element.stateNode));
invariant(
inst,
@@ -3268,6 +2989,512 @@
}
var reconcileChildFibers = ChildReconciler(!0),
mountChildFibers = ChildReconciler(!1),
+ NO_CONTEXT = {},
+ contextStackCursor$1 = { current: NO_CONTEXT },
+ contextFiberStackCursor = { current: NO_CONTEXT },
+ rootInstanceStackCursor = { current: NO_CONTEXT };
+function requiredContext(c) {
+ invariant(
+ c !== NO_CONTEXT,
+ "Expected host context to exist. This error is likely caused by a bug in React. Please file an issue."
+ );
+ return c;
+}
+function pushHostContainer(fiber, nextRootInstance) {
+ push(rootInstanceStackCursor, nextRootInstance, fiber);
+ push(contextFiberStackCursor, fiber, fiber);
+ push(contextStackCursor$1, NO_CONTEXT, fiber);
+ pop(contextStackCursor$1, fiber);
+ push(contextStackCursor$1, { isInAParentText: !1 }, fiber);
+}
+function popHostContainer(fiber) {
+ pop(contextStackCursor$1, fiber);
+ pop(contextFiberStackCursor, fiber);
+ pop(rootInstanceStackCursor, fiber);
+}
+function pushHostContext(fiber) {
+ requiredContext(rootInstanceStackCursor.current);
+ var context = requiredContext(contextStackCursor$1.current);
+ var nextContext = fiber.type;
+ nextContext =
+ "AndroidTextInput" === nextContext ||
+ "RCTMultilineTextInputView" === nextContext ||
+ "RCTSinglelineTextInputView" === nextContext ||
+ "RCTText" === nextContext ||
+ "RCTVirtualText" === nextContext;
+ nextContext =
+ context.isInAParentText !== nextContext
+ ? { isInAParentText: nextContext }
+ : context;
+ context !== nextContext &&
+ (push(contextFiberStackCursor, fiber, fiber),
+ push(contextStackCursor$1, nextContext, fiber));
+}
+function popHostContext(fiber) {
+ contextFiberStackCursor.current === fiber &&
+ (pop(contextStackCursor$1, fiber), pop(contextFiberStackCursor, fiber));
+}
+var NoEffect$1 = 0,
+ UnmountSnapshot = 2,
+ UnmountMutation = 4,
+ MountMutation = 8,
+ UnmountLayout = 16,
+ MountLayout = 32,
+ MountPassive = 64,
+ UnmountPassive = 128,
+ ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher,
+ renderExpirationTime = 0,
+ currentlyRenderingFiber$1 = null,
+ currentHook = null,
+ nextCurrentHook = null,
+ firstWorkInProgressHook = null,
+ workInProgressHook = null,
+ nextWorkInProgressHook = null,
+ remainingExpirationTime = 0,
+ componentUpdateQueue = null,
+ sideEffectTag = 0,
+ didScheduleRenderPhaseUpdate = !1,
+ renderPhaseUpdates = null,
+ numberOfReRenders = 0;
+function throwInvalidHookError() {
+ invariant(
+ !1,
+ "Hooks can only be called inside the body of a function component. (https://fb.me/react-invalid-hook-call)"
+ );
+}
+function areHookInputsEqual(nextDeps, prevDeps) {
+ if (null === prevDeps) return !1;
+ for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++)
+ if (!is(nextDeps[i], prevDeps[i])) return !1;
+ return !0;
+}
+function renderWithHooks(
+ current,
+ workInProgress,
+ Component,
+ props,
+ refOrContext,
+ nextRenderExpirationTime
+) {
+ renderExpirationTime = nextRenderExpirationTime;
+ currentlyRenderingFiber$1 = workInProgress;
+ nextCurrentHook = null !== current ? current.memoizedState : null;
+ ReactCurrentDispatcher$1.current =
+ null === nextCurrentHook ? HooksDispatcherOnMount : HooksDispatcherOnUpdate;
+ workInProgress = Component(props, refOrContext);
+ if (didScheduleRenderPhaseUpdate) {
+ do
+ (didScheduleRenderPhaseUpdate = !1),
+ (numberOfReRenders += 1),
+ (nextCurrentHook = null !== current ? current.memoizedState : null),
+ (nextWorkInProgressHook = firstWorkInProgressHook),
+ (componentUpdateQueue = workInProgressHook = currentHook = null),
+ (ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdate),
+ (workInProgress = Component(props, refOrContext));
+ while (didScheduleRenderPhaseUpdate);
+ renderPhaseUpdates = null;
+ numberOfReRenders = 0;
+ }
+ ReactCurrentDispatcher$1.current = ContextOnlyDispatcher;
+ current = currentlyRenderingFiber$1;
+ current.memoizedState = firstWorkInProgressHook;
+ current.expirationTime = remainingExpirationTime;
+ current.updateQueue = componentUpdateQueue;
+ current.effectTag |= sideEffectTag;
+ current = null !== currentHook && null !== currentHook.next;
+ renderExpirationTime = 0;
+ nextWorkInProgressHook = workInProgressHook = firstWorkInProgressHook = nextCurrentHook = currentHook = currentlyRenderingFiber$1 = null;
+ remainingExpirationTime = 0;
+ componentUpdateQueue = null;
+ sideEffectTag = 0;
+ invariant(
+ !current,
+ "Rendered fewer hooks than expected. This may be caused by an accidental early return statement."
+ );
+ return workInProgress;
+}
+function resetHooks() {
+ ReactCurrentDispatcher$1.current = ContextOnlyDispatcher;
+ renderExpirationTime = 0;
+ nextWorkInProgressHook = workInProgressHook = firstWorkInProgressHook = nextCurrentHook = currentHook = currentlyRenderingFiber$1 = null;
+ remainingExpirationTime = 0;
+ componentUpdateQueue = null;
+ sideEffectTag = 0;
+ didScheduleRenderPhaseUpdate = !1;
+ renderPhaseUpdates = null;
+ numberOfReRenders = 0;
+}
+function mountWorkInProgressHook() {
+ var hook = {
+ memoizedState: null,
+ baseState: null,
+ queue: null,
+ baseUpdate: null,
+ next: null
+ };
+ null === workInProgressHook
+ ? (firstWorkInProgressHook = workInProgressHook = hook)
+ : (workInProgressHook = workInProgressHook.next = hook);
+ return workInProgressHook;
+}
+function updateWorkInProgressHook() {
+ if (null !== nextWorkInProgressHook)
+ (workInProgressHook = nextWorkInProgressHook),
+ (nextWorkInProgressHook = workInProgressHook.next),
+ (currentHook = nextCurrentHook),
+ (nextCurrentHook = null !== currentHook ? currentHook.next : null);
+ else {
+ invariant(
+ null !== nextCurrentHook,
+ "Rendered more hooks than during the previous render."
+ );
+ currentHook = nextCurrentHook;
+ var newHook = {
+ memoizedState: currentHook.memoizedState,
+ baseState: currentHook.baseState,
+ queue: currentHook.queue,
+ baseUpdate: currentHook.baseUpdate,
+ next: null
+ };
+ workInProgressHook =
+ null === workInProgressHook
+ ? (firstWorkInProgressHook = newHook)
+ : (workInProgressHook.next = newHook);
+ nextCurrentHook = currentHook.next;
+ }
+ return workInProgressHook;
+}
+function basicStateReducer(state, action) {
+ return "function" === typeof action ? action(state) : action;
+}
+function updateReducer(reducer) {
+ var hook = updateWorkInProgressHook(),
+ queue = hook.queue;
+ invariant(
+ null !== queue,
+ "Should have a queue. This is likely a bug in React. Please file an issue."
+ );
+ if (0 < numberOfReRenders) {
+ var _dispatch = queue.dispatch;
+ if (null !== renderPhaseUpdates) {
+ var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+ if (void 0 !== firstRenderPhaseUpdate) {
+ renderPhaseUpdates.delete(queue);
+ var newState = hook.memoizedState;
+ do
+ (newState = reducer(newState, firstRenderPhaseUpdate.action)),
+ (firstRenderPhaseUpdate = firstRenderPhaseUpdate.next);
+ while (null !== firstRenderPhaseUpdate);
+ 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];
+ }
+ }
+ return [hook.memoizedState, _dispatch];
+ }
+ _dispatch = queue.last;
+ var baseUpdate = hook.baseUpdate;
+ newState = hook.baseState;
+ null !== baseUpdate
+ ? (null !== _dispatch && (_dispatch.next = null),
+ (_dispatch = baseUpdate.next))
+ : (_dispatch = null !== _dispatch ? _dispatch.next : null);
+ if (null !== _dispatch) {
+ var newBaseUpdate = (firstRenderPhaseUpdate = null),
+ _update = _dispatch,
+ didSkip = !1;
+ do {
+ var updateExpirationTime = _update.expirationTime;
+ updateExpirationTime < renderExpirationTime
+ ? (didSkip ||
+ ((didSkip = !0),
+ (newBaseUpdate = baseUpdate),
+ (firstRenderPhaseUpdate = newState)),
+ updateExpirationTime > remainingExpirationTime &&
+ (remainingExpirationTime = updateExpirationTime))
+ : (newState =
+ _update.eagerReducer === reducer
+ ? _update.eagerState
+ : reducer(newState, _update.action));
+ baseUpdate = _update;
+ _update = _update.next;
+ } while (null !== _update && _update !== _dispatch);
+ didSkip ||
+ ((newBaseUpdate = baseUpdate), (firstRenderPhaseUpdate = newState));
+ is(newState, hook.memoizedState) || (didReceiveUpdate = !0);
+ hook.memoizedState = newState;
+ hook.baseUpdate = newBaseUpdate;
+ hook.baseState = firstRenderPhaseUpdate;
+ queue.eagerReducer = reducer;
+ queue.eagerState = newState;
+ }
+ return [hook.memoizedState, queue.dispatch];
+}
+function pushEffect(tag, create, destroy, deps) {
+ tag = { tag: tag, create: create, destroy: destroy, deps: deps, next: null };
+ null === componentUpdateQueue
+ ? ((componentUpdateQueue = { lastEffect: null }),
+ (componentUpdateQueue.lastEffect = tag.next = tag))
+ : ((create = componentUpdateQueue.lastEffect),
+ null === create
+ ? (componentUpdateQueue.lastEffect = tag.next = tag)
+ : ((destroy = create.next),
+ (create.next = tag),
+ (tag.next = destroy),
+ (componentUpdateQueue.lastEffect = tag)));
+ return tag;
+}
+function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) {
+ var hook = mountWorkInProgressHook();
+ sideEffectTag |= fiberEffectTag;
+ hook.memoizedState = pushEffect(
+ hookEffectTag,
+ create,
+ void 0,
+ void 0 === deps ? null : deps
+ );
+}
+function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) {
+ var hook = updateWorkInProgressHook();
+ deps = void 0 === deps ? null : deps;
+ var destroy = void 0;
+ if (null !== currentHook) {
+ var prevEffect = currentHook.memoizedState;
+ destroy = prevEffect.destroy;
+ if (null !== deps && areHookInputsEqual(deps, prevEffect.deps)) {
+ pushEffect(NoEffect$1, create, destroy, deps);
+ return;
+ }
+ }
+ sideEffectTag |= fiberEffectTag;
+ hook.memoizedState = pushEffect(hookEffectTag, create, destroy, deps);
+}
+function imperativeHandleEffect(create, ref) {
+ if ("function" === typeof ref)
+ return (
+ (create = create()),
+ ref(create),
+ function() {
+ ref(null);
+ }
+ );
+ if (null !== ref && void 0 !== ref)
+ return (
+ (create = create()),
+ (ref.current = create),
+ function() {
+ ref.current = null;
+ }
+ );
+}
+function mountDebugValue() {}
+function dispatchAction(fiber, queue, action) {
+ invariant(
+ 25 > numberOfReRenders,
+ "Too many re-renders. React limits the number of renders to prevent an infinite loop."
+ );
+ var alternate = fiber.alternate;
+ if (
+ fiber === currentlyRenderingFiber$1 ||
+ (null !== alternate && alternate === currentlyRenderingFiber$1)
+ )
+ if (
+ ((didScheduleRenderPhaseUpdate = !0),
+ (fiber = {
+ expirationTime: renderExpirationTime,
+ action: action,
+ eagerReducer: null,
+ eagerState: null,
+ next: null
+ }),
+ null === renderPhaseUpdates && (renderPhaseUpdates = new Map()),
+ (action = renderPhaseUpdates.get(queue)),
+ void 0 === action)
+ )
+ renderPhaseUpdates.set(queue, fiber);
+ else {
+ for (queue = action; null !== queue.next; ) queue = queue.next;
+ queue.next = fiber;
+ }
+ else {
+ flushPassiveEffects();
+ var currentTime = requestCurrentTime();
+ currentTime = computeExpirationForFiber(currentTime, fiber);
+ var _update2 = {
+ expirationTime: currentTime,
+ action: action,
+ eagerReducer: null,
+ eagerState: null,
+ next: null
+ },
+ _last = queue.last;
+ if (null === _last) _update2.next = _update2;
+ else {
+ var first = _last.next;
+ null !== first && (_update2.next = first);
+ _last.next = _update2;
+ }
+ queue.last = _update2;
+ if (
+ 0 === fiber.expirationTime &&
+ (null === alternate || 0 === alternate.expirationTime) &&
+ ((alternate = queue.eagerReducer), null !== alternate)
+ )
+ try {
+ var currentState = queue.eagerState,
+ _eagerState = alternate(currentState, action);
+ _update2.eagerReducer = alternate;
+ _update2.eagerState = _eagerState;
+ if (is(_eagerState, currentState)) return;
+ } catch (error) {
+ } finally {
+ }
+ scheduleWork(fiber, currentTime);
+ }
+}
+var ContextOnlyDispatcher = {
+ readContext: readContext,
+ useCallback: throwInvalidHookError,
+ useContext: throwInvalidHookError,
+ useEffect: throwInvalidHookError,
+ useImperativeHandle: throwInvalidHookError,
+ useLayoutEffect: throwInvalidHookError,
+ useMemo: throwInvalidHookError,
+ useReducer: throwInvalidHookError,
+ useRef: throwInvalidHookError,
+ useState: throwInvalidHookError,
+ useDebugValue: throwInvalidHookError
+ },
+ HooksDispatcherOnMount = {
+ readContext: readContext,
+ useCallback: function(callback, deps) {
+ mountWorkInProgressHook().memoizedState = [
+ callback,
+ void 0 === deps ? null : deps
+ ];
+ return callback;
+ },
+ useContext: readContext,
+ useEffect: function(create, deps) {
+ return mountEffectImpl(516, UnmountPassive | MountPassive, create, deps);
+ },
+ useImperativeHandle: function(ref, create, deps) {
+ deps = null !== deps && void 0 !== deps ? deps.concat([ref]) : null;
+ return mountEffectImpl(
+ 4,
+ UnmountMutation | MountLayout,
+ imperativeHandleEffect.bind(null, create, ref),
+ deps
+ );
+ },
+ useLayoutEffect: function(create, deps) {
+ return mountEffectImpl(4, UnmountMutation | MountLayout, create, deps);
+ },
+ useMemo: function(nextCreate, deps) {
+ var hook = mountWorkInProgressHook();
+ deps = void 0 === deps ? null : deps;
+ nextCreate = nextCreate();
+ hook.memoizedState = [nextCreate, deps];
+ return nextCreate;
+ },
+ useReducer: function(reducer, initialArg, init) {
+ var hook = mountWorkInProgressHook();
+ initialArg = void 0 !== init ? init(initialArg) : initialArg;
+ hook.memoizedState = hook.baseState = initialArg;
+ reducer = hook.queue = {
+ last: null,
+ dispatch: null,
+ eagerReducer: reducer,
+ eagerState: initialArg
+ };
+ reducer = reducer.dispatch = dispatchAction.bind(
+ null,
+ currentlyRenderingFiber$1,
+ reducer
+ );
+ return [hook.memoizedState, reducer];
+ },
+ useRef: function(initialValue) {
+ var hook = mountWorkInProgressHook();
+ initialValue = { current: initialValue };
+ return (hook.memoizedState = initialValue);
+ },
+ useState: function(initialState) {
+ var hook = mountWorkInProgressHook();
+ "function" === typeof initialState && (initialState = initialState());
+ hook.memoizedState = hook.baseState = initialState;
+ initialState = hook.queue = {
+ last: null,
+ dispatch: null,
+ eagerReducer: basicStateReducer,
+ eagerState: initialState
+ };
+ initialState = initialState.dispatch = dispatchAction.bind(
+ null,
+ currentlyRenderingFiber$1,
+ initialState
+ );
+ return [hook.memoizedState, initialState];
+ },
+ useDebugValue: mountDebugValue
+ },
+ HooksDispatcherOnUpdate = {
+ readContext: readContext,
+ useCallback: function(callback, deps) {
+ var hook = updateWorkInProgressHook();
+ deps = void 0 === deps ? null : deps;
+ var prevState = hook.memoizedState;
+ if (
+ null !== prevState &&
+ null !== deps &&
+ areHookInputsEqual(deps, prevState[1])
+ )
+ return prevState[0];
+ hook.memoizedState = [callback, deps];
+ return callback;
+ },
+ useContext: readContext,
+ useEffect: function(create, deps) {
+ return updateEffectImpl(516, UnmountPassive | MountPassive, create, deps);
+ },
+ useImperativeHandle: function(ref, create, deps) {
+ deps = null !== deps && void 0 !== deps ? deps.concat([ref]) : null;
+ return updateEffectImpl(
+ 4,
+ UnmountMutation | MountLayout,
+ imperativeHandleEffect.bind(null, create, ref),
+ deps
+ );
+ },
+ useLayoutEffect: function(create, deps) {
+ return updateEffectImpl(4, UnmountMutation | MountLayout, create, deps);
+ },
+ useMemo: function(nextCreate, deps) {
+ var hook = updateWorkInProgressHook();
+ deps = void 0 === deps ? null : deps;
+ var prevState = hook.memoizedState;
+ if (
+ null !== prevState &&
+ null !== deps &&
+ areHookInputsEqual(deps, prevState[1])
+ )
+ return prevState[0];
+ nextCreate = nextCreate();
+ hook.memoizedState = [nextCreate, deps];
+ return nextCreate;
+ },
+ useReducer: updateReducer,
+ useRef: function() {
+ return updateWorkInProgressHook().memoizedState;
+ },
+ useState: function(initialState) {
+ return updateReducer(basicStateReducer, initialState);
+ },
+ useDebugValue: mountDebugValue
+ },
hydrationParentFiber = null,
nextHydratableInstance = null,
isHydrating = !1;
@@ -3283,6 +3510,8 @@
(nextInstance = shim$1(nextInstance, fiber.pendingProps)),
null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1
);
+ case 13:
+ return !1;
default:
return !1;
}
@@ -3320,7 +3549,8 @@
(hydrationParentFiber = fiber$jscomp$0);
}
}
-var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner;
+var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner,
+ didReceiveUpdate = !1;
function reconcileChildren(
current$$1,
workInProgress,
@@ -3352,7 +3582,26 @@
Component = Component.render;
var ref = workInProgress.ref;
prepareToReadContext(workInProgress, renderExpirationTime);
- nextProps = Component(nextProps, ref);
+ nextProps = renderWithHooks(
+ current$$1,
+ workInProgress,
+ Component,
+ nextProps,
+ ref,
+ renderExpirationTime
+ );
+ if (null !== current$$1 && !didReceiveUpdate)
+ return (
+ (workInProgress.updateQueue = current$$1.updateQueue),
+ (workInProgress.effectTag &= -517),
+ current$$1.expirationTime <= renderExpirationTime &&
+ (current$$1.expirationTime = 0),
+ bailoutOnAlreadyFinishedWork(
+ current$$1,
+ workInProgress,
+ renderExpirationTime
+ )
+ );
workInProgress.effectTag |= 1;
reconcileChildren(
current$$1,
@@ -3432,9 +3681,9 @@
renderExpirationTime
) {
return null !== current$$1 &&
- updateExpirationTime < renderExpirationTime &&
shallowEqual(current$$1.memoizedProps, nextProps) &&
- current$$1.ref === workInProgress.ref
+ current$$1.ref === workInProgress.ref &&
+ ((didReceiveUpdate = !1), updateExpirationTime < renderExpirationTime)
? bailoutOnAlreadyFinishedWork(
current$$1,
workInProgress,
@@ -3468,7 +3717,26 @@
: contextStackCursor.current;
unmaskedContext = getMaskedContext(workInProgress, unmaskedContext);
prepareToReadContext(workInProgress, renderExpirationTime);
- Component = Component(nextProps, unmaskedContext);
+ Component = renderWithHooks(
+ current$$1,
+ workInProgress,
+ Component,
+ nextProps,
+ unmaskedContext,
+ renderExpirationTime
+ );
+ if (null !== current$$1 && !didReceiveUpdate)
+ return (
+ (workInProgress.updateQueue = current$$1.updateQueue),
+ (workInProgress.effectTag &= -517),
+ current$$1.expirationTime <= renderExpirationTime &&
+ (current$$1.expirationTime = 0),
+ bailoutOnAlreadyFinishedWork(
+ current$$1,
+ workInProgress,
+ renderExpirationTime
+ )
+ );
workInProgress.effectTag |= 1;
reconcileChildren(
current$$1,
@@ -3515,9 +3783,7 @@
var oldContext = instance.context,
contextType = Component.contextType;
"object" === typeof contextType && null !== contextType
- ? (contextType = ReactCurrentOwner$4.currentDispatcher.readContext(
- contextType
- ))
+ ? (contextType = readContext(contextType))
: ((contextType = isContextProvider(Component)
? previousContext
: contextStackCursor.current),
@@ -3602,9 +3868,7 @@
(oldContext = instance.context),
(contextType = Component.contextType),
"object" === typeof contextType && null !== contextType
- ? (contextType = ReactCurrentOwner$4.currentDispatcher.readContext(
- contextType
- ))
+ ? (contextType = readContext(contextType))
: ((contextType = isContextProvider(Component)
? previousContext
: contextStackCursor.current),
@@ -3785,33 +4049,35 @@
(nextState = { timedOutAt: null !== nextState ? nextState.timedOutAt : 0 }),
(nextDidTimeout = !0),
(workInProgress.effectTag &= -65);
- null === current$$1
- ? nextDidTimeout
- ? ((nextDidTimeout = nextProps.fallback),
- (nextProps = createFiberFromFragment(null, mode, 0, null)),
+ if (null === current$$1)
+ if (nextDidTimeout) {
+ var nextFallbackChildren = nextProps.fallback;
+ current$$1 = createFiberFromFragment(null, mode, 0, null);
0 === (workInProgress.mode & 1) &&
- (nextProps.child =
+ (current$$1.child =
null !== workInProgress.memoizedState
? workInProgress.child.child
- : workInProgress.child),
- (mode = createFiberFromFragment(
- nextDidTimeout,
+ : workInProgress.child);
+ mode = createFiberFromFragment(
+ nextFallbackChildren,
mode,
renderExpirationTime,
null
- )),
- (nextProps.sibling = mode),
- (renderExpirationTime = nextProps),
- (renderExpirationTime.return = mode.return = workInProgress))
- : (renderExpirationTime = mode = mountChildFibers(
+ );
+ current$$1.sibling = mode;
+ renderExpirationTime = current$$1;
+ renderExpirationTime.return = mode.return = workInProgress;
+ } else
+ renderExpirationTime = mode = mountChildFibers(
workInProgress,
null,
nextProps.children,
renderExpirationTime
- ))
- : null !== current$$1.memoizedState
+ );
+ else
+ null !== current$$1.memoizedState
? ((mode = current$$1.child),
- (current$$1 = mode.sibling),
+ (nextFallbackChildren = mode.sibling),
nextDidTimeout
? ((renderExpirationTime = nextProps.fallback),
(nextProps = createWorkInProgress(mode, mode.pendingProps, 0)),
@@ -3823,9 +4089,9 @@
nextDidTimeout !== mode.child &&
(nextProps.child = nextDidTimeout)),
(mode = nextProps.sibling = createWorkInProgress(
- current$$1,
+ nextFallbackChildren,
renderExpirationTime,
- current$$1.expirationTime
+ nextFallbackChildren.expirationTime
)),
(renderExpirationTime = nextProps),
(nextProps.childExpirationTime = 0),
@@ -3836,11 +4102,11 @@
nextProps.children,
renderExpirationTime
)))
- : ((current$$1 = current$$1.child),
+ : ((nextFallbackChildren = current$$1.child),
nextDidTimeout
? ((nextDidTimeout = nextProps.fallback),
(nextProps = createFiberFromFragment(null, mode, 0, null)),
- (nextProps.child = current$$1),
+ (nextProps.child = nextFallbackChildren),
0 === (workInProgress.mode & 1) &&
(nextProps.child =
null !== workInProgress.memoizedState
@@ -3858,10 +4124,11 @@
(renderExpirationTime.return = mode.return = workInProgress))
: (mode = renderExpirationTime = reconcileChildFibers(
workInProgress,
- current$$1,
+ nextFallbackChildren,
nextProps.children,
renderExpirationTime
- )));
+ ))),
+ (workInProgress.stateNode = current$$1.stateNode);
workInProgress.memoizedState = nextState;
workInProgress.child = renderExpirationTime;
return mode;
@@ -3872,7 +4139,7 @@
renderExpirationTime
) {
null !== current$$1 &&
- (workInProgress.firstContextDependency = current$$1.firstContextDependency);
+ (workInProgress.contextDependencies = current$$1.contextDependencies);
if (workInProgress.childExpirationTime < renderExpirationTime) return null;
invariant(
null === current$$1 || workInProgress.child === current$$1.child,
@@ -3904,12 +4171,15 @@
}
function beginWork(current$$1, workInProgress, renderExpirationTime) {
var updateExpirationTime = workInProgress.expirationTime;
+ if (null !== current$$1)
if (
- null !== current$$1 &&
- current$$1.memoizedProps === workInProgress.pendingProps &&
- !didPerformWorkStackCursor.current &&
- updateExpirationTime < renderExpirationTime
- ) {
+ current$$1.memoizedProps !== workInProgress.pendingProps ||
+ didPerformWorkStackCursor.current
+ )
+ didReceiveUpdate = !0;
+ else {
+ if (updateExpirationTime < renderExpirationTime) {
+ didReceiveUpdate = !1;
switch (workInProgress.tag) {
case 3:
pushHostRootContext(workInProgress);
@@ -3956,6 +4226,8 @@
renderExpirationTime
);
}
+ }
+ else didReceiveUpdate = !1;
workInProgress.expirationTime = 0;
switch (workInProgress.tag) {
case 2:
@@ -3970,7 +4242,14 @@
contextStackCursor.current
);
prepareToReadContext(workInProgress, renderExpirationTime);
- context = updateExpirationTime(current$$1, context);
+ context = renderWithHooks(
+ null,
+ workInProgress,
+ updateExpirationTime,
+ current$$1,
+ context,
+ renderExpirationTime
+ );
workInProgress.effectTag |= 1;
if (
"object" === typeof context &&
@@ -3979,6 +4258,7 @@
void 0 === context.$$typeof
) {
workInProgress.tag = 1;
+ resetHooks();
if (isContextProvider(updateExpirationTime)) {
var hasContext = !0;
pushContextProvider(workInProgress);
@@ -4250,13 +4530,9 @@
pushProvider(workInProgress, hasContext);
if (null !== getDerivedStateFromProps) {
var oldValue = getDerivedStateFromProps.value;
- hasContext =
- (oldValue === hasContext &&
- (0 !== oldValue || 1 / oldValue === 1 / hasContext)) ||
- (oldValue !== oldValue && hasContext !== hasContext)
+ hasContext = is(oldValue, hasContext)
? 0
- : ("function" ===
- typeof updateExpirationTime._calculateChangedBits
+ : ("function" === typeof updateExpirationTime._calculateChangedBits
? updateExpirationTime._calculateChangedBits(
oldValue,
hasContext
@@ -4276,83 +4552,79 @@
}
} else
for (
- getDerivedStateFromProps = workInProgress.child,
- null !== getDerivedStateFromProps &&
- (getDerivedStateFromProps.return = workInProgress);
- null !== getDerivedStateFromProps;
+ oldValue = workInProgress.child,
+ null !== oldValue && (oldValue.return = workInProgress);
+ null !== oldValue;
) {
- oldValue = getDerivedStateFromProps.firstContextDependency;
- if (null !== oldValue) {
- do {
+ var list = oldValue.contextDependencies;
+ if (null !== list) {
+ getDerivedStateFromProps = oldValue.child;
+ for (var dependency = list.first; null !== dependency; ) {
if (
- oldValue.context === updateExpirationTime &&
- 0 !== (oldValue.observedBits & hasContext)
- ) {
- if (1 === getDerivedStateFromProps.tag) {
- var nextFiber = createUpdate(renderExpirationTime);
- nextFiber.tag = 2;
- enqueueUpdate(getDerivedStateFromProps, nextFiber);
- }
- getDerivedStateFromProps.expirationTime <
- renderExpirationTime &&
- (getDerivedStateFromProps.expirationTime = renderExpirationTime);
- nextFiber = getDerivedStateFromProps.alternate;
- null !== nextFiber &&
- nextFiber.expirationTime < renderExpirationTime &&
- (nextFiber.expirationTime = renderExpirationTime);
- for (
- var node = getDerivedStateFromProps.return;
- null !== node;
-
+ dependency.context === updateExpirationTime &&
+ 0 !== (dependency.observedBits & hasContext)
) {
- nextFiber = node.alternate;
- if (node.childExpirationTime < renderExpirationTime)
- (node.childExpirationTime = renderExpirationTime),
- null !== nextFiber &&
- nextFiber.childExpirationTime <
- renderExpirationTime &&
- (nextFiber.childExpirationTime = renderExpirationTime);
+ 1 === oldValue.tag &&
+ ((dependency = createUpdate(renderExpirationTime)),
+ (dependency.tag = ForceUpdate),
+ enqueueUpdate(oldValue, dependency));
+ oldValue.expirationTime < renderExpirationTime &&
+ (oldValue.expirationTime = renderExpirationTime);
+ dependency = oldValue.alternate;
+ null !== dependency &&
+ dependency.expirationTime < renderExpirationTime &&
+ (dependency.expirationTime = renderExpirationTime);
+ dependency = renderExpirationTime;
+ for (var node = oldValue.return; null !== node; ) {
+ var alternate = node.alternate;
+ if (node.childExpirationTime < dependency)
+ (node.childExpirationTime = dependency),
+ null !== alternate &&
+ alternate.childExpirationTime < dependency &&
+ (alternate.childExpirationTime = dependency);
else if (
- null !== nextFiber &&
- nextFiber.childExpirationTime < renderExpirationTime
+ null !== alternate &&
+ alternate.childExpirationTime < dependency
)
- nextFiber.childExpirationTime = renderExpirationTime;
+ alternate.childExpirationTime = dependency;
else break;
node = node.return;
}
+ list.expirationTime < renderExpirationTime &&
+ (list.expirationTime = renderExpirationTime);
+ break;
+ }
+ dependency = dependency.next;
}
- nextFiber = getDerivedStateFromProps.child;
- oldValue = oldValue.next;
- } while (null !== oldValue);
} else
- nextFiber =
- 10 === getDerivedStateFromProps.tag
- ? getDerivedStateFromProps.type === workInProgress.type
+ getDerivedStateFromProps =
+ 10 === oldValue.tag
+ ? oldValue.type === workInProgress.type
? null
- : getDerivedStateFromProps.child
- : getDerivedStateFromProps.child;
- if (null !== nextFiber)
- nextFiber.return = getDerivedStateFromProps;
+ : oldValue.child
+ : oldValue.child;
+ if (null !== getDerivedStateFromProps)
+ getDerivedStateFromProps.return = oldValue;
else
for (
- nextFiber = getDerivedStateFromProps;
- null !== nextFiber;
+ getDerivedStateFromProps = oldValue;
+ null !== getDerivedStateFromProps;
) {
- if (nextFiber === workInProgress) {
- nextFiber = null;
+ if (getDerivedStateFromProps === workInProgress) {
+ getDerivedStateFromProps = null;
break;
}
- getDerivedStateFromProps = nextFiber.sibling;
- if (null !== getDerivedStateFromProps) {
- getDerivedStateFromProps.return = nextFiber.return;
- nextFiber = getDerivedStateFromProps;
+ oldValue = getDerivedStateFromProps.sibling;
+ if (null !== oldValue) {
+ oldValue.return = getDerivedStateFromProps.return;
+ getDerivedStateFromProps = oldValue;
break;
}
- nextFiber = nextFiber.return;
+ getDerivedStateFromProps = getDerivedStateFromProps.return;
}
- getDerivedStateFromProps = nextFiber;
+ oldValue = getDerivedStateFromProps;
}
}
reconcileChildren(
@@ -4445,13 +4717,297 @@
renderExpirationTime
)
);
- default:
+ }
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,
+ lastContextDependency = null,
+ lastContextWithAllBitsObserved = null;
+function pushProvider(providerFiber, nextValue) {
+ var context = providerFiber.type._context;
+ push(valueCursor, context._currentValue2, providerFiber);
+ context._currentValue2 = nextValue;
+}
+function popProvider(providerFiber) {
+ var currentValue = valueCursor.current;
+ pop(valueCursor, providerFiber);
+ providerFiber.type._context._currentValue2 = currentValue;
+}
+function prepareToReadContext(workInProgress, renderExpirationTime) {
+ currentlyRenderingFiber = workInProgress;
+ lastContextWithAllBitsObserved = lastContextDependency = null;
+ var currentDependencies = workInProgress.contextDependencies;
+ null !== currentDependencies &&
+ currentDependencies.expirationTime >= renderExpirationTime &&
+ (didReceiveUpdate = !0);
+ workInProgress.contextDependencies = null;
+}
+function readContext(context, observedBits) {
+ if (
+ lastContextWithAllBitsObserved !== context &&
+ !1 !== observedBits &&
+ 0 !== observedBits
+ ) {
+ if ("number" !== typeof observedBits || 1073741823 === observedBits)
+ (lastContextWithAllBitsObserved = context), (observedBits = 1073741823);
+ observedBits = { context: context, observedBits: observedBits, next: null };
+ null === lastContextDependency
+ ? (invariant(
+ null !== currentlyRenderingFiber,
+ "Context can only be read while React is rendering. In classes, you can read it in the render method or getDerivedStateFromProps. In function components, you can read it directly in the function body, but not inside Hooks like useReducer() or useMemo()."
+ ),
+ (lastContextDependency = observedBits),
+ (currentlyRenderingFiber.contextDependencies = {
+ first: observedBits,
+ expirationTime: 0
+ }))
+ : (lastContextDependency = lastContextDependency.next = observedBits);
+ }
+ return context._currentValue2;
+}
+var UpdateState = 0,
+ ReplaceState = 1,
+ ForceUpdate = 2,
+ CaptureUpdate = 3,
+ hasForceUpdate = !1;
+function createUpdateQueue(baseState) {
+ return {
+ baseState: baseState,
+ firstUpdate: null,
+ lastUpdate: null,
+ firstCapturedUpdate: null,
+ lastCapturedUpdate: null,
+ firstEffect: null,
+ lastEffect: null,
+ firstCapturedEffect: null,
+ lastCapturedEffect: null
+ };
+}
+function cloneUpdateQueue(currentQueue) {
+ return {
+ baseState: currentQueue.baseState,
+ firstUpdate: currentQueue.firstUpdate,
+ lastUpdate: currentQueue.lastUpdate,
+ firstCapturedUpdate: null,
+ lastCapturedUpdate: null,
+ firstEffect: null,
+ lastEffect: null,
+ firstCapturedEffect: null,
+ lastCapturedEffect: null
+ };
+}
+function createUpdate(expirationTime) {
+ return {
+ expirationTime: expirationTime,
+ tag: UpdateState,
+ payload: null,
+ callback: null,
+ next: null,
+ nextEffect: null
+ };
+}
+function appendUpdateToQueue(queue, update) {
+ null === queue.lastUpdate
+ ? (queue.firstUpdate = queue.lastUpdate = update)
+ : ((queue.lastUpdate.next = update), (queue.lastUpdate = update));
+}
+function enqueueUpdate(fiber, update) {
+ var alternate = fiber.alternate;
+ if (null === alternate) {
+ var queue1 = fiber.updateQueue;
+ var queue2 = null;
+ null === queue1 &&
+ (queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState));
+ } else
+ (queue1 = fiber.updateQueue),
+ (queue2 = alternate.updateQueue),
+ null === queue1
+ ? null === queue2
+ ? ((queue1 = fiber.updateQueue = createUpdateQueue(
+ fiber.memoizedState
+ )),
+ (queue2 = alternate.updateQueue = createUpdateQueue(
+ alternate.memoizedState
+ )))
+ : (queue1 = fiber.updateQueue = cloneUpdateQueue(queue2))
+ : null === queue2 &&
+ (queue2 = alternate.updateQueue = cloneUpdateQueue(queue1));
+ null === queue2 || queue1 === queue2
+ ? appendUpdateToQueue(queue1, update)
+ : null === queue1.lastUpdate || null === queue2.lastUpdate
+ ? (appendUpdateToQueue(queue1, update),
+ appendUpdateToQueue(queue2, update))
+ : (appendUpdateToQueue(queue1, update), (queue2.lastUpdate = update));
+}
+function enqueueCapturedUpdate(workInProgress, update) {
+ var workInProgressQueue = workInProgress.updateQueue;
+ workInProgressQueue =
+ null === workInProgressQueue
+ ? (workInProgress.updateQueue = createUpdateQueue(
+ workInProgress.memoizedState
+ ))
+ : ensureWorkInProgressQueueIsAClone(workInProgress, workInProgressQueue);
+ null === workInProgressQueue.lastCapturedUpdate
+ ? (workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update)
+ : ((workInProgressQueue.lastCapturedUpdate.next = update),
+ (workInProgressQueue.lastCapturedUpdate = update));
+}
+function ensureWorkInProgressQueueIsAClone(workInProgress, queue) {
+ var current = workInProgress.alternate;
+ null !== current &&
+ queue === current.updateQueue &&
+ (queue = workInProgress.updateQueue = cloneUpdateQueue(queue));
+ return queue;
+}
+function getStateFromUpdate(
+ workInProgress,
+ queue,
+ update,
+ prevState,
+ nextProps,
+ instance
+) {
+ switch (update.tag) {
+ case ReplaceState:
+ return (
+ (workInProgress = update.payload),
+ "function" === typeof workInProgress
+ ? workInProgress.call(instance, prevState, nextProps)
+ : workInProgress
+ );
+ case CaptureUpdate:
+ workInProgress.effectTag = (workInProgress.effectTag & -2049) | 64;
+ case UpdateState:
+ workInProgress = update.payload;
+ nextProps =
+ "function" === typeof workInProgress
+ ? workInProgress.call(instance, prevState, nextProps)
+ : workInProgress;
+ if (null === nextProps || void 0 === nextProps) break;
+ return Object.assign({}, prevState, nextProps);
+ case ForceUpdate:
+ hasForceUpdate = !0;
+ }
+ return prevState;
+}
+function processUpdateQueue(
+ workInProgress,
+ queue,
+ props,
+ instance,
+ renderExpirationTime
+) {
+ hasForceUpdate = !1;
+ queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue);
+ for (
+ var newBaseState = queue.baseState,
+ newFirstUpdate = null,
+ newExpirationTime = 0,
+ update = queue.firstUpdate,
+ resultState = newBaseState;
+ null !== update;
+
+ ) {
+ var updateExpirationTime = update.expirationTime;
+ updateExpirationTime < renderExpirationTime
+ ? (null === newFirstUpdate &&
+ ((newFirstUpdate = update), (newBaseState = resultState)),
+ newExpirationTime < updateExpirationTime &&
+ (newExpirationTime = updateExpirationTime))
+ : ((resultState = getStateFromUpdate(
+ workInProgress,
+ queue,
+ update,
+ resultState,
+ props,
+ instance
+ )),
+ null !== update.callback &&
+ ((workInProgress.effectTag |= 32),
+ (update.nextEffect = null),
+ null === queue.lastEffect
+ ? (queue.firstEffect = queue.lastEffect = update)
+ : ((queue.lastEffect.nextEffect = update),
+ (queue.lastEffect = update))));
+ update = update.next;
+ }
+ updateExpirationTime = null;
+ for (update = queue.firstCapturedUpdate; null !== update; ) {
+ var _updateExpirationTime = update.expirationTime;
+ _updateExpirationTime < renderExpirationTime
+ ? (null === updateExpirationTime &&
+ ((updateExpirationTime = update),
+ null === newFirstUpdate && (newBaseState = resultState)),
+ newExpirationTime < _updateExpirationTime &&
+ (newExpirationTime = _updateExpirationTime))
+ : ((resultState = getStateFromUpdate(
+ workInProgress,
+ queue,
+ update,
+ resultState,
+ props,
+ instance
+ )),
+ null !== update.callback &&
+ ((workInProgress.effectTag |= 32),
+ (update.nextEffect = null),
+ null === queue.lastCapturedEffect
+ ? (queue.firstCapturedEffect = queue.lastCapturedEffect = update)
+ : ((queue.lastCapturedEffect.nextEffect = update),
+ (queue.lastCapturedEffect = update))));
+ update = update.next;
+ }
+ null === newFirstUpdate && (queue.lastUpdate = null);
+ null === updateExpirationTime
+ ? (queue.lastCapturedUpdate = null)
+ : (workInProgress.effectTag |= 32);
+ null === newFirstUpdate &&
+ null === updateExpirationTime &&
+ (newBaseState = resultState);
+ queue.baseState = newBaseState;
+ queue.firstUpdate = newFirstUpdate;
+ queue.firstCapturedUpdate = updateExpirationTime;
+ workInProgress.expirationTime = newExpirationTime;
+ workInProgress.memoizedState = resultState;
+}
+function commitUpdateQueue(finishedWork, finishedQueue, instance) {
+ null !== finishedQueue.firstCapturedUpdate &&
+ (null !== finishedQueue.lastUpdate &&
+ ((finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate),
+ (finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate)),
+ (finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null));
+ commitUpdateEffects(finishedQueue.firstEffect, instance);
+ finishedQueue.firstEffect = finishedQueue.lastEffect = null;
+ commitUpdateEffects(finishedQueue.firstCapturedEffect, instance);
+ finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null;
+}
+function commitUpdateEffects(effect, instance) {
+ for (; null !== effect; ) {
+ var _callback3 = effect.callback;
+ if (null !== _callback3) {
+ effect.callback = null;
+ var context = instance;
+ invariant(
+ "function" === typeof _callback3,
+ "Invalid argument passed as callback. Expected a function. Instead received: %s",
+ _callback3
+ );
+ _callback3.call(context);
+ }
+ effect = effect.nextEffect;
}
}
+function createCapturedValue(value, source) {
+ return {
+ value: value,
+ source: source,
+ stack: getStackByFiberInDevAndProd(source)
+ };
+}
var appendAllChildren = void 0,
updateHostContainer = void 0,
updateHostComponent$1 = void 0,
@@ -4695,12 +5251,30 @@
}
else ref.current = null;
}
+function commitHookEffectList(unmountTag, mountTag, finishedWork) {
+ finishedWork = finishedWork.updateQueue;
+ finishedWork = null !== finishedWork ? finishedWork.lastEffect : null;
+ if (null !== finishedWork) {
+ var effect = (finishedWork = finishedWork.next);
+ do {
+ if ((effect.tag & unmountTag) !== NoEffect$1) {
+ var destroy = effect.destroy;
+ effect.destroy = void 0;
+ void 0 !== destroy && destroy();
+ }
+ (effect.tag & mountTag) !== NoEffect$1 &&
+ ((destroy = effect.create), (effect.destroy = destroy()));
+ effect = effect.next;
+ } while (effect !== finishedWork);
+ }
+}
function commitWork(current$$1, finishedWork) {
switch (finishedWork.tag) {
case 0:
case 11:
case 14:
case 15:
+ commitHookEffectList(UnmountMutation, MountMutation, finishedWork);
return;
}
switch (finishedWork.tag) {
@@ -4720,9 +5294,10 @@
);
}
}
+var PossiblyWeakMap = "function" === typeof WeakMap ? WeakMap : Map;
function createRootErrorUpdate(fiber, errorInfo, expirationTime) {
expirationTime = createUpdate(expirationTime);
- expirationTime.tag = 3;
+ expirationTime.tag = CaptureUpdate;
expirationTime.payload = { element: null };
var error = errorInfo.value;
expirationTime.callback = function() {
@@ -4733,7 +5308,7 @@
}
function createClassErrorUpdate(fiber, errorInfo, expirationTime) {
expirationTime = createUpdate(expirationTime);
- expirationTime.tag = 3;
+ expirationTime.tag = CaptureUpdate;
var getDerivedStateFromError = fiber.type.getDerivedStateFromError;
if ("function" === typeof getDerivedStateFromError) {
var error$jscomp$0 = errorInfo.value;
@@ -4789,6 +5364,8 @@
workInProgress)
: null
);
+ case 18:
+ return null;
case 4:
return popHostContainer(workInProgress), null;
case 10:
@@ -4797,7 +5374,7 @@
return null;
}
}
-var DispatcherWithoutHooks = { readContext: readContext },
+var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher,
ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner,
isWorking = !1,
nextUnitOfWork = null,
@@ -4807,6 +5384,7 @@
nextRenderDidError = !1,
nextEffect = null,
isCommitting$1 = !1,
+ rootWithPendingPassiveEffects = null,
passiveEffectCallbackHandle = null,
passiveEffectCallback = null,
legacyErrorBoundariesThatAlreadyFailed = null;
@@ -4847,10 +5425,387 @@
nextRenderDidError = !1;
nextUnitOfWork = null;
}
+function commitAllHostEffects() {
+ for (; null !== nextEffect; ) {
+ var effectTag = nextEffect.effectTag;
+ if (effectTag & 128) {
+ var current$$1 = nextEffect.alternate;
+ null !== current$$1 &&
+ ((current$$1 = current$$1.ref),
+ null !== current$$1 &&
+ ("function" === typeof current$$1
+ ? current$$1(null)
+ : (current$$1.current = null)));
+ }
+ switch (effectTag & 14) {
+ case 2:
+ nextEffect.effectTag &= -3;
+ break;
+ case 6:
+ nextEffect.effectTag &= -3;
+ commitWork(nextEffect.alternate, nextEffect);
+ break;
+ case 4:
+ commitWork(nextEffect.alternate, nextEffect);
+ break;
+ case 8:
+ effectTag = nextEffect;
+ a: for (var node = (current$$1 = effectTag); ; ) {
+ var current$$1$jscomp$0 = node;
+ "function" === typeof onCommitFiberUnmount &&
+ onCommitFiberUnmount(current$$1$jscomp$0);
+ switch (current$$1$jscomp$0.tag) {
+ case 0:
+ case 11:
+ case 14:
+ case 15:
+ var updateQueue = current$$1$jscomp$0.updateQueue;
+ if (
+ null !== updateQueue &&
+ ((updateQueue = updateQueue.lastEffect), null !== updateQueue)
+ ) {
+ var effect = (updateQueue = updateQueue.next);
+ do {
+ var destroy = effect.destroy;
+ if (void 0 !== destroy) {
+ var current$$1$jscomp$1 = current$$1$jscomp$0;
+ try {
+ destroy();
+ } catch (error) {
+ captureCommitPhaseError(current$$1$jscomp$1, error);
+ }
+ }
+ effect = effect.next;
+ } while (effect !== updateQueue);
+ }
+ break;
+ case 1:
+ safelyDetachRef(current$$1$jscomp$0);
+ updateQueue = current$$1$jscomp$0.stateNode;
+ if ("function" === typeof updateQueue.componentWillUnmount)
+ try {
+ (updateQueue.props = current$$1$jscomp$0.memoizedProps),
+ (updateQueue.state = current$$1$jscomp$0.memoizedState),
+ updateQueue.componentWillUnmount();
+ } catch (unmountError) {
+ captureCommitPhaseError(current$$1$jscomp$0, unmountError);
+ }
+ break;
+ case 5:
+ safelyDetachRef(current$$1$jscomp$0);
+ break;
+ case 4:
+ FabricUIManager.createChildSet(
+ current$$1$jscomp$0.stateNode.containerInfo
+ );
+ }
+ if (null !== node.child)
+ (node.child.return = node), (node = node.child);
+ else {
+ if (node === current$$1) break;
+ for (; null === node.sibling; ) {
+ if (null === node.return || node.return === current$$1) break a;
+ node = node.return;
+ }
+ node.sibling.return = node.return;
+ node = node.sibling;
+ }
+ }
+ effectTag.return = null;
+ effectTag.child = null;
+ effectTag.memoizedState = null;
+ effectTag.updateQueue = null;
+ effectTag = effectTag.alternate;
+ null !== effectTag &&
+ ((effectTag.return = null),
+ (effectTag.child = null),
+ (effectTag.memoizedState = null),
+ (effectTag.updateQueue = null));
+ }
+ nextEffect = nextEffect.nextEffect;
+ }
+}
+function commitBeforeMutationLifecycles() {
+ for (; null !== nextEffect; ) {
+ if (nextEffect.effectTag & 256)
+ a: {
+ var current$$1 = nextEffect.alternate,
+ finishedWork = nextEffect;
+ switch (finishedWork.tag) {
+ case 0:
+ case 11:
+ case 15:
+ commitHookEffectList(UnmountSnapshot, NoEffect$1, finishedWork);
+ break a;
+ case 1:
+ if (finishedWork.effectTag & 256 && null !== current$$1) {
+ var prevProps = current$$1.memoizedProps,
+ prevState = current$$1.memoizedState;
+ current$$1 = finishedWork.stateNode;
+ finishedWork = current$$1.getSnapshotBeforeUpdate(
+ finishedWork.elementType === finishedWork.type
+ ? prevProps
+ : resolveDefaultProps(finishedWork.type, prevProps),
+ prevState
+ );
+ current$$1.__reactInternalSnapshotBeforeUpdate = finishedWork;
+ }
+ break a;
+ case 3:
+ case 5:
+ case 6:
+ case 4:
+ case 17:
+ break a;
+ default:
+ invariant(
+ !1,
+ "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue."
+ );
+ }
+ }
+ nextEffect = nextEffect.nextEffect;
+ }
+}
+function commitAllLifeCycles(finishedRoot, committedExpirationTime$jscomp$0) {
+ for (; null !== nextEffect; ) {
+ var effectTag = nextEffect.effectTag;
+ if (effectTag & 36) {
+ var current$$1 = nextEffect.alternate,
+ finishedWork = nextEffect,
+ committedExpirationTime = committedExpirationTime$jscomp$0;
+ switch (finishedWork.tag) {
+ case 0:
+ case 11:
+ case 15:
+ commitHookEffectList(UnmountLayout, MountLayout, finishedWork);
+ break;
+ case 1:
+ var instance = finishedWork.stateNode;
+ if (finishedWork.effectTag & 4)
+ if (null === current$$1) instance.componentDidMount();
+ else {
+ var prevProps =
+ finishedWork.elementType === finishedWork.type
+ ? current$$1.memoizedProps
+ : resolveDefaultProps(
+ finishedWork.type,
+ current$$1.memoizedProps
+ );
+ instance.componentDidUpdate(
+ prevProps,
+ current$$1.memoizedState,
+ instance.__reactInternalSnapshotBeforeUpdate
+ );
+ }
+ current$$1 = finishedWork.updateQueue;
+ null !== current$$1 &&
+ commitUpdateQueue(
+ finishedWork,
+ current$$1,
+ instance,
+ committedExpirationTime
+ );
+ break;
+ case 3:
+ instance = finishedWork.updateQueue;
+ if (null !== instance) {
+ current$$1 = null;
+ if (null !== finishedWork.child)
+ switch (finishedWork.child.tag) {
+ case 5:
+ current$$1 = finishedWork.child.stateNode.canonical;
+ break;
+ case 1:
+ current$$1 = finishedWork.child.stateNode;
+ }
+ commitUpdateQueue(
+ finishedWork,
+ instance,
+ current$$1,
+ committedExpirationTime
+ );
+ }
+ break;
+ case 5:
+ null === current$$1 &&
+ finishedWork.effectTag & 4 &&
+ invariant(
+ !1,
+ "The current renderer does not support mutation. This error is likely caused by a bug in React. Please file an issue."
+ );
+ break;
+ case 6:
+ break;
+ case 4:
+ break;
+ case 12:
+ break;
+ case 13:
+ break;
+ case 17:
+ break;
+ default:
+ invariant(
+ !1,
+ "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue."
+ );
+ }
+ }
+ if (
+ effectTag & 128 &&
+ ((finishedWork = nextEffect.ref), null !== finishedWork)
+ ) {
+ committedExpirationTime = nextEffect.stateNode;
+ switch (nextEffect.tag) {
+ case 5:
+ committedExpirationTime = committedExpirationTime.canonical;
+ }
+ "function" === typeof finishedWork
+ ? finishedWork(committedExpirationTime)
+ : (finishedWork.current = committedExpirationTime);
+ }
+ effectTag & 512 && (rootWithPendingPassiveEffects = finishedRoot);
+ nextEffect = nextEffect.nextEffect;
+ }
+}
+function commitPassiveEffects(root, firstEffect) {
+ passiveEffectCallback = passiveEffectCallbackHandle = rootWithPendingPassiveEffects = null;
+ var previousIsRendering = isRendering;
+ isRendering = !0;
+ do {
+ if (firstEffect.effectTag & 512) {
+ var didError = !1,
+ error = void 0;
+ try {
+ var finishedWork = firstEffect;
+ commitHookEffectList(UnmountPassive, NoEffect$1, finishedWork);
+ commitHookEffectList(NoEffect$1, MountPassive, finishedWork);
+ } catch (e) {
+ (didError = !0), (error = e);
+ }
+ didError && captureCommitPhaseError(firstEffect, error);
+ }
+ firstEffect = firstEffect.nextEffect;
+ } while (null !== firstEffect);
+ isRendering = previousIsRendering;
+ previousIsRendering = root.expirationTime;
+ 0 !== previousIsRendering && requestWork(root, previousIsRendering);
+ isBatchingUpdates || isRendering || performWork(1073741823, !1);
+}
function flushPassiveEffects() {
- null !== passiveEffectCallback &&
- (scheduler.unstable_cancelCallback(passiveEffectCallbackHandle),
- passiveEffectCallback());
+ if (null !== passiveEffectCallbackHandle) {
+ var callbackID = passiveEffectCallbackHandle;
+ scheduledCallback = null;
+ clearTimeout(callbackID);
+ }
+ null !== passiveEffectCallback && passiveEffectCallback();
+}
+function commitRoot(root, finishedWork) {
+ isCommitting$1 = isWorking = !0;
+ invariant(
+ root.current !== finishedWork,
+ "Cannot commit the same tree as before. This is probably a bug related to the return field. This error is likely caused by a bug in React. Please file an issue."
+ );
+ var committedExpirationTime = root.pendingCommitExpirationTime;
+ invariant(
+ 0 !== committedExpirationTime,
+ "Cannot commit an incomplete root. This error is likely caused by a bug in React. Please file an issue."
+ );
+ root.pendingCommitExpirationTime = 0;
+ var updateExpirationTimeBeforeCommit = finishedWork.expirationTime,
+ childExpirationTimeBeforeCommit = finishedWork.childExpirationTime;
+ markCommittedPriorityLevels(
+ root,
+ childExpirationTimeBeforeCommit > updateExpirationTimeBeforeCommit
+ ? childExpirationTimeBeforeCommit
+ : updateExpirationTimeBeforeCommit
+ );
+ ReactCurrentOwner$2.current = null;
+ updateExpirationTimeBeforeCommit = void 0;
+ 1 < finishedWork.effectTag
+ ? null !== finishedWork.lastEffect
+ ? ((finishedWork.lastEffect.nextEffect = finishedWork),
+ (updateExpirationTimeBeforeCommit = finishedWork.firstEffect))
+ : (updateExpirationTimeBeforeCommit = finishedWork)
+ : (updateExpirationTimeBeforeCommit = finishedWork.firstEffect);
+ for (nextEffect = updateExpirationTimeBeforeCommit; null !== nextEffect; ) {
+ childExpirationTimeBeforeCommit = !1;
+ var error = void 0;
+ try {
+ commitBeforeMutationLifecycles();
+ } catch (e) {
+ (childExpirationTimeBeforeCommit = !0), (error = e);
+ }
+ childExpirationTimeBeforeCommit &&
+ (invariant(
+ null !== nextEffect,
+ "Should have next effect. This error is likely caused by a bug in React. Please file an issue."
+ ),
+ captureCommitPhaseError(nextEffect, error),
+ null !== nextEffect && (nextEffect = nextEffect.nextEffect));
+ }
+ for (nextEffect = updateExpirationTimeBeforeCommit; null !== nextEffect; ) {
+ childExpirationTimeBeforeCommit = !1;
+ error = void 0;
+ try {
+ commitAllHostEffects();
+ } catch (e) {
+ (childExpirationTimeBeforeCommit = !0), (error = e);
+ }
+ childExpirationTimeBeforeCommit &&
+ (invariant(
+ null !== nextEffect,
+ "Should have next effect. This error is likely caused by a bug in React. Please file an issue."
+ ),
+ captureCommitPhaseError(nextEffect, error),
+ null !== nextEffect && (nextEffect = nextEffect.nextEffect));
+ }
+ root.current = finishedWork;
+ for (nextEffect = updateExpirationTimeBeforeCommit; null !== nextEffect; ) {
+ childExpirationTimeBeforeCommit = !1;
+ error = void 0;
+ try {
+ commitAllLifeCycles(root, committedExpirationTime);
+ } catch (e) {
+ (childExpirationTimeBeforeCommit = !0), (error = e);
+ }
+ childExpirationTimeBeforeCommit &&
+ (invariant(
+ null !== nextEffect,
+ "Should have next effect. This error is likely caused by a bug in React. Please file an issue."
+ ),
+ captureCommitPhaseError(nextEffect, error),
+ null !== nextEffect && (nextEffect = nextEffect.nextEffect));
+ }
+ if (
+ null !== updateExpirationTimeBeforeCommit &&
+ null !== rootWithPendingPassiveEffects
+ ) {
+ var callback = commitPassiveEffects.bind(
+ null,
+ root,
+ updateExpirationTimeBeforeCommit
+ );
+ passiveEffectCallbackHandle = scheduler.unstable_runWithPriority(
+ scheduler.unstable_NormalPriority,
+ function() {
+ return scheduleDeferredCallback$1(callback);
+ }
+ );
+ passiveEffectCallback = callback;
+ }
+ isWorking = isCommitting$1 = !1;
+ "function" === typeof onCommitFiberRoot &&
+ onCommitFiberRoot(finishedWork.stateNode);
+ committedExpirationTime = finishedWork.expirationTime;
+ finishedWork = finishedWork.childExpirationTime;
+ finishedWork =
+ finishedWork > committedExpirationTime
+ ? finishedWork
+ : committedExpirationTime;
+ 0 === finishedWork && (legacyErrorBoundariesThatAlreadyFailed = null);
+ onCommit(root, finishedWork);
}
function completeUnitOfWork(workInProgress) {
for (;;) {
@@ -4989,11 +5944,7 @@
: ((current$$1.firstEffect = current$$1.lastEffect = current),
(current.nextEffect = null)),
(current.effectTag = 8)));
- if (
- instance !== renderExpirationTime ||
- (0 === (current$$1.effectTag & 1) && instance)
- )
- current$$1.effectTag |= 4;
+ if (instance || renderExpirationTime) current$$1.effectTag |= 4;
break;
case 7:
break;
@@ -5015,6 +5966,8 @@
case 17:
isContextProvider(current$$1.type) && popContext(current$$1);
break;
+ case 18:
+ break;
default:
invariant(
!1,
@@ -5084,7 +6037,8 @@
);
flushPassiveEffects();
isWorking = !0;
- ReactCurrentOwner$2.currentDispatcher = DispatcherWithoutHooks;
+ var previousDispatcher = ReactCurrentDispatcher.current;
+ ReactCurrentDispatcher.current = ContextOnlyDispatcher;
var expirationTime = root$jscomp$0.nextExpirationTimeToWorkOn;
if (
expirationTime !== nextRenderExpirationTime ||
@@ -5104,7 +6058,7 @@
do {
try {
if (isYieldy)
- for (; null !== nextUnitOfWork && !shouldYieldToRenderer(); )
+ for (; null !== nextUnitOfWork && !(frameDeadline <= now$1()); )
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
else
for (; null !== nextUnitOfWork; )
@@ -5112,6 +6066,7 @@
} catch (thrownValue) {
if (
((lastContextWithAllBitsObserved = lastContextDependency = currentlyRenderingFiber = null),
+ resetHooks(),
null === nextUnitOfWork)
)
(didFatal = !0), onUncaughtError(thrownValue);
@@ -5171,23 +6126,44 @@
? !1
: null === value.memoizedState;
if (current$$1) {
- returnFiber$jscomp$0 = retrySuspendedRoot.bind(
- null,
- root,
- value,
- sourceFiber$jscomp$0,
- 0 === (value.mode & 1) ? 1073741823 : returnFiber
- );
- thenable.then(returnFiber$jscomp$0, returnFiber$jscomp$0);
+ returnFiber$jscomp$0 = value.updateQueue;
+ null === returnFiber$jscomp$0
+ ? ((returnFiber$jscomp$0 = new Set()),
+ returnFiber$jscomp$0.add(thenable),
+ (value.updateQueue = returnFiber$jscomp$0))
+ : returnFiber$jscomp$0.add(thenable);
if (0 === (value.mode & 1)) {
value.effectTag |= 64;
sourceFiber$jscomp$0.effectTag &= -1957;
1 === sourceFiber$jscomp$0.tag &&
- null === sourceFiber$jscomp$0.alternate &&
- (sourceFiber$jscomp$0.tag = 17);
- sourceFiber$jscomp$0.expirationTime = returnFiber;
+ (null === sourceFiber$jscomp$0.alternate
+ ? (sourceFiber$jscomp$0.tag = 17)
+ : ((returnFiber = createUpdate(1073741823)),
+ (returnFiber.tag = ForceUpdate),
+ enqueueUpdate(sourceFiber$jscomp$0, returnFiber)));
+ sourceFiber$jscomp$0.expirationTime = 1073741823;
break a;
}
+ 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,
+ sourceFiber$jscomp$0,
+ thenable,
+ returnFiber$jscomp$0
+ )),
+ thenable.then(sourceFiber$jscomp$0, sourceFiber$jscomp$0));
-1 === earliestTimeoutMs
? (root = 1073741823)
: (-1 === startTimeMs &&
@@ -5222,36 +6198,32 @@
do {
switch (root.tag) {
case 3:
- sourceFiber$jscomp$0 = value;
root.effectTag |= 2048;
root.expirationTime = returnFiber;
- returnFiber = createRootErrorUpdate(
- root,
- sourceFiber$jscomp$0,
- returnFiber
- );
+ returnFiber = createRootErrorUpdate(root, value, returnFiber);
enqueueCapturedUpdate(root, returnFiber);
break a;
case 1:
if (
- ((sourceFiber$jscomp$0 = value),
- (returnFiber$jscomp$0 = root.type),
- (thenable = root.stateNode),
+ ((earliestTimeoutMs = value),
+ (startTimeMs = root.type),
+ (sourceFiber$jscomp$0 = root.stateNode),
0 === (root.effectTag & 64) &&
("function" ===
- typeof returnFiber$jscomp$0.getDerivedStateFromError ||
- (null !== thenable &&
- "function" === typeof thenable.componentDidCatch &&
+ typeof startTimeMs.getDerivedStateFromError ||
+ (null !== sourceFiber$jscomp$0 &&
+ "function" ===
+ typeof sourceFiber$jscomp$0.componentDidCatch &&
(null === legacyErrorBoundariesThatAlreadyFailed ||
!legacyErrorBoundariesThatAlreadyFailed.has(
- thenable
+ sourceFiber$jscomp$0
)))))
) {
root.effectTag |= 2048;
root.expirationTime = returnFiber;
returnFiber = createClassErrorUpdate(
root,
- sourceFiber$jscomp$0,
+ earliestTimeoutMs,
returnFiber
);
enqueueCapturedUpdate(root, returnFiber);
@@ -5269,29 +6241,31 @@
break;
} while (1);
isWorking = !1;
- lastContextWithAllBitsObserved = lastContextDependency = currentlyRenderingFiber = ReactCurrentOwner$2.currentDispatcher = null;
+ ReactCurrentDispatcher.current = previousDispatcher;
+ lastContextWithAllBitsObserved = lastContextDependency = currentlyRenderingFiber = null;
+ resetHooks();
if (didFatal) (nextRoot = null), (root$jscomp$0.finishedWork = null);
else if (null !== nextUnitOfWork) root$jscomp$0.finishedWork = null;
else {
- didFatal = root$jscomp$0.current.alternate;
+ previousDispatcher = root$jscomp$0.current.alternate;
invariant(
- null !== didFatal,
+ null !== previousDispatcher,
"Finished root should have a work-in-progress. This error is likely caused by a bug in React. Please file an issue."
);
nextRoot = null;
if (nextRenderDidError) {
- sourceFiber = root$jscomp$0.latestPendingTime;
- returnFiber = root$jscomp$0.latestSuspendedTime;
- root = root$jscomp$0.latestPingedTime;
+ didFatal = root$jscomp$0.latestPendingTime;
+ sourceFiber = root$jscomp$0.latestSuspendedTime;
+ returnFiber = root$jscomp$0.latestPingedTime;
if (
+ (0 !== didFatal && didFatal < expirationTime) ||
(0 !== sourceFiber && sourceFiber < expirationTime) ||
- (0 !== returnFiber && returnFiber < expirationTime) ||
- (0 !== root && root < expirationTime)
+ (0 !== returnFiber && returnFiber < expirationTime)
) {
markSuspendedPriorityLevel(root$jscomp$0, expirationTime);
onSuspend(
root$jscomp$0,
- didFatal,
+ previousDispatcher,
expirationTime,
root$jscomp$0.expirationTime,
-1
@@ -5302,7 +6276,13 @@
root$jscomp$0.didError = !0;
expirationTime = root$jscomp$0.nextExpirationTimeToWorkOn = expirationTime;
isYieldy = root$jscomp$0.expirationTime = 1073741823;
- onSuspend(root$jscomp$0, didFatal, expirationTime, isYieldy, -1);
+ onSuspend(
+ root$jscomp$0,
+ previousDispatcher,
+ expirationTime,
+ isYieldy,
+ -1
+ );
return;
}
}
@@ -5321,13 +6301,13 @@
(isYieldy = nextLatestAbsoluteTimeoutMs - isYieldy),
onSuspend(
root$jscomp$0,
- didFatal,
+ previousDispatcher,
expirationTime,
root$jscomp$0.expirationTime,
0 > isYieldy ? 0 : isYieldy
))
: ((root$jscomp$0.pendingCommitExpirationTime = expirationTime),
- (root$jscomp$0.finishedWork = didFatal));
+ (root$jscomp$0.finishedWork = previousDispatcher));
}
}
function captureCommitPhaseError(sourceFiber, value) {
@@ -5364,57 +6344,63 @@
scheduleWork(sourceFiber, 1073741823));
}
function computeExpirationForFiber(currentTime, fiber) {
- isWorking
- ? (currentTime = isCommitting$1 ? 1073741823 : nextRenderExpirationTime)
- : fiber.mode & 1
- ? ((currentTime = isBatchingInteractiveUpdates
- ? 1073741822 - 10 * ((((1073741822 - currentTime + 15) / 10) | 0) + 1)
- : 1073741822 -
- 25 * ((((1073741822 - currentTime + 500) / 25) | 0) + 1)),
+ var priorityLevel = scheduler.unstable_getCurrentPriorityLevel(),
+ expirationTime = void 0;
+ if (0 === (fiber.mode & 1)) expirationTime = 1073741823;
+ else if (isWorking && !isCommitting$1)
+ expirationTime = nextRenderExpirationTime;
+ else {
+ switch (priorityLevel) {
+ case scheduler.unstable_ImmediatePriority:
+ expirationTime = 1073741823;
+ break;
+ case scheduler.unstable_UserBlockingPriority:
+ expirationTime =
+ 1073741822 - 10 * ((((1073741822 - currentTime + 15) / 10) | 0) + 1);
+ break;
+ case scheduler.unstable_NormalPriority:
+ expirationTime =
+ 1073741822 - 25 * ((((1073741822 - currentTime + 500) / 25) | 0) + 1);
+ break;
+ case scheduler.unstable_LowPriority:
+ case scheduler.unstable_IdlePriority:
+ expirationTime = 1;
+ break;
+ default:
+ invariant(
+ !1,
+ "Unknown priority level. This error is likely caused by a bug in React. Please file an issue."
+ );
+ }
null !== nextRoot &&
- currentTime === nextRenderExpirationTime &&
- --currentTime)
- : (currentTime = 1073741823);
- isBatchingInteractiveUpdates &&
+ expirationTime === nextRenderExpirationTime &&
+ --expirationTime;
+ }
+ priorityLevel === scheduler.unstable_UserBlockingPriority &&
(0 === lowestPriorityPendingInteractiveExpirationTime ||
- currentTime < lowestPriorityPendingInteractiveExpirationTime) &&
- (lowestPriorityPendingInteractiveExpirationTime = currentTime);
- return currentTime;
-}
-function retrySuspendedRoot(root, boundaryFiber, sourceFiber, suspendedTime) {
- var retryTime = root.earliestSuspendedTime;
- var latestSuspendedTime = root.latestSuspendedTime;
- if (
- 0 !== retryTime &&
- suspendedTime <= retryTime &&
- suspendedTime >= latestSuspendedTime
+ expirationTime < lowestPriorityPendingInteractiveExpirationTime) &&
+ (lowestPriorityPendingInteractiveExpirationTime = expirationTime);
+ return expirationTime;
+}
+function pingSuspendedRoot(root, thenable, pingTime) {
+ var pingCache = root.pingCache;
+ null !== pingCache && pingCache.delete(thenable);
+ if (null !== nextRoot && nextRenderExpirationTime === pingTime)
+ nextRoot = null;
+ else if (
+ ((thenable = root.earliestSuspendedTime),
+ (pingCache = root.latestSuspendedTime),
+ 0 !== thenable && pingTime <= thenable && pingTime >= pingCache)
) {
- latestSuspendedTime = retryTime = suspendedTime;
root.didError = !1;
- var latestPingedTime = root.latestPingedTime;
- if (0 === latestPingedTime || latestPingedTime > latestSuspendedTime)
- root.latestPingedTime = latestSuspendedTime;
- findNextExpirationTimeToWorkOn(latestSuspendedTime, root);
- } else
- (retryTime = requestCurrentTime()),
- (retryTime = computeExpirationForFiber(retryTime, boundaryFiber)),
- markPendingPriorityLevel(root, retryTime);
- 0 !== (boundaryFiber.mode & 1) &&
- root === nextRoot &&
- nextRenderExpirationTime === suspendedTime &&
- (nextRoot = null);
- scheduleWorkToRoot(boundaryFiber, retryTime);
- 0 === (boundaryFiber.mode & 1) &&
- (scheduleWorkToRoot(sourceFiber, retryTime),
- 1 === sourceFiber.tag &&
- null !== sourceFiber.stateNode &&
- ((boundaryFiber = createUpdate(retryTime)),
- (boundaryFiber.tag = 2),
- enqueueUpdate(sourceFiber, boundaryFiber)));
- sourceFiber = root.expirationTime;
- 0 !== sourceFiber && requestWork(root, sourceFiber);
+ thenable = root.latestPingedTime;
+ if (0 === thenable || thenable > pingTime) root.latestPingedTime = pingTime;
+ findNextExpirationTimeToWorkOn(pingTime, root);
+ pingTime = root.expirationTime;
+ 0 !== pingTime && requestWork(root, pingTime);
+ }
}
-function scheduleWorkToRoot(fiber, expirationTime) {
+function scheduleWork(fiber, expirationTime) {
fiber.expirationTime < expirationTime &&
(fiber.expirationTime = expirationTime);
var alternate = fiber.alternate;
@@ -5438,10 +6424,7 @@
}
node = node.return;
}
- return root;
-}
-function scheduleWork(fiber, expirationTime) {
- fiber = scheduleWorkToRoot(fiber, expirationTime);
+ fiber = root;
null !== fiber &&
(!isWorking &&
0 !== nextRenderExpirationTime &&
@@ -5469,7 +6452,6 @@
unhandledError = null,
isBatchingUpdates = !1,
isUnbatchingUpdates = !1,
- isBatchingInteractiveUpdates = !1,
completedBatches = null,
originalStartTimeMs = now$1(),
currentRendererTime = 1073741822 - ((originalStartTimeMs / 10) | 0),
@@ -5488,9 +6470,10 @@
((root = callbackID), (scheduledCallback = null), clearTimeout(root));
}
callbackExpirationTime = expirationTime;
- now$1();
- scheduledCallback = performAsyncWork;
- callbackID = setTimeout(setTimeoutCallback, 1);
+ root = now$1() - originalStartTimeMs;
+ callbackID = scheduleDeferredCallback$1(performAsyncWork, {
+ timeout: 10 * (1073741822 - expirationTime) - root
+ });
}
function onSuspend(
root,
@@ -5500,7 +6483,7 @@
msUntilTimeout
) {
root.expirationTime = rootExpirationTime;
- 0 !== msUntilTimeout || shouldYieldToRenderer()
+ 0 !== msUntilTimeout || frameDeadline <= now$1()
? 0 < msUntilTimeout &&
(root.timeoutHandle = scheduleTimeout(
onTimeout.bind(null, root, finishedWork, suspendedExpirationTime),
@@ -5523,6 +6506,10 @@
performWorkOnRoot(root, suspendedExpirationTime, !1);
performWork(1073741823, !1);
}
+function onCommit(root, expirationTime) {
+ root.expirationTime = expirationTime;
+ root.finishedWork = null;
+}
function requestCurrentTime() {
if (isRendering) return currentSchedulerTime;
findHighestPriorityRoot();
@@ -5596,27 +6583,19 @@
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) {
+function performAsyncWork(didTimeout) {
+ if (didTimeout && null !== firstScheduledRoot) {
recomputeCurrentRendererTime();
- var root = firstScheduledRoot;
+ didTimeout = firstScheduledRoot;
do {
- var expirationTime = root.expirationTime;
+ var expirationTime = didTimeout.expirationTime;
0 !== expirationTime &&
currentRendererTime <= expirationTime &&
- (root.nextExpirationTimeToWorkOn = currentRendererTime);
- root = root.nextScheduledRoot;
- } while (root !== firstScheduledRoot);
+ (didTimeout.nextExpirationTimeToWorkOn = currentRendererTime);
+ didTimeout = didTimeout.nextScheduledRoot;
+ } while (didTimeout !== firstScheduledRoot);
}
performWork(0, !0);
- } finally {
- didYield = !1;
- }
}
function performWork(minExpirationTime, isYieldy) {
findHighestPriorityRoot();
@@ -5627,7 +6606,10 @@
null !== nextFlushedRoot &&
0 !== nextFlushedExpirationTime &&
minExpirationTime <= nextFlushedExpirationTime &&
- !(didYield && currentRendererTime > nextFlushedExpirationTime);
+ !(
+ frameDeadline <= now$1() &&
+ currentRendererTime > nextFlushedExpirationTime
+ );
)
performWorkOnRoot(
@@ -5695,7 +6677,7 @@
renderRoot(root, isYieldy),
(_finishedWork = root.finishedWork),
null !== _finishedWork &&
- (shouldYieldToRenderer()
+ (frameDeadline <= now$1()
? (root.finishedWork = _finishedWork)
: completeRoot$1(root, _finishedWork, expirationTime)));
} else
@@ -5712,7 +6694,7 @@
completeRoot$1(root, _finishedWork, expirationTime));
isRendering = !1;
}
-function completeRoot$1(root, finishedWork$jscomp$0, expirationTime) {
+function completeRoot$1(root, finishedWork, expirationTime) {
var firstBatch = root.firstBatch;
if (
null !== firstBatch &&
@@ -5722,7 +6704,7 @@
: completedBatches.push(firstBatch),
firstBatch._defer)
) {
- root.finishedWork = finishedWork$jscomp$0;
+ root.finishedWork = finishedWork;
root.expirationTime = 0;
return;
}
@@ -5730,364 +6712,12 @@
root === lastCommittedRootDuringThisBatch
? nestedUpdateCount++
: ((lastCommittedRootDuringThisBatch = root), (nestedUpdateCount = 0));
- isCommitting$1 = isWorking = !0;
- invariant(
- root.current !== finishedWork$jscomp$0,
- "Cannot commit the same tree as before. This is probably a bug related to the return field. This error is likely caused by a bug in React. Please file an issue."
- );
- expirationTime = root.pendingCommitExpirationTime;
- invariant(
- 0 !== expirationTime,
- "Cannot commit an incomplete root. This error is likely caused by a bug in React. Please file an issue."
- );
- root.pendingCommitExpirationTime = 0;
- firstBatch = finishedWork$jscomp$0.expirationTime;
- var childExpirationTimeBeforeCommit =
- finishedWork$jscomp$0.childExpirationTime;
- firstBatch =
- childExpirationTimeBeforeCommit > firstBatch
- ? childExpirationTimeBeforeCommit
- : firstBatch;
- root.didError = !1;
- 0 === firstBatch
- ? ((root.earliestPendingTime = 0),
- (root.latestPendingTime = 0),
- (root.earliestSuspendedTime = 0),
- (root.latestSuspendedTime = 0),
- (root.latestPingedTime = 0))
- : ((childExpirationTimeBeforeCommit = root.latestPendingTime),
- 0 !== childExpirationTimeBeforeCommit &&
- (childExpirationTimeBeforeCommit > firstBatch
- ? (root.earliestPendingTime = root.latestPendingTime = 0)
- : root.earliestPendingTime > firstBatch &&
- (root.earliestPendingTime = root.latestPendingTime)),
- (childExpirationTimeBeforeCommit = root.earliestSuspendedTime),
- 0 === childExpirationTimeBeforeCommit
- ? markPendingPriorityLevel(root, firstBatch)
- : firstBatch < root.latestSuspendedTime
- ? ((root.earliestSuspendedTime = 0),
- (root.latestSuspendedTime = 0),
- (root.latestPingedTime = 0),
- markPendingPriorityLevel(root, firstBatch))
- : firstBatch > childExpirationTimeBeforeCommit &&
- markPendingPriorityLevel(root, firstBatch));
- findNextExpirationTimeToWorkOn(0, root);
- ReactCurrentOwner$2.current = null;
- 1 < finishedWork$jscomp$0.effectTag
- ? null !== finishedWork$jscomp$0.lastEffect
- ? ((finishedWork$jscomp$0.lastEffect.nextEffect = finishedWork$jscomp$0),
- (firstBatch = finishedWork$jscomp$0.firstEffect))
- : (firstBatch = finishedWork$jscomp$0)
- : (firstBatch = finishedWork$jscomp$0.firstEffect);
- for (nextEffect = firstBatch; null !== nextEffect; ) {
- childExpirationTimeBeforeCommit = !1;
- var error$jscomp$0 = void 0;
- try {
- for (; null !== nextEffect; ) {
- if (nextEffect.effectTag & 256)
- a: {
- var current$$1 = nextEffect.alternate,
- finishedWork = nextEffect;
- switch (finishedWork.tag) {
- case 0:
- case 11:
- case 15:
- break a;
- case 1:
- if (finishedWork.effectTag & 256 && null !== current$$1) {
- var prevProps = current$$1.memoizedProps,
- prevState = current$$1.memoizedState,
- instance = finishedWork.stateNode,
- snapshot = instance.getSnapshotBeforeUpdate(
- finishedWork.elementType === finishedWork.type
- ? prevProps
- : resolveDefaultProps(finishedWork.type, prevProps),
- prevState
- );
- instance.__reactInternalSnapshotBeforeUpdate = snapshot;
- }
- break a;
- case 3:
- case 5:
- case 6:
- case 4:
- case 17:
- break a;
- default:
- invariant(
- !1,
- "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue."
- );
- }
- }
- nextEffect = nextEffect.nextEffect;
- }
- } catch (e) {
- (childExpirationTimeBeforeCommit = !0), (error$jscomp$0 = e);
- }
- childExpirationTimeBeforeCommit &&
- (invariant(
- null !== nextEffect,
- "Should have next effect. This error is likely caused by a bug in React. Please file an issue."
- ),
- captureCommitPhaseError(nextEffect, error$jscomp$0),
- null !== nextEffect && (nextEffect = nextEffect.nextEffect));
- }
- for (nextEffect = firstBatch; null !== nextEffect; ) {
- current$$1 = !1;
- prevProps = void 0;
- try {
- for (; null !== nextEffect; ) {
- var effectTag = nextEffect.effectTag;
- if (effectTag & 128) {
- var current$$1$jscomp$0 = nextEffect.alternate;
- if (null !== current$$1$jscomp$0) {
- var currentRef = current$$1$jscomp$0.ref;
- null !== currentRef &&
- ("function" === typeof currentRef
- ? currentRef(null)
- : (currentRef.current = null));
- }
- }
- switch (effectTag & 14) {
- case 2:
- nextEffect.effectTag &= -3;
- break;
- case 6:
- nextEffect.effectTag &= -3;
- commitWork(nextEffect.alternate, nextEffect);
- break;
- case 4:
- commitWork(nextEffect.alternate, nextEffect);
- break;
- case 8:
- prevState = nextEffect;
- a: for (snapshot = instance = prevState; ; ) {
- childExpirationTimeBeforeCommit = snapshot;
- "function" === typeof onCommitFiberUnmount &&
- onCommitFiberUnmount(childExpirationTimeBeforeCommit);
- switch (childExpirationTimeBeforeCommit.tag) {
- case 0:
- case 11:
- case 14:
- case 15:
- var updateQueue = childExpirationTimeBeforeCommit.updateQueue;
- if (null !== updateQueue) {
- var lastEffect = updateQueue.lastEffect;
- if (null !== lastEffect) {
- var firstEffect = lastEffect.next;
- error$jscomp$0 = firstEffect;
- do {
- var destroy = error$jscomp$0.destroy;
- if (null !== destroy) {
- finishedWork = childExpirationTimeBeforeCommit;
- try {
- destroy();
- } catch (error) {
- captureCommitPhaseError(finishedWork, error);
+ scheduler.unstable_runWithPriority(
+ scheduler.unstable_ImmediatePriority,
+ function() {
+ commitRoot(root, finishedWork);
}
- }
- error$jscomp$0 = error$jscomp$0.next;
- } while (error$jscomp$0 !== firstEffect);
- }
- }
- break;
- case 1:
- safelyDetachRef(childExpirationTimeBeforeCommit);
- var instance$jscomp$0 =
- childExpirationTimeBeforeCommit.stateNode;
- if (
- "function" === typeof instance$jscomp$0.componentWillUnmount
- )
- try {
- (instance$jscomp$0.props =
- childExpirationTimeBeforeCommit.memoizedProps),
- (instance$jscomp$0.state =
- childExpirationTimeBeforeCommit.memoizedState),
- instance$jscomp$0.componentWillUnmount();
- } catch (unmountError) {
- captureCommitPhaseError(
- childExpirationTimeBeforeCommit,
- unmountError
);
- }
- break;
- case 5:
- safelyDetachRef(childExpirationTimeBeforeCommit);
- break;
- case 4:
- FabricUIManager.createChildSet(
- childExpirationTimeBeforeCommit.stateNode.containerInfo
- );
- }
- if (null !== snapshot.child)
- (snapshot.child.return = snapshot), (snapshot = snapshot.child);
- else {
- if (snapshot === instance) break;
- for (; null === snapshot.sibling; ) {
- if (null === snapshot.return || snapshot.return === instance)
- break a;
- snapshot = snapshot.return;
- }
- snapshot.sibling.return = snapshot.return;
- snapshot = snapshot.sibling;
- }
- }
- prevState.return = null;
- prevState.child = null;
- prevState.memoizedState = null;
- prevState.updateQueue = null;
- var alternate = prevState.alternate;
- null !== alternate &&
- ((alternate.return = null),
- (alternate.child = null),
- (alternate.memoizedState = null),
- (alternate.updateQueue = null));
- }
- nextEffect = nextEffect.nextEffect;
- }
- } catch (e) {
- (current$$1 = !0), (prevProps = e);
- }
- current$$1 &&
- (invariant(
- null !== nextEffect,
- "Should have next effect. This error is likely caused by a bug in React. Please file an issue."
- ),
- captureCommitPhaseError(nextEffect, prevProps),
- null !== nextEffect && (nextEffect = nextEffect.nextEffect));
- }
- root.current = finishedWork$jscomp$0;
- for (nextEffect = firstBatch; null !== nextEffect; ) {
- effectTag = !1;
- current$$1$jscomp$0 = void 0;
- try {
- for (currentRef = expirationTime; null !== nextEffect; ) {
- var effectTag$jscomp$0 = nextEffect.effectTag;
- if (effectTag$jscomp$0 & 36) {
- var current$$1$jscomp$1 = nextEffect.alternate;
- updateQueue = nextEffect;
- lastEffect = currentRef;
- switch (updateQueue.tag) {
- case 0:
- case 11:
- case 15:
- break;
- case 1:
- var instance$jscomp$1 = updateQueue.stateNode;
- if (updateQueue.effectTag & 4)
- if (null === current$$1$jscomp$1)
- instance$jscomp$1.componentDidMount();
- else {
- var prevProps$jscomp$0 =
- updateQueue.elementType === updateQueue.type
- ? current$$1$jscomp$1.memoizedProps
- : resolveDefaultProps(
- updateQueue.type,
- current$$1$jscomp$1.memoizedProps
- );
- instance$jscomp$1.componentDidUpdate(
- prevProps$jscomp$0,
- current$$1$jscomp$1.memoizedState,
- instance$jscomp$1.__reactInternalSnapshotBeforeUpdate
- );
- }
- var updateQueue$jscomp$0 = updateQueue.updateQueue;
- null !== updateQueue$jscomp$0 &&
- commitUpdateQueue(
- updateQueue,
- updateQueue$jscomp$0,
- instance$jscomp$1,
- lastEffect
- );
- break;
- case 3:
- var _updateQueue = updateQueue.updateQueue;
- if (null !== _updateQueue) {
- firstEffect = null;
- if (null !== updateQueue.child)
- switch (updateQueue.child.tag) {
- case 5:
- firstEffect = updateQueue.child.stateNode.canonical;
- break;
- case 1:
- firstEffect = updateQueue.child.stateNode;
- }
- commitUpdateQueue(
- updateQueue,
- _updateQueue,
- firstEffect,
- lastEffect
- );
- }
- break;
- case 5:
- null === current$$1$jscomp$1 &&
- updateQueue.effectTag & 4 &&
- invariant(
- !1,
- "The current renderer does not support mutation. This error is likely caused by a bug in React. Please file an issue."
- );
- break;
- case 6:
- break;
- case 4:
- break;
- case 12:
- break;
- case 13:
- break;
- case 17:
- break;
- default:
- invariant(
- !1,
- "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue."
- );
- }
- }
- if (effectTag$jscomp$0 & 128) {
- var ref = nextEffect.ref;
- if (null !== ref) {
- var instance$jscomp$2 = nextEffect.stateNode;
- switch (nextEffect.tag) {
- case 5:
- var instanceToUse = instance$jscomp$2.canonical;
- break;
- default:
- instanceToUse = instance$jscomp$2;
- }
- "function" === typeof ref
- ? ref(instanceToUse)
- : (ref.current = instanceToUse);
- }
- }
- nextEffect = nextEffect.nextEffect;
- }
- } catch (e) {
- (effectTag = !0), (current$$1$jscomp$0 = e);
- }
- effectTag &&
- (invariant(
- null !== nextEffect,
- "Should have next effect. This error is likely caused by a bug in React. Please file an issue."
- ),
- captureCommitPhaseError(nextEffect, current$$1$jscomp$0),
- null !== nextEffect && (nextEffect = nextEffect.nextEffect));
- }
- isWorking = isCommitting$1 = !1;
- "function" === typeof onCommitFiberRoot &&
- onCommitFiberRoot(finishedWork$jscomp$0.stateNode);
- effectTag$jscomp$0 = finishedWork$jscomp$0.expirationTime;
- finishedWork$jscomp$0 = finishedWork$jscomp$0.childExpirationTime;
- finishedWork$jscomp$0 =
- finishedWork$jscomp$0 > effectTag$jscomp$0
- ? finishedWork$jscomp$0
- : effectTag$jscomp$0;
- 0 === finishedWork$jscomp$0 &&
- (legacyErrorBoundariesThatAlreadyFailed = null);
- root.expirationTime = finishedWork$jscomp$0;
- root.finishedWork = null;
}
function onUncaughtError(error) {
invariant(
@@ -6288,18 +6918,20 @@
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
);
}
@@ -6308,6 +6940,21 @@
})(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) {
@@ -6316,6 +6963,7 @@
current: root,
containerInfo: containerTag,
pendingChildren: null,
+ pingCache: null,
earliestPendingTime: 0,
latestPendingTime: 0,
earliestSuspendedTime: 0,
@@ -6392,17 +7040,20 @@
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
);
}
@@ -6421,6 +7072,8 @@
var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance;
return injectInternals(
Object.assign({}, devToolsConfig, {
+ overrideProps: null,
+ currentDispatcherRef: ReactSharedInternals.ReactCurrentDispatcher,
findHostInstanceByFiber: function(fiber) {
fiber = findCurrentHostFiber(fiber);
return null === fiber ? null : fiber.stateNode;
@@ -6436,7 +7089,7 @@
findFiberByHostInstance: getInstanceFromInstance,
getInspectorDataForViewTag: getInspectorDataForViewTag,
bundleType: 0,
- version: "16.6.1",
+ version: "16.8.3",
rendererPackageName: "react-native-renderer"
});
var ReactFabric$2 = { default: ReactFabric },

Libraries/Renderer/oss/ReactFabric-profiling.js

@@ -1020,8 +1020,10 @@
}
});
var ReactSharedInternals =
- React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
- hasSymbol = "function" === typeof Symbol && Symbol.for,
+ React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
+ReactSharedInternals.hasOwnProperty("ReactCurrentDispatcher") ||
+ (ReactSharedInternals.ReactCurrentDispatcher = { current: null });
+var hasSymbol = "function" === typeof Symbol && Symbol.for,
REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for("react.element") : 60103,
REACT_PORTAL_TYPE = hasSymbol ? Symbol.for("react.portal") : 60106,
REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for("react.fragment") : 60107,
@@ -1431,6 +1433,10 @@
scheduledCallback = null;
null !== callback && callback();
}
+function scheduleDeferredCallback$1(callback) {
+ scheduledCallback = callback;
+ return setTimeout(setTimeoutCallback, 1);
+}
var restoreTarget = null,
restoreQueue = null;
function restoreStateOfTarget(target) {
@@ -1779,7 +1785,7 @@
this.index = 0;
this.ref = null;
this.pendingProps = pendingProps;
- this.firstContextDependency = this.memoizedState = this.updateQueue = this.memoizedProps = null;
+ this.contextDependencies = this.memoizedState = this.updateQueue = this.memoizedProps = null;
this.mode = mode;
this.effectTag = 0;
this.lastEffect = this.firstEffect = this.nextEffect = null;
@@ -1833,7 +1839,7 @@
workInProgress.memoizedProps = current.memoizedProps;
workInProgress.memoizedState = current.memoizedState;
workInProgress.updateQueue = current.updateQueue;
- workInProgress.firstContextDependency = current.firstContextDependency;
+ workInProgress.contextDependencies = current.contextDependencies;
workInProgress.sibling = current.sibling;
workInProgress.index = current.index;
workInProgress.ref = current.ref;
@@ -1968,6 +1974,8 @@
(root.latestSuspendedTime = 0),
(root.latestPingedTime = 0);
else {
+ earliestRemainingTime < root.latestPingedTime &&
+ (root.latestPingedTime = 0);
var latestPendingTime = root.latestPendingTime;
0 !== latestPendingTime &&
(latestPendingTime > earliestRemainingTime
@@ -2000,24 +2008,21 @@
}
function markSuspendedPriorityLevel(root, suspendedTime) {
root.didError = !1;
- var latestPingedTime = root.latestPingedTime;
- 0 !== latestPingedTime &&
- latestPingedTime >= suspendedTime &&
- (root.latestPingedTime = 0);
- latestPingedTime = root.earliestPendingTime;
- var latestPendingTime = root.latestPendingTime;
- latestPingedTime === suspendedTime
+ root.latestPingedTime >= suspendedTime && (root.latestPingedTime = 0);
+ var earliestPendingTime = root.earliestPendingTime,
+ latestPendingTime = root.latestPendingTime;
+ earliestPendingTime === suspendedTime
? (root.earliestPendingTime =
latestPendingTime === suspendedTime
? (root.latestPendingTime = 0)
: latestPendingTime)
: latestPendingTime === suspendedTime &&
- (root.latestPendingTime = latestPingedTime);
- latestPingedTime = root.earliestSuspendedTime;
+ (root.latestPendingTime = earliestPendingTime);
+ earliestPendingTime = root.earliestSuspendedTime;
latestPendingTime = root.latestSuspendedTime;
- 0 === latestPingedTime
+ 0 === earliestPendingTime
? (root.earliestSuspendedTime = root.latestSuspendedTime = suspendedTime)
- : latestPingedTime < suspendedTime
+ : earliestPendingTime < suspendedTime
? (root.earliestSuspendedTime = suspendedTime)
: latestPendingTime > suspendedTime &&
(root.latestSuspendedTime = suspendedTime);
@@ -2049,338 +2054,10 @@
root.nextExpirationTimeToWorkOn = earliestPendingTime;
root.expirationTime = completedExpirationTime;
}
-var hasForceUpdate = !1;
-function createUpdateQueue(baseState) {
- return {
- baseState: baseState,
- firstUpdate: null,
- lastUpdate: null,
- firstCapturedUpdate: null,
- lastCapturedUpdate: null,
- firstEffect: null,
- lastEffect: null,
- firstCapturedEffect: null,
- lastCapturedEffect: null
- };
-}
-function cloneUpdateQueue(currentQueue) {
- return {
- baseState: currentQueue.baseState,
- firstUpdate: currentQueue.firstUpdate,
- lastUpdate: currentQueue.lastUpdate,
- firstCapturedUpdate: null,
- lastCapturedUpdate: null,
- firstEffect: null,
- lastEffect: null,
- firstCapturedEffect: null,
- lastCapturedEffect: null
- };
-}
-function createUpdate(expirationTime) {
- return {
- expirationTime: expirationTime,
- tag: 0,
- payload: null,
- callback: null,
- next: null,
- nextEffect: null
- };
-}
-function appendUpdateToQueue(queue, update) {
- null === queue.lastUpdate
- ? (queue.firstUpdate = queue.lastUpdate = update)
- : ((queue.lastUpdate.next = update), (queue.lastUpdate = update));
-}
-function enqueueUpdate(fiber, update) {
- var alternate = fiber.alternate;
- if (null === alternate) {
- var queue1 = fiber.updateQueue;
- var queue2 = null;
- null === queue1 &&
- (queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState));
- } else
- (queue1 = fiber.updateQueue),
- (queue2 = alternate.updateQueue),
- null === queue1
- ? null === queue2
- ? ((queue1 = fiber.updateQueue = createUpdateQueue(
- fiber.memoizedState
- )),
- (queue2 = alternate.updateQueue = createUpdateQueue(
- alternate.memoizedState
- )))
- : (queue1 = fiber.updateQueue = cloneUpdateQueue(queue2))
- : null === queue2 &&
- (queue2 = alternate.updateQueue = cloneUpdateQueue(queue1));
- null === queue2 || queue1 === queue2
- ? appendUpdateToQueue(queue1, update)
- : null === queue1.lastUpdate || null === queue2.lastUpdate
- ? (appendUpdateToQueue(queue1, update),
- appendUpdateToQueue(queue2, update))
- : (appendUpdateToQueue(queue1, update), (queue2.lastUpdate = update));
-}
-function enqueueCapturedUpdate(workInProgress, update) {
- var workInProgressQueue = workInProgress.updateQueue;
- workInProgressQueue =
- null === workInProgressQueue
- ? (workInProgress.updateQueue = createUpdateQueue(
- workInProgress.memoizedState
- ))
- : ensureWorkInProgressQueueIsAClone(workInProgress, workInProgressQueue);
- null === workInProgressQueue.lastCapturedUpdate
- ? (workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update)
- : ((workInProgressQueue.lastCapturedUpdate.next = update),
- (workInProgressQueue.lastCapturedUpdate = update));
-}
-function ensureWorkInProgressQueueIsAClone(workInProgress, queue) {
- var current = workInProgress.alternate;
- null !== current &&
- queue === current.updateQueue &&
- (queue = workInProgress.updateQueue = cloneUpdateQueue(queue));
- return queue;
-}
-function getStateFromUpdate(
- workInProgress,
- queue,
- update,
- prevState,
- nextProps,
- instance
-) {
- switch (update.tag) {
- case 1:
- return (
- (workInProgress = update.payload),
- "function" === typeof workInProgress
- ? workInProgress.call(instance, prevState, nextProps)
- : workInProgress
- );
- case 3:
- workInProgress.effectTag = (workInProgress.effectTag & -2049) | 64;
- case 0:
- workInProgress = update.payload;
- nextProps =
- "function" === typeof workInProgress
- ? workInProgress.call(instance, prevState, nextProps)
- : workInProgress;
- if (null === nextProps || void 0 === nextProps) break;
- return Object.assign({}, prevState, nextProps);
- case 2:
- hasForceUpdate = !0;
- }
- return prevState;
-}
-function processUpdateQueue(
- workInProgress,
- queue,
- props,
- instance,
- renderExpirationTime
-) {
- hasForceUpdate = !1;
- queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue);
- for (
- var newBaseState = queue.baseState,
- newFirstUpdate = null,
- newExpirationTime = 0,
- update = queue.firstUpdate,
- resultState = newBaseState;
- null !== update;
-
- ) {
- var updateExpirationTime = update.expirationTime;
- updateExpirationTime < renderExpirationTime
- ? (null === newFirstUpdate &&
- ((newFirstUpdate = update), (newBaseState = resultState)),
- newExpirationTime < updateExpirationTime &&
- (newExpirationTime = updateExpirationTime))
- : ((resultState = getStateFromUpdate(
- workInProgress,
- queue,
- update,
- resultState,
- props,
- instance
- )),
- null !== update.callback &&
- ((workInProgress.effectTag |= 32),
- (update.nextEffect = null),
- null === queue.lastEffect
- ? (queue.firstEffect = queue.lastEffect = update)
- : ((queue.lastEffect.nextEffect = update),
- (queue.lastEffect = update))));
- update = update.next;
- }
- updateExpirationTime = null;
- for (update = queue.firstCapturedUpdate; null !== update; ) {
- var _updateExpirationTime = update.expirationTime;
- _updateExpirationTime < renderExpirationTime
- ? (null === updateExpirationTime &&
- ((updateExpirationTime = update),
- null === newFirstUpdate && (newBaseState = resultState)),
- newExpirationTime < _updateExpirationTime &&
- (newExpirationTime = _updateExpirationTime))
- : ((resultState = getStateFromUpdate(
- workInProgress,
- queue,
- update,
- resultState,
- props,
- instance
- )),
- null !== update.callback &&
- ((workInProgress.effectTag |= 32),
- (update.nextEffect = null),
- null === queue.lastCapturedEffect
- ? (queue.firstCapturedEffect = queue.lastCapturedEffect = update)
- : ((queue.lastCapturedEffect.nextEffect = update),
- (queue.lastCapturedEffect = update))));
- update = update.next;
- }
- null === newFirstUpdate && (queue.lastUpdate = null);
- null === updateExpirationTime
- ? (queue.lastCapturedUpdate = null)
- : (workInProgress.effectTag |= 32);
- null === newFirstUpdate &&
- null === updateExpirationTime &&
- (newBaseState = resultState);
- queue.baseState = newBaseState;
- queue.firstUpdate = newFirstUpdate;
- queue.firstCapturedUpdate = updateExpirationTime;
- workInProgress.expirationTime = newExpirationTime;
- workInProgress.memoizedState = resultState;
-}
-function commitUpdateQueue(finishedWork, finishedQueue, instance) {
- null !== finishedQueue.firstCapturedUpdate &&
- (null !== finishedQueue.lastUpdate &&
- ((finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate),
- (finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate)),
- (finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null));
- commitUpdateEffects(finishedQueue.firstEffect, instance);
- finishedQueue.firstEffect = finishedQueue.lastEffect = null;
- commitUpdateEffects(finishedQueue.firstCapturedEffect, instance);
- finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null;
-}
-function commitUpdateEffects(effect, instance) {
- for (; null !== effect; ) {
- var _callback3 = effect.callback;
- if (null !== _callback3) {
- effect.callback = null;
- var context = instance;
- invariant(
- "function" === typeof _callback3,
- "Invalid argument passed as callback. Expected a function. Instead received: %s",
- _callback3
- );
- _callback3.call(context);
- }
- effect = effect.nextEffect;
- }
-}
-function createCapturedValue(value, source) {
- return {
- value: value,
- source: source,
- stack: getStackByFiberInDevAndProd(source)
- };
-}
-var valueCursor = { current: null },
- currentlyRenderingFiber = null,
- lastContextDependency = null,
- lastContextWithAllBitsObserved = null;
-function pushProvider(providerFiber, nextValue) {
- var context = providerFiber.type._context;
- push(valueCursor, context._currentValue2, providerFiber);
- context._currentValue2 = nextValue;
-}
-function popProvider(providerFiber) {
- var currentValue = valueCursor.current;
- pop(valueCursor, providerFiber);
- providerFiber.type._context._currentValue2 = currentValue;
-}
-function prepareToReadContext(workInProgress) {
- currentlyRenderingFiber = workInProgress;
- lastContextWithAllBitsObserved = lastContextDependency = null;
- workInProgress.firstContextDependency = null;
-}
-function readContext(context, observedBits) {
- if (
- lastContextWithAllBitsObserved !== context &&
- !1 !== observedBits &&
- 0 !== observedBits
- ) {
- if ("number" !== typeof observedBits || 1073741823 === observedBits)
- (lastContextWithAllBitsObserved = context), (observedBits = 1073741823);
- observedBits = { context: context, observedBits: observedBits, next: null };
- null === lastContextDependency
- ? (invariant(
- null !== currentlyRenderingFiber,
- "Context can only be read while React is rendering, e.g. inside the render method or getDerivedStateFromProps."
- ),
- (currentlyRenderingFiber.firstContextDependency = lastContextDependency = observedBits))
- : (lastContextDependency = lastContextDependency.next = observedBits);
- }
- return context._currentValue2;
-}
-var NO_CONTEXT = {},
- contextStackCursor$1 = { current: NO_CONTEXT },
- contextFiberStackCursor = { current: NO_CONTEXT },
- rootInstanceStackCursor = { current: NO_CONTEXT };
-function requiredContext(c) {
- invariant(
- c !== NO_CONTEXT,
- "Expected host context to exist. This error is likely caused by a bug in React. Please file an issue."
- );
- return c;
-}
-function pushHostContainer(fiber, nextRootInstance) {
- push(rootInstanceStackCursor, nextRootInstance, fiber);
- push(contextFiberStackCursor, fiber, fiber);
- push(contextStackCursor$1, NO_CONTEXT, fiber);
- pop(contextStackCursor$1, fiber);
- push(contextStackCursor$1, { isInAParentText: !1 }, fiber);
-}
-function popHostContainer(fiber) {
- pop(contextStackCursor$1, fiber);
- pop(contextFiberStackCursor, fiber);
- pop(rootInstanceStackCursor, fiber);
-}
-function pushHostContext(fiber) {
- requiredContext(rootInstanceStackCursor.current);
- var context = requiredContext(contextStackCursor$1.current);
- var nextContext = fiber.type;
- nextContext =
- "AndroidTextInput" === nextContext ||
- "RCTMultilineTextInputView" === nextContext ||
- "RCTSinglelineTextInputView" === nextContext ||
- "RCTText" === nextContext ||
- "RCTVirtualText" === nextContext;
- nextContext =
- context.isInAParentText !== nextContext
- ? { isInAParentText: nextContext }
- : context;
- context !== nextContext &&
- (push(contextFiberStackCursor, fiber, fiber),
- push(contextStackCursor$1, nextContext, fiber));
-}
-function popHostContext(fiber) {
- contextFiberStackCursor.current === fiber &&
- (pop(contextStackCursor$1, fiber), pop(contextFiberStackCursor, fiber));
-}
-var commitTime = 0,
- profilerStartTime = -1;
-function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) {
- if (0 <= profilerStartTime) {
- var elapsedTime = now$1() - profilerStartTime;
- fiber.actualDuration += elapsedTime;
- overrideBaseTime && (fiber.selfBaseDuration = elapsedTime);
- profilerStartTime = -1;
- }
-}
-var hasOwnProperty = Object.prototype.hasOwnProperty;
function is(x, y) {
- return x === y ? 0 !== x || 0 !== y || 1 / x === 1 / y : x !== x && y !== y;
+ return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y);
}
+var hasOwnProperty = Object.prototype.hasOwnProperty;
function shallowEqual(objA, objB) {
if (is(objA, objB)) return !0;
if (
@@ -2421,9 +2098,9 @@
case 0:
throw result;
default:
- throw ((lazyComponent._status = 0),
- (result = lazyComponent._ctor),
- (result = result()),
+ lazyComponent._status = 0;
+ result = lazyComponent._ctor;
+ result = result();
result.then(
function(moduleObject) {
0 === lazyComponent._status &&
@@ -2435,13 +2112,18 @@
0 === lazyComponent._status &&
((lazyComponent._status = 2), (lazyComponent._result = error));
}
- ),
- (lazyComponent._result = result),
- result);
+ );
+ switch (lazyComponent._status) {
+ case 1:
+ return lazyComponent._result;
+ case 2:
+ throw lazyComponent._result;
+ }
+ lazyComponent._result = result;
+ throw result;
}
}
-var ReactCurrentOwner$4 = ReactSharedInternals.ReactCurrentOwner,
- emptyRefsObject = new React.Component().refs;
+var emptyRefsObject = new React.Component().refs;
function applyDerivedStateFromProps(
workInProgress,
ctor,
@@ -2482,7 +2164,7 @@
var currentTime = requestCurrentTime();
currentTime = computeExpirationForFiber(currentTime, inst);
var update = createUpdate(currentTime);
- update.tag = 1;
+ update.tag = ReplaceState;
update.payload = payload;
void 0 !== callback && null !== callback && (update.callback = callback);
flushPassiveEffects();
@@ -2494,7 +2176,7 @@
var currentTime = requestCurrentTime();
currentTime = computeExpirationForFiber(currentTime, inst);
var update = createUpdate(currentTime);
- update.tag = 2;
+ update.tag = ForceUpdate;
void 0 !== callback && null !== callback && (update.callback = callback);
flushPassiveEffects();
enqueueUpdate(inst, update);
@@ -2522,7 +2204,7 @@
unmaskedContext = emptyContextObject;
var context = ctor.contextType;
"object" === typeof context && null !== context
- ? (context = ReactCurrentOwner$4.currentDispatcher.readContext(context))
+ ? (context = readContext(context))
: ((unmaskedContext = isContextProvider(ctor)
? previousContext
: contextStackCursor.current),
@@ -2569,9 +2251,7 @@
instance.refs = emptyRefsObject;
var contextType = ctor.contextType;
"object" === typeof contextType && null !== contextType
- ? (instance.context = ReactCurrentOwner$4.currentDispatcher.readContext(
- contextType
- ))
+ ? (instance.context = readContext(contextType))
: ((contextType = isContextProvider(ctor)
? previousContext
: contextStackCursor.current),
@@ -2626,7 +2306,10 @@
element = element._owner;
var inst = void 0;
element &&
- (invariant(1 === element.tag, "Function components cannot have refs."),
+ (invariant(
+ 1 === element.tag,
+ "Function components cannot have refs. Did you mean to use React.forwardRef()?"
+ ),
(inst = element.stateNode));
invariant(
inst,
@@ -3326,7 +3009,523 @@
}
var reconcileChildFibers = ChildReconciler(!0),
mountChildFibers = ChildReconciler(!1),
- hydrationParentFiber = null,
+ NO_CONTEXT = {},
+ contextStackCursor$1 = { current: NO_CONTEXT },
+ contextFiberStackCursor = { current: NO_CONTEXT },
+ rootInstanceStackCursor = { current: NO_CONTEXT };
+function requiredContext(c) {
+ invariant(
+ c !== NO_CONTEXT,
+ "Expected host context to exist. This error is likely caused by a bug in React. Please file an issue."
+ );
+ return c;
+}
+function pushHostContainer(fiber, nextRootInstance) {
+ push(rootInstanceStackCursor, nextRootInstance, fiber);
+ push(contextFiberStackCursor, fiber, fiber);
+ push(contextStackCursor$1, NO_CONTEXT, fiber);
+ pop(contextStackCursor$1, fiber);
+ push(contextStackCursor$1, { isInAParentText: !1 }, fiber);
+}
+function popHostContainer(fiber) {
+ pop(contextStackCursor$1, fiber);
+ pop(contextFiberStackCursor, fiber);
+ pop(rootInstanceStackCursor, fiber);
+}
+function pushHostContext(fiber) {
+ requiredContext(rootInstanceStackCursor.current);
+ var context = requiredContext(contextStackCursor$1.current);
+ var nextContext = fiber.type;
+ nextContext =
+ "AndroidTextInput" === nextContext ||
+ "RCTMultilineTextInputView" === nextContext ||
+ "RCTSinglelineTextInputView" === nextContext ||
+ "RCTText" === nextContext ||
+ "RCTVirtualText" === nextContext;
+ nextContext =
+ context.isInAParentText !== nextContext
+ ? { isInAParentText: nextContext }
+ : context;
+ context !== nextContext &&
+ (push(contextFiberStackCursor, fiber, fiber),
+ push(contextStackCursor$1, nextContext, fiber));
+}
+function popHostContext(fiber) {
+ contextFiberStackCursor.current === fiber &&
+ (pop(contextStackCursor$1, fiber), pop(contextFiberStackCursor, fiber));
+}
+var NoEffect$1 = 0,
+ UnmountSnapshot = 2,
+ UnmountMutation = 4,
+ MountMutation = 8,
+ UnmountLayout = 16,
+ MountLayout = 32,
+ MountPassive = 64,
+ UnmountPassive = 128,
+ ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher,
+ renderExpirationTime = 0,
+ currentlyRenderingFiber$1 = null,
+ currentHook = null,
+ nextCurrentHook = null,
+ firstWorkInProgressHook = null,
+ workInProgressHook = null,
+ nextWorkInProgressHook = null,
+ remainingExpirationTime = 0,
+ componentUpdateQueue = null,
+ sideEffectTag = 0,
+ didScheduleRenderPhaseUpdate = !1,
+ renderPhaseUpdates = null,
+ numberOfReRenders = 0;
+function throwInvalidHookError() {
+ invariant(
+ !1,
+ "Hooks can only be called inside the body of a function component. (https://fb.me/react-invalid-hook-call)"
+ );
+}
+function areHookInputsEqual(nextDeps, prevDeps) {
+ if (null === prevDeps) return !1;
+ for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++)
+ if (!is(nextDeps[i], prevDeps[i])) return !1;
+ return !0;
+}
+function renderWithHooks(
+ current,
+ workInProgress,
+ Component,
+ props,
+ refOrContext,
+ nextRenderExpirationTime
+) {
+ renderExpirationTime = nextRenderExpirationTime;
+ currentlyRenderingFiber$1 = workInProgress;
+ nextCurrentHook = null !== current ? current.memoizedState : null;
+ ReactCurrentDispatcher$1.current =
+ null === nextCurrentHook ? HooksDispatcherOnMount : HooksDispatcherOnUpdate;
+ workInProgress = Component(props, refOrContext);
+ if (didScheduleRenderPhaseUpdate) {
+ do
+ (didScheduleRenderPhaseUpdate = !1),
+ (numberOfReRenders += 1),
+ (nextCurrentHook = null !== current ? current.memoizedState : null),
+ (nextWorkInProgressHook = firstWorkInProgressHook),
+ (componentUpdateQueue = workInProgressHook = currentHook = null),
+ (ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdate),
+ (workInProgress = Component(props, refOrContext));
+ while (didScheduleRenderPhaseUpdate);
+ renderPhaseUpdates = null;
+ numberOfReRenders = 0;
+ }
+ ReactCurrentDispatcher$1.current = ContextOnlyDispatcher;
+ current = currentlyRenderingFiber$1;
+ current.memoizedState = firstWorkInProgressHook;
+ current.expirationTime = remainingExpirationTime;
+ current.updateQueue = componentUpdateQueue;
+ current.effectTag |= sideEffectTag;
+ current = null !== currentHook && null !== currentHook.next;
+ renderExpirationTime = 0;
+ nextWorkInProgressHook = workInProgressHook = firstWorkInProgressHook = nextCurrentHook = currentHook = currentlyRenderingFiber$1 = null;
+ remainingExpirationTime = 0;
+ componentUpdateQueue = null;
+ sideEffectTag = 0;
+ invariant(
+ !current,
+ "Rendered fewer hooks than expected. This may be caused by an accidental early return statement."
+ );
+ return workInProgress;
+}
+function resetHooks() {
+ ReactCurrentDispatcher$1.current = ContextOnlyDispatcher;
+ renderExpirationTime = 0;
+ nextWorkInProgressHook = workInProgressHook = firstWorkInProgressHook = nextCurrentHook = currentHook = currentlyRenderingFiber$1 = null;
+ remainingExpirationTime = 0;
+ componentUpdateQueue = null;
+ sideEffectTag = 0;
+ didScheduleRenderPhaseUpdate = !1;
+ renderPhaseUpdates = null;
+ numberOfReRenders = 0;
+}
+function mountWorkInProgressHook() {
+ var hook = {
+ memoizedState: null,
+ baseState: null,
+ queue: null,
+ baseUpdate: null,
+ next: null
+ };
+ null === workInProgressHook
+ ? (firstWorkInProgressHook = workInProgressHook = hook)
+ : (workInProgressHook = workInProgressHook.next = hook);
+ return workInProgressHook;
+}
+function updateWorkInProgressHook() {
+ if (null !== nextWorkInProgressHook)
+ (workInProgressHook = nextWorkInProgressHook),
+ (nextWorkInProgressHook = workInProgressHook.next),
+ (currentHook = nextCurrentHook),
+ (nextCurrentHook = null !== currentHook ? currentHook.next : null);
+ else {
+ invariant(
+ null !== nextCurrentHook,
+ "Rendered more hooks than during the previous render."
+ );
+ currentHook = nextCurrentHook;
+ var newHook = {
+ memoizedState: currentHook.memoizedState,
+ baseState: currentHook.baseState,
+ queue: currentHook.queue,
+ baseUpdate: currentHook.baseUpdate,
+ next: null
+ };
+ workInProgressHook =
+ null === workInProgressHook
+ ? (firstWorkInProgressHook = newHook)
+ : (workInProgressHook.next = newHook);
+ nextCurrentHook = currentHook.next;
+ }
+ return workInProgressHook;
+}
+function basicStateReducer(state, action) {
+ return "function" === typeof action ? action(state) : action;
+}
+function updateReducer(reducer) {
+ var hook = updateWorkInProgressHook(),
+ queue = hook.queue;
+ invariant(
+ null !== queue,
+ "Should have a queue. This is likely a bug in React. Please file an issue."
+ );
+ if (0 < numberOfReRenders) {
+ var _dispatch = queue.dispatch;
+ if (null !== renderPhaseUpdates) {
+ var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+ if (void 0 !== firstRenderPhaseUpdate) {
+ renderPhaseUpdates.delete(queue);
+ var newState = hook.memoizedState;
+ do
+ (newState = reducer(newState, firstRenderPhaseUpdate.action)),
+ (firstRenderPhaseUpdate = firstRenderPhaseUpdate.next);
+ while (null !== firstRenderPhaseUpdate);
+ 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];
+ }
+ }
+ return [hook.memoizedState, _dispatch];
+ }
+ _dispatch = queue.last;
+ var baseUpdate = hook.baseUpdate;
+ newState = hook.baseState;
+ null !== baseUpdate
+ ? (null !== _dispatch && (_dispatch.next = null),
+ (_dispatch = baseUpdate.next))
+ : (_dispatch = null !== _dispatch ? _dispatch.next : null);
+ if (null !== _dispatch) {
+ var newBaseUpdate = (firstRenderPhaseUpdate = null),
+ _update = _dispatch,
+ didSkip = !1;
+ do {
+ var updateExpirationTime = _update.expirationTime;
+ updateExpirationTime < renderExpirationTime
+ ? (didSkip ||
+ ((didSkip = !0),
+ (newBaseUpdate = baseUpdate),
+ (firstRenderPhaseUpdate = newState)),
+ updateExpirationTime > remainingExpirationTime &&
+ (remainingExpirationTime = updateExpirationTime))
+ : (newState =
+ _update.eagerReducer === reducer
+ ? _update.eagerState
+ : reducer(newState, _update.action));
+ baseUpdate = _update;
+ _update = _update.next;
+ } while (null !== _update && _update !== _dispatch);
+ didSkip ||
+ ((newBaseUpdate = baseUpdate), (firstRenderPhaseUpdate = newState));
+ is(newState, hook.memoizedState) || (didReceiveUpdate = !0);
+ hook.memoizedState = newState;
+ hook.baseUpdate = newBaseUpdate;
+ hook.baseState = firstRenderPhaseUpdate;
+ queue.eagerReducer = reducer;
+ queue.eagerState = newState;
+ }
+ return [hook.memoizedState, queue.dispatch];
+}
+function pushEffect(tag, create, destroy, deps) {
+ tag = { tag: tag, create: create, destroy: destroy, deps: deps, next: null };
+ null === componentUpdateQueue
+ ? ((componentUpdateQueue = { lastEffect: null }),
+ (componentUpdateQueue.lastEffect = tag.next = tag))
+ : ((create = componentUpdateQueue.lastEffect),
+ null === create
+ ? (componentUpdateQueue.lastEffect = tag.next = tag)
+ : ((destroy = create.next),
+ (create.next = tag),
+ (tag.next = destroy),
+ (componentUpdateQueue.lastEffect = tag)));
+ return tag;
+}
+function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) {
+ var hook = mountWorkInProgressHook();
+ sideEffectTag |= fiberEffectTag;
+ hook.memoizedState = pushEffect(
+ hookEffectTag,
+ create,
+ void 0,
+ void 0 === deps ? null : deps
+ );
+}
+function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) {
+ var hook = updateWorkInProgressHook();
+ deps = void 0 === deps ? null : deps;
+ var destroy = void 0;
+ if (null !== currentHook) {
+ var prevEffect = currentHook.memoizedState;
+ destroy = prevEffect.destroy;
+ if (null !== deps && areHookInputsEqual(deps, prevEffect.deps)) {
+ pushEffect(NoEffect$1, create, destroy, deps);
+ return;
+ }
+ }
+ sideEffectTag |= fiberEffectTag;
+ hook.memoizedState = pushEffect(hookEffectTag, create, destroy, deps);
+}
+function imperativeHandleEffect(create, ref) {
+ if ("function" === typeof ref)
+ return (
+ (create = create()),
+ ref(create),
+ function() {
+ ref(null);
+ }
+ );
+ if (null !== ref && void 0 !== ref)
+ return (
+ (create = create()),
+ (ref.current = create),
+ function() {
+ ref.current = null;
+ }
+ );
+}
+function mountDebugValue() {}
+function dispatchAction(fiber, queue, action) {
+ invariant(
+ 25 > numberOfReRenders,
+ "Too many re-renders. React limits the number of renders to prevent an infinite loop."
+ );
+ var alternate = fiber.alternate;
+ if (
+ fiber === currentlyRenderingFiber$1 ||
+ (null !== alternate && alternate === currentlyRenderingFiber$1)
+ )
+ if (
+ ((didScheduleRenderPhaseUpdate = !0),
+ (fiber = {
+ expirationTime: renderExpirationTime,
+ action: action,
+ eagerReducer: null,
+ eagerState: null,
+ next: null
+ }),
+ null === renderPhaseUpdates && (renderPhaseUpdates = new Map()),
+ (action = renderPhaseUpdates.get(queue)),
+ void 0 === action)
+ )
+ renderPhaseUpdates.set(queue, fiber);
+ else {
+ for (queue = action; null !== queue.next; ) queue = queue.next;
+ queue.next = fiber;
+ }
+ else {
+ flushPassiveEffects();
+ var currentTime = requestCurrentTime();
+ currentTime = computeExpirationForFiber(currentTime, fiber);
+ var _update2 = {
+ expirationTime: currentTime,
+ action: action,
+ eagerReducer: null,
+ eagerState: null,
+ next: null
+ },
+ _last = queue.last;
+ if (null === _last) _update2.next = _update2;
+ else {
+ var first = _last.next;
+ null !== first && (_update2.next = first);
+ _last.next = _update2;
+ }
+ queue.last = _update2;
+ if (
+ 0 === fiber.expirationTime &&
+ (null === alternate || 0 === alternate.expirationTime) &&
+ ((alternate = queue.eagerReducer), null !== alternate)
+ )
+ try {
+ var currentState = queue.eagerState,
+ _eagerState = alternate(currentState, action);
+ _update2.eagerReducer = alternate;
+ _update2.eagerState = _eagerState;
+ if (is(_eagerState, currentState)) return;
+ } catch (error) {
+ } finally {
+ }
+ scheduleWork(fiber, currentTime);
+ }
+}
+var ContextOnlyDispatcher = {
+ readContext: readContext,
+ useCallback: throwInvalidHookError,
+ useContext: throwInvalidHookError,
+ useEffect: throwInvalidHookError,
+ useImperativeHandle: throwInvalidHookError,
+ useLayoutEffect: throwInvalidHookError,
+ useMemo: throwInvalidHookError,
+ useReducer: throwInvalidHookError,
+ useRef: throwInvalidHookError,
+ useState: throwInvalidHookError,
+ useDebugValue: throwInvalidHookError
+ },
+ HooksDispatcherOnMount = {
+ readContext: readContext,
+ useCallback: function(callback, deps) {
+ mountWorkInProgressHook().memoizedState = [
+ callback,
+ void 0 === deps ? null : deps
+ ];
+ return callback;
+ },
+ useContext: readContext,
+ useEffect: function(create, deps) {
+ return mountEffectImpl(516, UnmountPassive | MountPassive, create, deps);
+ },
+ useImperativeHandle: function(ref, create, deps) {
+ deps = null !== deps && void 0 !== deps ? deps.concat([ref]) : null;
+ return mountEffectImpl(
+ 4,
+ UnmountMutation | MountLayout,
+ imperativeHandleEffect.bind(null, create, ref),
+ deps
+ );
+ },
+ useLayoutEffect: function(create, deps) {
+ return mountEffectImpl(4, UnmountMutation | MountLayout, create, deps);
+ },
+ useMemo: function(nextCreate, deps) {
+ var hook = mountWorkInProgressHook();
+ deps = void 0 === deps ? null : deps;
+ nextCreate = nextCreate();
+ hook.memoizedState = [nextCreate, deps];
+ return nextCreate;
+ },
+ useReducer: function(reducer, initialArg, init) {
+ var hook = mountWorkInProgressHook();
+ initialArg = void 0 !== init ? init(initialArg) : initialArg;
+ hook.memoizedState = hook.baseState = initialArg;
+ reducer = hook.queue = {
+ last: null,
+ dispatch: null,
+ eagerReducer: reducer,
+ eagerState: initialArg
+ };
+ reducer = reducer.dispatch = dispatchAction.bind(
+ null,
+ currentlyRenderingFiber$1,
+ reducer
+ );
+ return [hook.memoizedState, reducer];
+ },
+ useRef: function(initialValue) {
+ var hook = mountWorkInProgressHook();
+ initialValue = { current: initialValue };
+ return (hook.memoizedState = initialValue);
+ },
+ useState: function(initialState) {
+ var hook = mountWorkInProgressHook();
+ "function" === typeof initialState && (initialState = initialState());
+ hook.memoizedState = hook.baseState = initialState;
+ initialState = hook.queue = {
+ last: null,
+ dispatch: null,
+ eagerReducer: basicStateReducer,
+ eagerState: initialState
+ };
+ initialState = initialState.dispatch = dispatchAction.bind(
+ null,
+ currentlyRenderingFiber$1,
+ initialState
+ );
+ return [hook.memoizedState, initialState];
+ },
+ useDebugValue: mountDebugValue
+ },
+ HooksDispatcherOnUpdate = {
+ readContext: readContext,
+ useCallback: function(callback, deps) {
+ var hook = updateWorkInProgressHook();
+ deps = void 0 === deps ? null : deps;
+ var prevState = hook.memoizedState;
+ if (
+ null !== prevState &&
+ null !== deps &&
+ areHookInputsEqual(deps, prevState[1])
+ )
+ return prevState[0];
+ hook.memoizedState = [callback, deps];
+ return callback;
+ },
+ useContext: readContext,
+ useEffect: function(create, deps) {
+ return updateEffectImpl(516, UnmountPassive | MountPassive, create, deps);
+ },
+ useImperativeHandle: function(ref, create, deps) {
+ deps = null !== deps && void 0 !== deps ? deps.concat([ref]) : null;
+ return updateEffectImpl(
+ 4,
+ UnmountMutation | MountLayout,
+ imperativeHandleEffect.bind(null, create, ref),
+ deps
+ );
+ },
+ useLayoutEffect: function(create, deps) {
+ return updateEffectImpl(4, UnmountMutation | MountLayout, create, deps);
+ },
+ useMemo: function(nextCreate, deps) {
+ var hook = updateWorkInProgressHook();
+ deps = void 0 === deps ? null : deps;
+ var prevState = hook.memoizedState;
+ if (
+ null !== prevState &&
+ null !== deps &&
+ areHookInputsEqual(deps, prevState[1])
+ )
+ return prevState[0];
+ nextCreate = nextCreate();
+ hook.memoizedState = [nextCreate, deps];
+ return nextCreate;
+ },
+ useReducer: updateReducer,
+ useRef: function() {
+ return updateWorkInProgressHook().memoizedState;
+ },
+ useState: function(initialState) {
+ return updateReducer(basicStateReducer, initialState);
+ },
+ useDebugValue: mountDebugValue
+ },
+ commitTime = 0,
+ profilerStartTime = -1;
+function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) {
+ if (0 <= profilerStartTime) {
+ var elapsedTime = now$1() - profilerStartTime;
+ fiber.actualDuration += elapsedTime;
+ overrideBaseTime && (fiber.selfBaseDuration = elapsedTime);
+ profilerStartTime = -1;
+ }
+}
+var hydrationParentFiber = null,
nextHydratableInstance = null,
isHydrating = !1;
function tryHydrate(fiber, nextInstance) {
@@ -3341,6 +3540,8 @@
(nextInstance = shim$1(nextInstance, fiber.pendingProps)),
null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1
);
+ case 13:
+ return !1;
default:
return !1;
}
@@ -3378,7 +3579,8 @@
(hydrationParentFiber = fiber$jscomp$0);
}
}
-var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner;
+var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner,
+ didReceiveUpdate = !1;
function reconcileChildren(
current$$1,
workInProgress,
@@ -3410,7 +3612,26 @@
Component = Component.render;
var ref = workInProgress.ref;
prepareToReadContext(workInProgress, renderExpirationTime);
- nextProps = Component(nextProps, ref);
+ nextProps = renderWithHooks(
+ current$$1,
+ workInProgress,
+ Component,
+ nextProps,
+ ref,
+ renderExpirationTime
+ );
+ if (null !== current$$1 && !didReceiveUpdate)
+ return (
+ (workInProgress.updateQueue = current$$1.updateQueue),
+ (workInProgress.effectTag &= -517),
+ current$$1.expirationTime <= renderExpirationTime &&
+ (current$$1.expirationTime = 0),
+ bailoutOnAlreadyFinishedWork(
+ current$$1,
+ workInProgress,
+ renderExpirationTime
+ )
+ );
workInProgress.effectTag |= 1;
reconcileChildren(
current$$1,
@@ -3490,9 +3711,9 @@
renderExpirationTime
) {
return null !== current$$1 &&
- updateExpirationTime < renderExpirationTime &&
shallowEqual(current$$1.memoizedProps, nextProps) &&
- current$$1.ref === workInProgress.ref
+ current$$1.ref === workInProgress.ref &&
+ ((didReceiveUpdate = !1), updateExpirationTime < renderExpirationTime)
? bailoutOnAlreadyFinishedWork(
current$$1,
workInProgress,
@@ -3526,7 +3747,26 @@
: contextStackCursor.current;
unmaskedContext = getMaskedContext(workInProgress, unmaskedContext);
prepareToReadContext(workInProgress, renderExpirationTime);
- Component = Component(nextProps, unmaskedContext);
+ Component = renderWithHooks(
+ current$$1,
+ workInProgress,
+ Component,
+ nextProps,
+ unmaskedContext,
+ renderExpirationTime
+ );
+ if (null !== current$$1 && !didReceiveUpdate)
+ return (
+ (workInProgress.updateQueue = current$$1.updateQueue),
+ (workInProgress.effectTag &= -517),
+ current$$1.expirationTime <= renderExpirationTime &&
+ (current$$1.expirationTime = 0),
+ bailoutOnAlreadyFinishedWork(
+ current$$1,
+ workInProgress,
+ renderExpirationTime
+ )
+ );
workInProgress.effectTag |= 1;
reconcileChildren(
current$$1,
@@ -3573,9 +3813,7 @@
var oldContext = instance.context,
contextType = Component.contextType;
"object" === typeof contextType && null !== contextType
- ? (contextType = ReactCurrentOwner$4.currentDispatcher.readContext(
- contextType
- ))
+ ? (contextType = readContext(contextType))
: ((contextType = isContextProvider(Component)
? previousContext
: contextStackCursor.current),
@@ -3660,9 +3898,7 @@
(oldContext = instance.context),
(contextType = Component.contextType),
"object" === typeof contextType && null !== contextType
- ? (contextType = ReactCurrentOwner$4.currentDispatcher.readContext(
- contextType
- ))
+ ? (contextType = readContext(contextType))
: ((contextType = isContextProvider(Component)
? previousContext
: contextStackCursor.current),
@@ -3848,39 +4084,41 @@
(nextDidTimeout = !0),
(workInProgress.effectTag &= -65);
if (null === current$$1)
- nextDidTimeout
- ? ((nextDidTimeout = nextProps.fallback),
- (nextProps = createFiberFromFragment(null, mode, 0, null)),
+ if (nextDidTimeout) {
+ var nextFallbackChildren = nextProps.fallback;
+ current$$1 = createFiberFromFragment(null, mode, 0, null);
0 === (workInProgress.mode & 1) &&
- (nextProps.child =
+ (current$$1.child =
null !== workInProgress.memoizedState
? workInProgress.child.child
- : workInProgress.child),
- (renderExpirationTime = createFiberFromFragment(
- nextDidTimeout,
+ : workInProgress.child);
+ renderExpirationTime = createFiberFromFragment(
+ nextFallbackChildren,
mode,
renderExpirationTime,
null
- )),
- (nextProps.sibling = renderExpirationTime),
- (mode = nextProps),
- (mode.return = renderExpirationTime.return = workInProgress))
- : (mode = renderExpirationTime = mountChildFibers(
+ );
+ current$$1.sibling = renderExpirationTime;
+ mode = current$$1;
+ mode.return = renderExpirationTime.return = workInProgress;
+ } else
+ mode = renderExpirationTime = mountChildFibers(
workInProgress,
null,
nextProps.children,
renderExpirationTime
- ));
- else if (null !== current$$1.memoizedState)
+ );
+ else {
+ if (null !== current$$1.memoizedState)
if (
- ((current$$1 = current$$1.child),
- (mode = current$$1.sibling),
+ ((nextFallbackChildren = current$$1.child),
+ (mode = nextFallbackChildren.sibling),
nextDidTimeout)
) {
nextProps = nextProps.fallback;
renderExpirationTime = createWorkInProgress(
- current$$1,
- current$$1.pendingProps,
+ nextFallbackChildren,
+ nextFallbackChildren.pendingProps,
0
);
0 === (workInProgress.mode & 1) &&
@@ -3888,64 +4126,77 @@
null !== workInProgress.memoizedState
? workInProgress.child.child
: workInProgress.child),
- nextDidTimeout !== current$$1.child &&
+ nextDidTimeout !== nextFallbackChildren.child &&
(renderExpirationTime.child = nextDidTimeout));
if (workInProgress.mode & 4) {
- nextDidTimeout = 0;
- for (current$$1 = renderExpirationTime.child; null !== current$$1; )
- (nextDidTimeout += current$$1.treeBaseDuration),
- (current$$1 = current$$1.sibling);
- renderExpirationTime.treeBaseDuration = nextDidTimeout;
+ nextFallbackChildren = 0;
+ for (
+ nextDidTimeout = renderExpirationTime.child;
+ null !== nextDidTimeout;
+
+ )
+ (nextFallbackChildren += nextDidTimeout.treeBaseDuration),
+ (nextDidTimeout = nextDidTimeout.sibling);
+ renderExpirationTime.treeBaseDuration = nextFallbackChildren;
}
- nextProps = renderExpirationTime.sibling = createWorkInProgress(
+ nextFallbackChildren = renderExpirationTime.sibling = createWorkInProgress(
mode,
nextProps,
mode.expirationTime
);
mode = renderExpirationTime;
renderExpirationTime.childExpirationTime = 0;
- renderExpirationTime = nextProps;
+ renderExpirationTime = nextFallbackChildren;
mode.return = renderExpirationTime.return = workInProgress;
} else
mode = renderExpirationTime = reconcileChildFibers(
workInProgress,
- current$$1.child,
+ nextFallbackChildren.child,
nextProps.children,
renderExpirationTime
);
- else if (((current$$1 = current$$1.child), nextDidTimeout)) {
- nextDidTimeout = nextProps.fallback;
- nextProps = createFiberFromFragment(null, mode, 0, null);
- nextProps.child = current$$1;
+ else {
+ var _currentPrimaryChild = current$$1.child;
+ if (nextDidTimeout) {
+ nextProps = nextProps.fallback;
+ nextFallbackChildren = createFiberFromFragment(null, mode, 0, null);
+ nextFallbackChildren.child = _currentPrimaryChild;
0 === (workInProgress.mode & 1) &&
- (nextProps.child =
+ (nextFallbackChildren.child =
null !== workInProgress.memoizedState
? workInProgress.child.child
: workInProgress.child);
if (workInProgress.mode & 4) {
- current$$1 = 0;
- for (var _hiddenChild = nextProps.child; null !== _hiddenChild; )
- (current$$1 += _hiddenChild.treeBaseDuration),
- (_hiddenChild = _hiddenChild.sibling);
- nextProps.treeBaseDuration = current$$1;
+ nextDidTimeout = 0;
+ for (
+ _currentPrimaryChild = nextFallbackChildren.child;
+ null !== _currentPrimaryChild;
+
+ )
+ (nextDidTimeout += _currentPrimaryChild.treeBaseDuration),
+ (_currentPrimaryChild = _currentPrimaryChild.sibling);
+ nextFallbackChildren.treeBaseDuration = nextDidTimeout;
}
- renderExpirationTime = nextProps.sibling = createFiberFromFragment(
- nextDidTimeout,
+ renderExpirationTime = nextFallbackChildren.sibling = createFiberFromFragment(
+ nextProps,
mode,
renderExpirationTime,
null
);
renderExpirationTime.effectTag |= 2;
- mode = nextProps;
- nextProps.childExpirationTime = 0;
+ mode = nextFallbackChildren;
+ nextFallbackChildren.childExpirationTime = 0;
mode.return = renderExpirationTime.return = workInProgress;
} else
renderExpirationTime = mode = reconcileChildFibers(
workInProgress,
- current$$1,
+ _currentPrimaryChild,
nextProps.children,
renderExpirationTime
);
+ }
+ workInProgress.stateNode = current$$1.stateNode;
+ }
workInProgress.memoizedState = nextState;
workInProgress.child = mode;
return renderExpirationTime;
@@ -3956,7 +4207,7 @@
renderExpirationTime
) {
null !== current$$1 &&
- (workInProgress.firstContextDependency = current$$1.firstContextDependency);
+ (workInProgress.contextDependencies = current$$1.contextDependencies);
profilerStartTime = -1;
if (workInProgress.childExpirationTime < renderExpirationTime) return null;
invariant(
@@ -3989,12 +4240,15 @@
}
function beginWork(current$$1, workInProgress, renderExpirationTime) {
var updateExpirationTime = workInProgress.expirationTime;
+ if (null !== current$$1)
if (
- null !== current$$1 &&
- current$$1.memoizedProps === workInProgress.pendingProps &&
- !didPerformWorkStackCursor.current &&
- updateExpirationTime < renderExpirationTime
- ) {
+ current$$1.memoizedProps !== workInProgress.pendingProps ||
+ didPerformWorkStackCursor.current
+ )
+ didReceiveUpdate = !0;
+ else {
+ if (updateExpirationTime < renderExpirationTime) {
+ didReceiveUpdate = !1;
switch (workInProgress.tag) {
case 3:
pushHostRootContext(workInProgress);
@@ -4044,6 +4298,8 @@
renderExpirationTime
);
}
+ }
+ else didReceiveUpdate = !1;
workInProgress.expirationTime = 0;
switch (workInProgress.tag) {
case 2:
@@ -4058,7 +4314,14 @@
contextStackCursor.current
);
prepareToReadContext(workInProgress, renderExpirationTime);
- context = updateExpirationTime(current$$1, context);
+ context = renderWithHooks(
+ null,
+ workInProgress,
+ updateExpirationTime,
+ current$$1,
+ context,
+ renderExpirationTime
+ );
workInProgress.effectTag |= 1;
if (
"object" === typeof context &&
@@ -4067,6 +4330,7 @@
void 0 === context.$$typeof
) {
workInProgress.tag = 1;
+ resetHooks();
if (isContextProvider(updateExpirationTime)) {
var hasContext = !0;
pushContextProvider(workInProgress);
@@ -4339,13 +4603,9 @@
pushProvider(workInProgress, hasContext);
if (null !== getDerivedStateFromProps) {
var oldValue = getDerivedStateFromProps.value;
- hasContext =
- (oldValue === hasContext &&
- (0 !== oldValue || 1 / oldValue === 1 / hasContext)) ||
- (oldValue !== oldValue && hasContext !== hasContext)
+ hasContext = is(oldValue, hasContext)
? 0
- : ("function" ===
- typeof updateExpirationTime._calculateChangedBits
+ : ("function" === typeof updateExpirationTime._calculateChangedBits
? updateExpirationTime._calculateChangedBits(
oldValue,
hasContext
@@ -4365,83 +4625,79 @@
}
} else
for (
- getDerivedStateFromProps = workInProgress.child,
- null !== getDerivedStateFromProps &&
- (getDerivedStateFromProps.return = workInProgress);
- null !== getDerivedStateFromProps;
+ oldValue = workInProgress.child,
+ null !== oldValue && (oldValue.return = workInProgress);
+ null !== oldValue;
) {
- oldValue = getDerivedStateFromProps.firstContextDependency;
- if (null !== oldValue) {
- do {
- if (
- oldValue.context === updateExpirationTime &&
- 0 !== (oldValue.observedBits & hasContext)
- ) {
- if (1 === getDerivedStateFromProps.tag) {
- var nextFiber = createUpdate(renderExpirationTime);
- nextFiber.tag = 2;
- enqueueUpdate(getDerivedStateFromProps, nextFiber);
- }
- getDerivedStateFromProps.expirationTime <
- renderExpirationTime &&
- (getDerivedStateFromProps.expirationTime = renderExpirationTime);
- nextFiber = getDerivedStateFromProps.alternate;
- null !== nextFiber &&
- nextFiber.expirationTime < renderExpirationTime &&
- (nextFiber.expirationTime = renderExpirationTime);
- for (
- var node = getDerivedStateFromProps.return;
- null !== node;
-
- ) {
- nextFiber = node.alternate;
- if (node.childExpirationTime < renderExpirationTime)
- (node.childExpirationTime = renderExpirationTime),
- null !== nextFiber &&
- nextFiber.childExpirationTime <
- renderExpirationTime &&
- (nextFiber.childExpirationTime = renderExpirationTime);
+ var list = oldValue.contextDependencies;
+ if (null !== list) {
+ getDerivedStateFromProps = oldValue.child;
+ for (var dependency = list.first; null !== dependency; ) {
+ if (
+ dependency.context === updateExpirationTime &&
+ 0 !== (dependency.observedBits & hasContext)
+ ) {
+ 1 === oldValue.tag &&
+ ((dependency = createUpdate(renderExpirationTime)),
+ (dependency.tag = ForceUpdate),
+ enqueueUpdate(oldValue, dependency));
+ oldValue.expirationTime < renderExpirationTime &&
+ (oldValue.expirationTime = renderExpirationTime);
+ dependency = oldValue.alternate;
+ null !== dependency &&
+ dependency.expirationTime < renderExpirationTime &&
+ (dependency.expirationTime = renderExpirationTime);
+ dependency = renderExpirationTime;
+ for (var node = oldValue.return; null !== node; ) {
+ var alternate = node.alternate;
+ if (node.childExpirationTime < dependency)
+ (node.childExpirationTime = dependency),
+ null !== alternate &&
+ alternate.childExpirationTime < dependency &&
+ (alternate.childExpirationTime = dependency);
else if (
- null !== nextFiber &&
- nextFiber.childExpirationTime < renderExpirationTime
+ null !== alternate &&
+ alternate.childExpirationTime < dependency
)
- nextFiber.childExpirationTime = renderExpirationTime;
+ alternate.childExpirationTime = dependency;
else break;
node = node.return;
}
+ list.expirationTime < renderExpirationTime &&
+ (list.expirationTime = renderExpirationTime);
+ break;
+ }
+ dependency = dependency.next;
}
- nextFiber = getDerivedStateFromProps.child;
- oldValue = oldValue.next;
- } while (null !== oldValue);
} else
- nextFiber =
- 10 === getDerivedStateFromProps.tag
- ? getDerivedStateFromProps.type === workInProgress.type
+ getDerivedStateFromProps =
+ 10 === oldValue.tag
+ ? oldValue.type === workInProgress.type
? null
- : getDerivedStateFromProps.child
- : getDerivedStateFromProps.child;
- if (null !== nextFiber)
- nextFiber.return = getDerivedStateFromProps;
+ : oldValue.child
+ : oldValue.child;
+ if (null !== getDerivedStateFromProps)
+ getDerivedStateFromProps.return = oldValue;
else
for (
- nextFiber = getDerivedStateFromProps;
- null !== nextFiber;
+ getDerivedStateFromProps = oldValue;
+ null !== getDerivedStateFromProps;
) {
- if (nextFiber === workInProgress) {
- nextFiber = null;
+ if (getDerivedStateFromProps === workInProgress) {
+ getDerivedStateFromProps = null;
break;
}
- getDerivedStateFromProps = nextFiber.sibling;
- if (null !== getDerivedStateFromProps) {
- getDerivedStateFromProps.return = nextFiber.return;
- nextFiber = getDerivedStateFromProps;
+ oldValue = getDerivedStateFromProps.sibling;
+ if (null !== oldValue) {
+ oldValue.return = getDerivedStateFromProps.return;
+ getDerivedStateFromProps = oldValue;
break;
}
- nextFiber = nextFiber.return;
+ getDerivedStateFromProps = getDerivedStateFromProps.return;
}
- getDerivedStateFromProps = nextFiber;
+ oldValue = getDerivedStateFromProps;
}
}
reconcileChildren(
@@ -4534,12 +4790,296 @@
renderExpirationTime
)
);
- default:
+ }
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,
+ lastContextDependency = null,
+ lastContextWithAllBitsObserved = null;
+function pushProvider(providerFiber, nextValue) {
+ var context = providerFiber.type._context;
+ push(valueCursor, context._currentValue2, providerFiber);
+ context._currentValue2 = nextValue;
+}
+function popProvider(providerFiber) {
+ var currentValue = valueCursor.current;
+ pop(valueCursor, providerFiber);
+ providerFiber.type._context._currentValue2 = currentValue;
+}
+function prepareToReadContext(workInProgress, renderExpirationTime) {
+ currentlyRenderingFiber = workInProgress;
+ lastContextWithAllBitsObserved = lastContextDependency = null;
+ var currentDependencies = workInProgress.contextDependencies;
+ null !== currentDependencies &&
+ currentDependencies.expirationTime >= renderExpirationTime &&
+ (didReceiveUpdate = !0);
+ workInProgress.contextDependencies = null;
+}
+function readContext(context, observedBits) {
+ if (
+ lastContextWithAllBitsObserved !== context &&
+ !1 !== observedBits &&
+ 0 !== observedBits
+ ) {
+ if ("number" !== typeof observedBits || 1073741823 === observedBits)
+ (lastContextWithAllBitsObserved = context), (observedBits = 1073741823);
+ observedBits = { context: context, observedBits: observedBits, next: null };
+ null === lastContextDependency
+ ? (invariant(
+ null !== currentlyRenderingFiber,
+ "Context can only be read while React is rendering. In classes, you can read it in the render method or getDerivedStateFromProps. In function components, you can read it directly in the function body, but not inside Hooks like useReducer() or useMemo()."
+ ),
+ (lastContextDependency = observedBits),
+ (currentlyRenderingFiber.contextDependencies = {
+ first: observedBits,
+ expirationTime: 0
+ }))
+ : (lastContextDependency = lastContextDependency.next = observedBits);
+ }
+ return context._currentValue2;
+}
+var UpdateState = 0,
+ ReplaceState = 1,
+ ForceUpdate = 2,
+ CaptureUpdate = 3,
+ hasForceUpdate = !1;
+function createUpdateQueue(baseState) {
+ return {
+ baseState: baseState,
+ firstUpdate: null,
+ lastUpdate: null,
+ firstCapturedUpdate: null,
+ lastCapturedUpdate: null,
+ firstEffect: null,
+ lastEffect: null,
+ firstCapturedEffect: null,
+ lastCapturedEffect: null
+ };
+}
+function cloneUpdateQueue(currentQueue) {
+ return {
+ baseState: currentQueue.baseState,
+ firstUpdate: currentQueue.firstUpdate,
+ lastUpdate: currentQueue.lastUpdate,
+ firstCapturedUpdate: null,
+ lastCapturedUpdate: null,
+ firstEffect: null,
+ lastEffect: null,
+ firstCapturedEffect: null,
+ lastCapturedEffect: null
+ };
+}
+function createUpdate(expirationTime) {
+ return {
+ expirationTime: expirationTime,
+ tag: UpdateState,
+ payload: null,
+ callback: null,
+ next: null,
+ nextEffect: null
+ };
+}
+function appendUpdateToQueue(queue, update) {
+ null === queue.lastUpdate
+ ? (queue.firstUpdate = queue.lastUpdate = update)
+ : ((queue.lastUpdate.next = update), (queue.lastUpdate = update));
+}
+function enqueueUpdate(fiber, update) {
+ var alternate = fiber.alternate;
+ if (null === alternate) {
+ var queue1 = fiber.updateQueue;
+ var queue2 = null;
+ null === queue1 &&
+ (queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState));
+ } else
+ (queue1 = fiber.updateQueue),
+ (queue2 = alternate.updateQueue),
+ null === queue1
+ ? null === queue2
+ ? ((queue1 = fiber.updateQueue = createUpdateQueue(
+ fiber.memoizedState
+ )),
+ (queue2 = alternate.updateQueue = createUpdateQueue(
+ alternate.memoizedState
+ )))
+ : (queue1 = fiber.updateQueue = cloneUpdateQueue(queue2))
+ : null === queue2 &&
+ (queue2 = alternate.updateQueue = cloneUpdateQueue(queue1));
+ null === queue2 || queue1 === queue2
+ ? appendUpdateToQueue(queue1, update)
+ : null === queue1.lastUpdate || null === queue2.lastUpdate
+ ? (appendUpdateToQueue(queue1, update),
+ appendUpdateToQueue(queue2, update))
+ : (appendUpdateToQueue(queue1, update), (queue2.lastUpdate = update));
+}
+function enqueueCapturedUpdate(workInProgress, update) {
+ var workInProgressQueue = workInProgress.updateQueue;
+ workInProgressQueue =
+ null === workInProgressQueue
+ ? (workInProgress.updateQueue = createUpdateQueue(
+ workInProgress.memoizedState
+ ))
+ : ensureWorkInProgressQueueIsAClone(workInProgress, workInProgressQueue);
+ null === workInProgressQueue.lastCapturedUpdate
+ ? (workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update)
+ : ((workInProgressQueue.lastCapturedUpdate.next = update),
+ (workInProgressQueue.lastCapturedUpdate = update));
+}
+function ensureWorkInProgressQueueIsAClone(workInProgress, queue) {
+ var current = workInProgress.alternate;
+ null !== current &&
+ queue === current.updateQueue &&
+ (queue = workInProgress.updateQueue = cloneUpdateQueue(queue));
+ return queue;
+}
+function getStateFromUpdate(
+ workInProgress,
+ queue,
+ update,
+ prevState,
+ nextProps,
+ instance
+) {
+ switch (update.tag) {
+ case ReplaceState:
+ return (
+ (workInProgress = update.payload),
+ "function" === typeof workInProgress
+ ? workInProgress.call(instance, prevState, nextProps)
+ : workInProgress
+ );
+ case CaptureUpdate:
+ workInProgress.effectTag = (workInProgress.effectTag & -2049) | 64;
+ case UpdateState:
+ workInProgress = update.payload;
+ nextProps =
+ "function" === typeof workInProgress
+ ? workInProgress.call(instance, prevState, nextProps)
+ : workInProgress;
+ if (null === nextProps || void 0 === nextProps) break;
+ return Object.assign({}, prevState, nextProps);
+ case ForceUpdate:
+ hasForceUpdate = !0;
+ }
+ return prevState;
+}
+function processUpdateQueue(
+ workInProgress,
+ queue,
+ props,
+ instance,
+ renderExpirationTime
+) {
+ hasForceUpdate = !1;
+ queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue);
+ for (
+ var newBaseState = queue.baseState,
+ newFirstUpdate = null,
+ newExpirationTime = 0,
+ update = queue.firstUpdate,
+ resultState = newBaseState;
+ null !== update;
+
+ ) {
+ var updateExpirationTime = update.expirationTime;
+ updateExpirationTime < renderExpirationTime
+ ? (null === newFirstUpdate &&
+ ((newFirstUpdate = update), (newBaseState = resultState)),
+ newExpirationTime < updateExpirationTime &&
+ (newExpirationTime = updateExpirationTime))
+ : ((resultState = getStateFromUpdate(
+ workInProgress,
+ queue,
+ update,
+ resultState,
+ props,
+ instance
+ )),
+ null !== update.callback &&
+ ((workInProgress.effectTag |= 32),
+ (update.nextEffect = null),
+ null === queue.lastEffect
+ ? (queue.firstEffect = queue.lastEffect = update)
+ : ((queue.lastEffect.nextEffect = update),
+ (queue.lastEffect = update))));
+ update = update.next;
+ }
+ updateExpirationTime = null;
+ for (update = queue.firstCapturedUpdate; null !== update; ) {
+ var _updateExpirationTime = update.expirationTime;
+ _updateExpirationTime < renderExpirationTime
+ ? (null === updateExpirationTime &&
+ ((updateExpirationTime = update),
+ null === newFirstUpdate && (newBaseState = resultState)),
+ newExpirationTime < _updateExpirationTime &&
+ (newExpirationTime = _updateExpirationTime))
+ : ((resultState = getStateFromUpdate(
+ workInProgress,
+ queue,
+ update,
+ resultState,
+ props,
+ instance
+ )),
+ null !== update.callback &&
+ ((workInProgress.effectTag |= 32),
+ (update.nextEffect = null),
+ null === queue.lastCapturedEffect
+ ? (queue.firstCapturedEffect = queue.lastCapturedEffect = update)
+ : ((queue.lastCapturedEffect.nextEffect = update),
+ (queue.lastCapturedEffect = update))));
+ update = update.next;
}
+ null === newFirstUpdate && (queue.lastUpdate = null);
+ null === updateExpirationTime
+ ? (queue.lastCapturedUpdate = null)
+ : (workInProgress.effectTag |= 32);
+ null === newFirstUpdate &&
+ null === updateExpirationTime &&
+ (newBaseState = resultState);
+ queue.baseState = newBaseState;
+ queue.firstUpdate = newFirstUpdate;
+ queue.firstCapturedUpdate = updateExpirationTime;
+ workInProgress.expirationTime = newExpirationTime;
+ workInProgress.memoizedState = resultState;
+}
+function commitUpdateQueue(finishedWork, finishedQueue, instance) {
+ null !== finishedQueue.firstCapturedUpdate &&
+ (null !== finishedQueue.lastUpdate &&
+ ((finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate),
+ (finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate)),
+ (finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null));
+ commitUpdateEffects(finishedQueue.firstEffect, instance);
+ finishedQueue.firstEffect = finishedQueue.lastEffect = null;
+ commitUpdateEffects(finishedQueue.firstCapturedEffect, instance);
+ finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null;
+}
+function commitUpdateEffects(effect, instance) {
+ for (; null !== effect; ) {
+ var _callback3 = effect.callback;
+ if (null !== _callback3) {
+ effect.callback = null;
+ var context = instance;
+ invariant(
+ "function" === typeof _callback3,
+ "Invalid argument passed as callback. Expected a function. Instead received: %s",
+ _callback3
+ );
+ _callback3.call(context);
+ }
+ effect = effect.nextEffect;
+ }
+}
+function createCapturedValue(value, source) {
+ return {
+ value: value,
+ source: source,
+ stack: getStackByFiberInDevAndProd(source)
+ };
}
var appendAllChildren = void 0,
updateHostContainer = void 0,
@@ -4784,12 +5324,30 @@
}
else ref.current = null;
}
+function commitHookEffectList(unmountTag, mountTag, finishedWork) {
+ finishedWork = finishedWork.updateQueue;
+ finishedWork = null !== finishedWork ? finishedWork.lastEffect : null;
+ if (null !== finishedWork) {
+ var effect = (finishedWork = finishedWork.next);
+ do {
+ if ((effect.tag & unmountTag) !== NoEffect$1) {
+ var destroy = effect.destroy;
+ effect.destroy = void 0;
+ void 0 !== destroy && destroy();
+ }
+ (effect.tag & mountTag) !== NoEffect$1 &&
+ ((destroy = effect.create), (effect.destroy = destroy()));
+ effect = effect.next;
+ } while (effect !== finishedWork);
+ }
+}
function commitWork(current$$1, finishedWork) {
switch (finishedWork.tag) {
case 0:
case 11:
case 14:
case 15:
+ commitHookEffectList(UnmountMutation, MountMutation, finishedWork);
return;
}
switch (finishedWork.tag) {
@@ -4809,9 +5367,10 @@
);
}
}
+var PossiblyWeakMap = "function" === typeof WeakMap ? WeakMap : Map;
function createRootErrorUpdate(fiber, errorInfo, expirationTime) {
expirationTime = createUpdate(expirationTime);
- expirationTime.tag = 3;
+ expirationTime.tag = CaptureUpdate;
expirationTime.payload = { element: null };
var error = errorInfo.value;
expirationTime.callback = function() {
@@ -4822,7 +5381,7 @@
}
function createClassErrorUpdate(fiber, errorInfo, expirationTime) {
expirationTime = createUpdate(expirationTime);
- expirationTime.tag = 3;
+ expirationTime.tag = CaptureUpdate;
var getDerivedStateFromError = fiber.type.getDerivedStateFromError;
if ("function" === typeof getDerivedStateFromError) {
var error$jscomp$0 = errorInfo.value;
@@ -4891,24 +5450,44 @@
? !1
: null === value.memoizedState;
if (current$$1) {
- returnFiber = retrySuspendedRoot.bind(
- null,
- root,
- value,
- sourceFiber,
- 0 === (value.mode & 1) ? 1073741823 : renderExpirationTime
- );
- returnFiber = tracing.unstable_wrap(returnFiber);
- thenable.then(returnFiber, returnFiber);
+ returnFiber = value.updateQueue;
+ null === returnFiber
+ ? ((returnFiber = new Set()),
+ returnFiber.add(thenable),
+ (value.updateQueue = returnFiber))
+ : returnFiber.add(thenable);
if (0 === (value.mode & 1)) {
value.effectTag |= 64;
sourceFiber.effectTag &= -1957;
1 === sourceFiber.tag &&
- null === sourceFiber.alternate &&
- (sourceFiber.tag = 17);
- sourceFiber.expirationTime = renderExpirationTime;
+ (null === sourceFiber.alternate
+ ? (sourceFiber.tag = 17)
+ : ((renderExpirationTime = createUpdate(1073741823)),
+ (renderExpirationTime.tag = ForceUpdate),
+ enqueueUpdate(sourceFiber, renderExpirationTime)));
+ sourceFiber.expirationTime = 1073741823;
return;
}
+ 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,
+ sourceFiber,
+ thenable,
+ returnFiber
+ )),
+ (sourceFiber = tracing.unstable_wrap(sourceFiber)),
+ thenable.then(sourceFiber, sourceFiber));
-1 === earliestTimeoutMs
? (root = 1073741823)
: (-1 === startTimeMs &&
@@ -4942,33 +5521,32 @@
do {
switch (root.tag) {
case 3:
- sourceFiber = value;
root.effectTag |= 2048;
root.expirationTime = renderExpirationTime;
renderExpirationTime = createRootErrorUpdate(
root,
- sourceFiber,
+ value,
renderExpirationTime
);
enqueueCapturedUpdate(root, renderExpirationTime);
return;
case 1:
if (
- ((sourceFiber = value),
- (returnFiber = root.type),
- (thenable = root.stateNode),
+ ((earliestTimeoutMs = value),
+ (startTimeMs = root.type),
+ (sourceFiber = root.stateNode),
0 === (root.effectTag & 64) &&
- ("function" === typeof returnFiber.getDerivedStateFromError ||
- (null !== thenable &&
- "function" === typeof thenable.componentDidCatch &&
+ ("function" === typeof startTimeMs.getDerivedStateFromError ||
+ (null !== sourceFiber &&
+ "function" === typeof sourceFiber.componentDidCatch &&
(null === legacyErrorBoundariesThatAlreadyFailed ||
- !legacyErrorBoundariesThatAlreadyFailed.has(thenable)))))
+ !legacyErrorBoundariesThatAlreadyFailed.has(sourceFiber)))))
) {
root.effectTag |= 2048;
root.expirationTime = renderExpirationTime;
renderExpirationTime = createClassErrorUpdate(
root,
- sourceFiber,
+ earliestTimeoutMs,
renderExpirationTime
);
enqueueCapturedUpdate(root, renderExpirationTime);
@@ -5009,6 +5587,8 @@
workInProgress)
: null
);
+ case 18:
+ return null;
case 4:
return popHostContainer(workInProgress), null;
case 10:
@@ -5017,7 +5597,7 @@
return null;
}
}
-var DispatcherWithoutHooks = { readContext: readContext },
+var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher,
ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner;
invariant(
null != tracing.__interactionsRef &&
@@ -5032,6 +5612,7 @@
nextRenderDidError = !1,
nextEffect = null,
isCommitting$1 = !1,
+ rootWithPendingPassiveEffects = null,
passiveEffectCallbackHandle = null,
passiveEffectCallback = null,
legacyErrorBoundariesThatAlreadyFailed = null;
@@ -5114,7 +5695,7 @@
var effect = (updateQueue = updateQueue.next);
do {
var destroy = effect.destroy;
- if (null !== destroy) {
+ if (void 0 !== destroy) {
var current$$1$jscomp$1 = current$$1$jscomp$0;
try {
destroy();
@@ -5182,6 +5763,7 @@
case 0:
case 11:
case 15:
+ commitHookEffectList(UnmountSnapshot, NoEffect$1, finishedWork);
break a;
case 1:
if (finishedWork.effectTag & 256 && null !== current$$1) {
@@ -5228,6 +5810,7 @@
case 0:
case 11:
case 15:
+ commitHookEffectList(UnmountLayout, MountLayout, finishedWork);
break;
case 1:
finishedRoot = finishedWork.stateNode;
@@ -5311,23 +5894,54 @@
);
}
}
- if (effectTag & 128 && ((effectTag = nextEffect.ref), null !== effectTag)) {
- finishedWork = nextEffect.stateNode;
+ if (
+ effectTag & 128 &&
+ ((finishedWork = nextEffect.ref), null !== finishedWork)
+ ) {
+ committedExpirationTime = nextEffect.stateNode;
switch (nextEffect.tag) {
case 5:
- finishedWork = finishedWork.canonical;
+ committedExpirationTime = committedExpirationTime.canonical;
}
- "function" === typeof effectTag
- ? effectTag(finishedWork)
- : (effectTag.current = finishedWork);
+ "function" === typeof finishedWork
+ ? finishedWork(committedExpirationTime)
+ : (finishedWork.current = committedExpirationTime);
}
+ effectTag & 512 && (rootWithPendingPassiveEffects = finishedRoot$jscomp$0);
nextEffect = nextEffect.nextEffect;
}
}
+function commitPassiveEffects(root, firstEffect) {
+ passiveEffectCallback = passiveEffectCallbackHandle = rootWithPendingPassiveEffects = null;
+ var previousIsRendering = isRendering;
+ isRendering = !0;
+ do {
+ if (firstEffect.effectTag & 512) {
+ var didError = !1,
+ error = void 0;
+ try {
+ var finishedWork = firstEffect;
+ commitHookEffectList(UnmountPassive, NoEffect$1, finishedWork);
+ commitHookEffectList(NoEffect$1, MountPassive, finishedWork);
+ } catch (e) {
+ (didError = !0), (error = e);
+ }
+ didError && captureCommitPhaseError(firstEffect, error);
+ }
+ firstEffect = firstEffect.nextEffect;
+ } while (null !== firstEffect);
+ isRendering = previousIsRendering;
+ previousIsRendering = root.expirationTime;
+ 0 !== previousIsRendering && requestWork(root, previousIsRendering);
+ isBatchingUpdates || isRendering || performWork(1073741823, !1);
+}
function flushPassiveEffects() {
- null !== passiveEffectCallback &&
- (scheduler.unstable_cancelCallback(passiveEffectCallbackHandle),
- passiveEffectCallback());
+ if (null !== passiveEffectCallbackHandle) {
+ var callbackID = passiveEffectCallbackHandle;
+ scheduledCallback = null;
+ clearTimeout(callbackID);
+ }
+ null !== passiveEffectCallback && passiveEffectCallback();
}
function commitRoot(root, finishedWork) {
isCommitting$1 = isWorking = !0;
@@ -5395,21 +6009,39 @@
}
root.current = finishedWork;
for (nextEffect = childExpirationTimeBeforeCommit; null !== nextEffect; ) {
- childExpirationTimeBeforeCommit = !1;
- didError = void 0;
+ didError = !1;
+ error$jscomp$0 = void 0;
try {
commitAllLifeCycles(root, committedExpirationTime);
} catch (e) {
- (childExpirationTimeBeforeCommit = !0), (didError = e);
+ (didError = !0), (error$jscomp$0 = e);
}
- childExpirationTimeBeforeCommit &&
+ didError &&
(invariant(
null !== nextEffect,
"Should have next effect. This error is likely caused by a bug in React. Please file an issue."
),
- captureCommitPhaseError(nextEffect, didError),
+ captureCommitPhaseError(nextEffect, error$jscomp$0),
null !== nextEffect && (nextEffect = nextEffect.nextEffect));
}
+ if (
+ null !== childExpirationTimeBeforeCommit &&
+ null !== rootWithPendingPassiveEffects
+ ) {
+ var callback = commitPassiveEffects.bind(
+ null,
+ root,
+ childExpirationTimeBeforeCommit
+ );
+ callback = tracing.unstable_wrap(callback);
+ passiveEffectCallbackHandle = scheduler.unstable_runWithPriority(
+ scheduler.unstable_NormalPriority,
+ function() {
+ return scheduleDeferredCallback$1(callback);
+ }
+ );
+ passiveEffectCallback = callback;
+ }
isWorking = isCommitting$1 = !1;
"function" === typeof onCommitFiberRoot &&
onCommitFiberRoot(finishedWork.stateNode);
@@ -5594,11 +6226,7 @@
: ((current$$1.firstEffect = current$$1.lastEffect = current),
(current.nextEffect = null)),
(current.effectTag = 8)));
- if (
- fiber !== renderExpirationTime ||
- (0 === (current$$1.effectTag & 1) && fiber)
- )
- current$$1.effectTag |= 4;
+ if (fiber || renderExpirationTime) current$$1.effectTag |= 4;
break;
case 7:
break;
@@ -5620,6 +6248,8 @@
case 17:
isContextProvider(current$$1.type) && popContext(current$$1);
break;
+ case 18:
+ break;
default:
invariant(
!1,
@@ -5718,7 +6348,8 @@
);
flushPassiveEffects();
isWorking = !0;
- ReactCurrentOwner$2.currentDispatcher = DispatcherWithoutHooks;
+ var previousDispatcher = ReactCurrentDispatcher.current;
+ ReactCurrentDispatcher.current = ContextOnlyDispatcher;
var expirationTime = root.nextExpirationTimeToWorkOn;
if (
expirationTime !== nextRenderExpirationTime ||
@@ -5765,7 +6396,7 @@
do {
try {
if (isYieldy)
- for (; null !== nextUnitOfWork && !shouldYieldToRenderer(); )
+ for (; null !== nextUnitOfWork && !(frameDeadline <= now$1()); )
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
else
for (; null !== nextUnitOfWork; )
@@ -5773,6 +6404,7 @@
} catch (thrownValue) {
if (
((lastContextWithAllBitsObserved = lastContextDependency = currentlyRenderingFiber = null),
+ resetHooks(),
null === nextUnitOfWork)
)
(threadID = !0), onUncaughtError(thrownValue);
@@ -5803,27 +6435,35 @@
} while (1);
tracing.__interactionsRef.current = subscriber;
isWorking = !1;
- lastContextWithAllBitsObserved = lastContextDependency = currentlyRenderingFiber = ReactCurrentOwner$2.currentDispatcher = null;
+ ReactCurrentDispatcher.current = previousDispatcher;
+ lastContextWithAllBitsObserved = lastContextDependency = currentlyRenderingFiber = null;
+ resetHooks();
if (threadID) (nextRoot = null), (root.finishedWork = null);
else if (null !== nextUnitOfWork) root.finishedWork = null;
else {
- subscriber = root.current.alternate;
+ previousDispatcher = root.current.alternate;
invariant(
- null !== subscriber,
+ null !== previousDispatcher,
"Finished root should have a work-in-progress. This error is likely caused by a bug in React. Please file an issue."
);
nextRoot = null;
if (nextRenderDidError) {
if (hasLowerPriorityWork(root, expirationTime)) {
markSuspendedPriorityLevel(root, expirationTime);
- onSuspend(root, subscriber, expirationTime, root.expirationTime, -1);
+ onSuspend(
+ root,
+ previousDispatcher,
+ expirationTime,
+ root.expirationTime,
+ -1
+ );
return;
}
if (!root.didError && isYieldy) {
root.didError = !0;
isYieldy = root.nextExpirationTimeToWorkOn = expirationTime;
- threadID = root.expirationTime = 1073741823;
- onSuspend(root, subscriber, isYieldy, threadID, -1);
+ subscriber = root.expirationTime = 1073741823;
+ onSuspend(root, previousDispatcher, isYieldy, subscriber, -1);
return;
}
}
@@ -5839,12 +6479,12 @@
(isYieldy = nextLatestAbsoluteTimeoutMs - isYieldy),
onSuspend(
root,
- subscriber,
+ previousDispatcher,
expirationTime,
root.expirationTime,
0 > isYieldy ? 0 : isYieldy
))
- : onComplete(root, subscriber, expirationTime);
+ : onComplete(root, previousDispatcher, expirationTime);
}
}
function captureCommitPhaseError(sourceFiber, value) {
@@ -5881,55 +6521,61 @@
scheduleWork(sourceFiber, 1073741823));
}
function computeExpirationForFiber(currentTime, fiber) {
- isWorking
- ? (currentTime = isCommitting$1 ? 1073741823 : nextRenderExpirationTime)
- : fiber.mode & 1
- ? ((currentTime = isBatchingInteractiveUpdates
- ? 1073741822 - 10 * ((((1073741822 - currentTime + 15) / 10) | 0) + 1)
- : 1073741822 -
- 25 * ((((1073741822 - currentTime + 500) / 25) | 0) + 1)),
+ var priorityLevel = scheduler.unstable_getCurrentPriorityLevel(),
+ expirationTime = void 0;
+ if (0 === (fiber.mode & 1)) expirationTime = 1073741823;
+ else if (isWorking && !isCommitting$1)
+ expirationTime = nextRenderExpirationTime;
+ else {
+ switch (priorityLevel) {
+ case scheduler.unstable_ImmediatePriority:
+ expirationTime = 1073741823;
+ break;
+ case scheduler.unstable_UserBlockingPriority:
+ expirationTime =
+ 1073741822 - 10 * ((((1073741822 - currentTime + 15) / 10) | 0) + 1);
+ break;
+ case scheduler.unstable_NormalPriority:
+ expirationTime =
+ 1073741822 - 25 * ((((1073741822 - currentTime + 500) / 25) | 0) + 1);
+ break;
+ case scheduler.unstable_LowPriority:
+ case scheduler.unstable_IdlePriority:
+ expirationTime = 1;
+ break;
+ default:
+ invariant(
+ !1,
+ "Unknown priority level. This error is likely caused by a bug in React. Please file an issue."
+ );
+ }
null !== nextRoot &&
- currentTime === nextRenderExpirationTime &&
- --currentTime)
- : (currentTime = 1073741823);
- isBatchingInteractiveUpdates &&
+ expirationTime === nextRenderExpirationTime &&
+ --expirationTime;
+ }
+ priorityLevel === scheduler.unstable_UserBlockingPriority &&
(0 === lowestPriorityPendingInteractiveExpirationTime ||
- currentTime < lowestPriorityPendingInteractiveExpirationTime) &&
- (lowestPriorityPendingInteractiveExpirationTime = currentTime);
- return currentTime;
-}
-function retrySuspendedRoot(root, boundaryFiber, sourceFiber, suspendedTime) {
- var retryTime = root.earliestSuspendedTime;
- var latestSuspendedTime = root.latestSuspendedTime;
- if (
- 0 !== retryTime &&
- suspendedTime <= retryTime &&
- suspendedTime >= latestSuspendedTime
+ expirationTime < lowestPriorityPendingInteractiveExpirationTime) &&
+ (lowestPriorityPendingInteractiveExpirationTime = expirationTime);
+ return expirationTime;
+}
+function pingSuspendedRoot(root, thenable, pingTime) {
+ var pingCache = root.pingCache;
+ null !== pingCache && pingCache.delete(thenable);
+ if (null !== nextRoot && nextRenderExpirationTime === pingTime)
+ nextRoot = null;
+ else if (
+ ((thenable = root.earliestSuspendedTime),
+ (pingCache = root.latestSuspendedTime),
+ 0 !== thenable && pingTime <= thenable && pingTime >= pingCache)
) {
- latestSuspendedTime = retryTime = suspendedTime;
root.didError = !1;
- var latestPingedTime = root.latestPingedTime;
- if (0 === latestPingedTime || latestPingedTime > latestSuspendedTime)
- root.latestPingedTime = latestSuspendedTime;
- findNextExpirationTimeToWorkOn(latestSuspendedTime, root);
- } else
- (retryTime = requestCurrentTime()),
- (retryTime = computeExpirationForFiber(retryTime, boundaryFiber)),
- markPendingPriorityLevel(root, retryTime);
- 0 !== (boundaryFiber.mode & 1) &&
- root === nextRoot &&
- nextRenderExpirationTime === suspendedTime &&
- (nextRoot = null);
- scheduleWorkToRoot(boundaryFiber, retryTime);
- 0 === (boundaryFiber.mode & 1) &&
- (scheduleWorkToRoot(sourceFiber, retryTime),
- 1 === sourceFiber.tag &&
- null !== sourceFiber.stateNode &&
- ((boundaryFiber = createUpdate(retryTime)),
- (boundaryFiber.tag = 2),
- enqueueUpdate(sourceFiber, boundaryFiber)));
- sourceFiber = root.expirationTime;
- 0 !== sourceFiber && requestWork(root, sourceFiber);
+ thenable = root.latestPingedTime;
+ if (0 === thenable || thenable > pingTime) root.latestPingedTime = pingTime;
+ findNextExpirationTimeToWorkOn(pingTime, root);
+ pingTime = root.expirationTime;
+ 0 !== pingTime && requestWork(root, pingTime);
+ }
}
function scheduleWorkToRoot(fiber, expirationTime) {
fiber.expirationTime < expirationTime &&
@@ -6008,7 +6654,6 @@
unhandledError = null,
isBatchingUpdates = !1,
isUnbatchingUpdates = !1,
- isBatchingInteractiveUpdates = !1,
completedBatches = null,
originalStartTimeMs = now$1(),
currentRendererTime = 1073741822 - ((originalStartTimeMs / 10) | 0),
@@ -6027,9 +6672,10 @@
((root = callbackID), (scheduledCallback = null), clearTimeout(root));
}
callbackExpirationTime = expirationTime;
- now$1();
- scheduledCallback = performAsyncWork;
- callbackID = setTimeout(setTimeoutCallback, 1);
+ root = now$1() - originalStartTimeMs;
+ callbackID = scheduleDeferredCallback$1(performAsyncWork, {
+ timeout: 10 * (1073741822 - expirationTime) - root
+ });
}
function onComplete(root, finishedWork, expirationTime) {
root.pendingCommitExpirationTime = expirationTime;
@@ -6043,7 +6689,7 @@
msUntilTimeout
) {
root.expirationTime = rootExpirationTime;
- 0 !== msUntilTimeout || shouldYieldToRenderer()
+ 0 !== msUntilTimeout || frameDeadline <= now$1()
? 0 < msUntilTimeout &&
(root.timeoutHandle = scheduleTimeout(
onTimeout.bind(null, root, finishedWork, suspendedExpirationTime),
@@ -6143,27 +6789,19 @@
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) {
+function performAsyncWork(didTimeout) {
+ if (didTimeout && null !== firstScheduledRoot) {
recomputeCurrentRendererTime();
- var root = firstScheduledRoot;
+ didTimeout = firstScheduledRoot;
do {
- var expirationTime = root.expirationTime;
+ var expirationTime = didTimeout.expirationTime;
0 !== expirationTime &&
currentRendererTime <= expirationTime &&
- (root.nextExpirationTimeToWorkOn = currentRendererTime);
- root = root.nextScheduledRoot;
- } while (root !== firstScheduledRoot);
+ (didTimeout.nextExpirationTimeToWorkOn = currentRendererTime);
+ didTimeout = didTimeout.nextScheduledRoot;
+ } while (didTimeout !== firstScheduledRoot);
}
performWork(0, !0);
- } finally {
- didYield = !1;
- }
}
function performWork(minExpirationTime, isYieldy) {
findHighestPriorityRoot();
@@ -6174,7 +6812,10 @@
null !== nextFlushedRoot &&
0 !== nextFlushedExpirationTime &&
minExpirationTime <= nextFlushedExpirationTime &&
- !(didYield && currentRendererTime > nextFlushedExpirationTime);
+ !(
+ frameDeadline <= now$1() &&
+ currentRendererTime > nextFlushedExpirationTime
+ );
)
performWorkOnRoot(
@@ -6242,7 +6883,7 @@
renderRoot(root, isYieldy),
(_finishedWork = root.finishedWork),
null !== _finishedWork &&
- (shouldYieldToRenderer()
+ (frameDeadline <= now$1()
? (root.finishedWork = _finishedWork)
: completeRoot$1(root, _finishedWork, expirationTime)));
} else
@@ -6277,7 +6918,12 @@
root === lastCommittedRootDuringThisBatch
? nestedUpdateCount++
: ((lastCommittedRootDuringThisBatch = root), (nestedUpdateCount = 0));
+ scheduler.unstable_runWithPriority(
+ scheduler.unstable_ImmediatePriority,
+ function() {
commitRoot(root, finishedWork);
+ }
+ );
}
function onUncaughtError(error) {
invariant(
@@ -6478,18 +7124,20 @@
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
);
}
@@ -6498,6 +7146,21 @@
})(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) {
@@ -6513,6 +7176,7 @@
earliestSuspendedTime: 0,
latestSuspendedTime: 0,
latestPingedTime: 0,
+ pingCache: null,
didError: !1,
pendingCommitExpirationTime: 0,
finishedWork: null,
@@ -6587,17 +7251,20 @@
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
);
}
@@ -6616,6 +7283,8 @@
var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance;
return injectInternals(
Object.assign({}, devToolsConfig, {
+ overrideProps: null,
+ currentDispatcherRef: ReactSharedInternals.ReactCurrentDispatcher,
findHostInstanceByFiber: function(fiber) {
fiber = findCurrentHostFiber(fiber);
return null === fiber ? null : fiber.stateNode;
@@ -6631,7 +7300,7 @@
findFiberByHostInstance: getInstanceFromInstance,
getInspectorDataForViewTag: getInspectorDataForViewTag,
bundleType: 0,
- version: "16.6.1",
+ version: "16.8.3",
rendererPackageName: "react-native-renderer"
});
var ReactFabric$2 = { default: ReactFabric },

Libraries/Renderer/oss/ReactNativeRenderer-dev.js

@@ -104,7 +104,7 @@
// invokeGuardedCallback uses a try-catch, all user exceptions are treated
// like caught exceptions, and the DevTools won't pause unless the developer
// takes the extra step of enabling pause on caught exceptions. This is
- // untintuitive, though, because even though React has caught the error, from
+ // unintuitive, though, because even though React has caught the error, from
// the developer's perspective, the error is uncaught.
//
// To preserve the expected "Pause on exceptions" behavior, we don't use a
@@ -1090,6 +1090,7 @@
var SimpleMemoComponent = 15;
var LazyComponent = 16;
var IncompleteClassComponent = 17;
+var DehydratedSuspenseComponent = 18;
function getParent(inst) {
do {
@@ -2840,6 +2841,15 @@
var ReactSharedInternals =
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
+// Prevent newer renderers from RTE when used with older react package versions.
+// Current owner and dispatcher used to share the same ref,
+// but PR #14548 split them out to better support the react-debug-tools package.
+if (!ReactSharedInternals.hasOwnProperty("ReactCurrentDispatcher")) {
+ ReactSharedInternals.ReactCurrentDispatcher = {
+ current: null
+ };
+}
+
// The Symbol used to tag the ReactElement-like types. If there is no native Symbol
// nor polyfill, then a plain number is used for performance.
var hasSymbol = typeof Symbol === "function" && Symbol.for;
@@ -3715,6 +3725,19 @@
}
}
+var debugRenderPhaseSideEffects = false;
+var debugRenderPhaseSideEffectsForStrictMode = false;
+var enableUserTimingAPI = true;
+var replayFailedUnitOfWorkWithInvokeGuardedCallback = true;
+var warnAboutDeprecatedLifecycles = false;
+var enableProfilerTimer = true;
+var enableSchedulerTracing = true;
+var enableSuspenseServerRenderer = false;
+
+var warnAboutDeprecatedSetNativeProps = false;
+
+// Only used in www builds.
+
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
@@ -3780,6 +3803,15 @@
nativeProps
) {
{
+ if (warnAboutDeprecatedSetNativeProps) {
+ warningWithoutStack$1(
+ false,
+ "Warning: Calling ref.setNativeProps(nativeProps) " +
+ "is deprecated and will be removed in a future release. " +
+ "Use the setNativeProps export from the react-native package instead." +
+ "\n\timport {setNativeProps} from 'react-native';\n\tsetNativeProps(ref, nativeProps);\n"
+ );
+ }
warnForStyleProps(nativeProps, this.viewConfig.validAttributes);
}
@@ -3883,21 +3915,31 @@
}
// Hydration (when unsupported)
+
var supportsHydration = false;
var canHydrateInstance = shim$1;
var canHydrateTextInstance = shim$1;
+var canHydrateSuspenseInstance = shim$1;
+var isSuspenseInstancePending = shim$1;
+var isSuspenseInstanceFallback = shim$1;
+var registerSuspenseInstanceRetry = shim$1;
var getNextHydratableSibling = shim$1;
var getFirstHydratableChild = shim$1;
var hydrateInstance = shim$1;
var hydrateTextInstance = shim$1;
+var getNextHydratableInstanceAfterSuspenseInstance = shim$1;
+var clearSuspenseBoundary = shim$1;
+var clearSuspenseBoundaryFromContainer = shim$1;
var didNotMatchHydratedContainerTextInstance = shim$1;
var didNotMatchHydratedTextInstance = shim$1;
var didNotHydrateContainerInstance = shim$1;
var didNotHydrateInstance = shim$1;
var didNotFindHydratableContainerInstance = shim$1;
var didNotFindHydratableContainerTextInstance = shim$1;
+var didNotFindHydratableContainerSuspenseInstance = shim$1;
var didNotFindHydratableInstance = shim$1;
var didNotFindHydratableTextInstance = shim$1;
+var didNotFindHydratableSuspenseInstance = shim$1;
// Modules provided by RN:
// Unused
@@ -4082,6 +4124,8 @@
var scheduleTimeout = setTimeout;
var cancelTimeout = clearTimeout;
var noTimeout = -1;
+var schedulePassiveEffects = scheduleDeferredCallback$$1;
+var cancelPassiveEffects = cancelDeferredCallback$$1;
function shouldDeprioritizeSubtree(type, props) {
return false;
@@ -4401,17 +4445,6 @@
}
}
-var debugRenderPhaseSideEffects = false;
-var debugRenderPhaseSideEffectsForStrictMode = false;
-var enableHooks = false;
-var enableUserTimingAPI = true;
-var replayFailedUnitOfWorkWithInvokeGuardedCallback = true;
-var warnAboutDeprecatedLifecycles = false;
-var enableProfilerTimer = true;
-var enableSchedulerTracing = true;
-
-// Only used in www builds.
-
// Prefix measurements so that it's possible to filter them.
// Longer prefixes are hard to read in DevTools.
var reactEmoji = "\u269B";
@@ -4683,7 +4716,8 @@
}
fiber._debugIsCurrentlyTiming = false;
var warning =
- fiber.tag === SuspenseComponent
+ fiber.tag === SuspenseComponent ||
+ fiber.tag === DehydratedSuspenseComponent
? "Rendering was suspended"
: "An error was thrown inside this error boundary";
endFiberMark(fiber, null, warning);
@@ -5407,7 +5441,7 @@
this.memoizedProps = null;
this.updateQueue = null;
this.memoizedState = null;
- this.firstContextDependency = null;
+ this.contextDependencies = null;
this.mode = mode;
@@ -5424,14 +5458,16 @@
this.alternate = null;
if (enableProfilerTimer) {
- // Note: The following is done to avoid a v8 deopt.
+ // Note: The following is done to avoid a v8 performance cliff.
//
- // It is important to initialize the fields below with doubles.
- // Otherwise Fibers will deopt and end up having separate shapes when
- // doubles are later assigned to fields that initially contained smis.
- // This is a bug in v8 having something to do with Object.preventExtension().
+ // Initializing the fields below to smis and later updating them with
+ // double values will cause Fibers to end up having separate shapes.
+ // This behavior/bug has something to do with Object.preventExtension().
+ // Fortunately this only impacts DEV builds.
+ // Unfortunately it makes React unusably slow for some applications.
+ // To work around this, initialize the fields below with doubles.
//
- // Learn more about this deopt here:
+ // Learn more about this here:
// https://github.com/facebook/react/issues/14365
// https://bugs.chromium.org/p/v8/issues/detail?id=8538
this.actualDuration = Number.NaN;
@@ -5440,7 +5476,8 @@
this.treeBaseDuration = Number.NaN;
// It's okay to replace the initial doubles with smis after initialization.
- // This simplifies other profiler code and doesn't trigger the deopt.
+ // This won't trigger the performance cliff mentioned above,
+ // and it simplifies other profiler code (including DevTools).
this.actualDuration = 0;
this.actualStartTime = -1;
this.selfBaseDuration = 0;
@@ -5561,7 +5598,7 @@
workInProgress.memoizedProps = current.memoizedProps;
workInProgress.memoizedState = current.memoizedState;
workInProgress.updateQueue = current.updateQueue;
- workInProgress.firstContextDependency = current.firstContextDependency;
+ workInProgress.contextDependencies = current.contextDependencies;
// These will be overridden during the parent's reconciliation
workInProgress.sibling = current.sibling;
@@ -5827,7 +5864,7 @@
target.memoizedProps = source.memoizedProps;
target.updateQueue = source.updateQueue;
target.memoizedState = source.memoizedState;
- target.firstContextDependency = source.firstContextDependency;
+ target.contextDependencies = source.contextDependencies;
target.mode = source.mode;
target.effectTag = source.effectTag;
target.nextEffect = source.nextEffect;
@@ -5880,6 +5917,8 @@
latestSuspendedTime: NoWork,
latestPingedTime: NoWork,
+ pingCache: null,
+
didError: false,
pendingCommitExpirationTime: NoWork,
@@ -5903,6 +5942,8 @@
containerInfo: containerInfo,
pendingChildren: null,
+ pingCache: null,
+
earliestPendingTime: NoWork,
latestPendingTime: NoWork,
earliestSuspendedTime: NoWork,
@@ -6052,7 +6093,7 @@
lifecycleWarningsMap,
strictRoot
) {
- var lifecyclesWarningMesages = [];
+ var lifecyclesWarningMessages = [];
Object.keys(lifecycleWarningsMap).forEach(function(lifecycle) {
var lifecycleWarnings = lifecycleWarningsMap[lifecycle];
@@ -6067,7 +6108,7 @@
var suggestion = LIFECYCLE_SUGGESTIONS[lifecycle];
var sortedComponentNames = setToSortedString(componentNames);
- lifecyclesWarningMesages.push(
+ lifecyclesWarningMessages.push(
formatted +
": Please update the following components to use " +
(suggestion + " instead: " + sortedComponentNames)
@@ -6075,7 +6116,7 @@
}
});
- if (lifecyclesWarningMesages.length > 0) {
+ if (lifecyclesWarningMessages.length > 0) {
var strictRootComponentStack = getStackByFiberInDevAndProd(strictRoot);
warningWithoutStack$1(
@@ -6085,7 +6126,7 @@
"\n\nLearn more about this warning here:" +
"\nhttps://fb.me/react-strict-mode-warnings",
strictRootComponentStack,
- lifecyclesWarningMesages.join("\n\n")
+ lifecyclesWarningMessages.join("\n\n")
);
}
});
@@ -6386,6 +6427,10 @@
return;
}
+ if (earliestRemainingTime < root.latestPingedTime) {
+ root.latestPingedTime = NoWork;
+ }
+
// Let's see if the previous latest known pending level was just flushed.
var latestPendingTime = root.latestPendingTime;
if (latestPendingTime !== NoWork) {
@@ -6521,10 +6566,8 @@
}
function clearPing(root, completedTime) {
- // TODO: Track whether the root was pinged during the render phase. If so,
- // we need to make sure we don't lose track of it.
var latestPingedTime = root.latestPingedTime;
- if (latestPingedTime !== NoWork && latestPingedTime >= completedTime) {
+ if (latestPingedTime >= completedTime) {
root.latestPingedTime = NoWork;
}
}
@@ -6585,561 +6628,6 @@
root.expirationTime = expirationTime;
}
-// UpdateQueue is a linked list of prioritized updates.
-//
-// Like fibers, update queues come in pairs: a current queue, which represents
-// the visible state of the screen, and a work-in-progress queue, which is
-// can be mutated and processed asynchronously before it is committed — a form
-// of double buffering. If a work-in-progress render is discarded before
-// finishing, we create a new work-in-progress by cloning the current queue.
-//
-// Both queues share a persistent, singly-linked list structure. To schedule an
-// update, we append it to the end of both queues. Each queue maintains a
-// pointer to first update in the persistent list that hasn't been processed.
-// The work-in-progress pointer always has a position equal to or greater than
-// the current queue, since we always work on that one. The current queue's
-// pointer is only updated during the commit phase, when we swap in the
-// work-in-progress.
-//
-// For example:
-//
-// Current pointer: A - B - C - D - E - F
-// Work-in-progress pointer: D - E - F
-// ^
-// The work-in-progress queue has
-// processed more updates than current.
-//
-// The reason we append to both queues is because otherwise we might drop
-// updates without ever processing them. For example, if we only add updates to
-// the work-in-progress queue, some updates could be lost whenever a work-in
-// -progress render restarts by cloning from current. Similarly, if we only add
-// updates to the current queue, the updates will be lost whenever an already
-// in-progress queue commits and swaps with the current queue. However, by
-// adding to both queues, we guarantee that the update will be part of the next
-// work-in-progress. (And because the work-in-progress queue becomes the
-// current queue once it commits, there's no danger of applying the same
-// update twice.)
-//
-// Prioritization
-// --------------
-//
-// Updates are not sorted by priority, but by insertion; new updates are always
-// appended to the end of the list.
-//
-// The priority is still important, though. When processing the update queue
-// during the render phase, only the updates with sufficient priority are
-// included in the result. If we skip an update because it has insufficient
-// priority, it remains in the queue to be processed later, during a lower
-// priority render. Crucially, all updates subsequent to a skipped update also
-// remain in the queue *regardless of their priority*. That means high priority
-// updates are sometimes processed twice, at two separate priorities. We also
-// keep track of a base state, that represents the state before the first
-// update in the queue is applied.
-//
-// For example:
-//
-// Given a base state of '', and the following queue of updates
-//
-// A1 - B2 - C1 - D2
-//
-// where the number indicates the priority, and the update is applied to the
-// previous state by appending a letter, React will process these updates as
-// two separate renders, one per distinct priority level:
-//
-// First render, at priority 1:
-// Base state: ''
-// Updates: [A1, C1]
-// Result state: 'AC'
-//
-// Second render, at priority 2:
-// Base state: 'A' <- The base state does not include C1,
-// because B2 was skipped.
-// Updates: [B2, C1, D2] <- C1 was rebased on top of B2
-// Result state: 'ABCD'
-//
-// Because we process updates in insertion order, and rebase high priority
-// updates when preceding updates are skipped, the final result is deterministic
-// regardless of priority. Intermediate state may vary according to system
-// resources, but the final state is always the same.
-
-var UpdateState = 0;
-var ReplaceState = 1;
-var ForceUpdate = 2;
-var CaptureUpdate = 3;
-
-// Global state that is reset at the beginning of calling `processUpdateQueue`.
-// It should only be read right after calling `processUpdateQueue`, via
-// `checkHasForceUpdateAfterProcessing`.
-var hasForceUpdate = false;
-
-var didWarnUpdateInsideUpdate = void 0;
-var currentlyProcessingQueue = void 0;
-var resetCurrentlyProcessingQueue = void 0;
-{
- didWarnUpdateInsideUpdate = false;
- currentlyProcessingQueue = null;
- resetCurrentlyProcessingQueue = function() {
- currentlyProcessingQueue = null;
- };
-}
-
-function createUpdateQueue(baseState) {
- var queue = {
- baseState: baseState,
- firstUpdate: null,
- lastUpdate: null,
- firstCapturedUpdate: null,
- lastCapturedUpdate: null,
- firstEffect: null,
- lastEffect: null,
- firstCapturedEffect: null,
- lastCapturedEffect: null
- };
- return queue;
-}
-
-function cloneUpdateQueue(currentQueue) {
- var queue = {
- baseState: currentQueue.baseState,
- firstUpdate: currentQueue.firstUpdate,
- lastUpdate: currentQueue.lastUpdate,
-
- // TODO: With resuming, if we bail out and resuse the child tree, we should
- // keep these effects.
- firstCapturedUpdate: null,
- lastCapturedUpdate: null,
-
- firstEffect: null,
- lastEffect: null,
-
- firstCapturedEffect: null,
- lastCapturedEffect: null
- };
- return queue;
-}
-
-function createUpdate(expirationTime) {
- return {
- expirationTime: expirationTime,
-
- tag: UpdateState,
- payload: null,
- callback: null,
-
- next: null,
- nextEffect: null
- };
-}
-
-function appendUpdateToQueue(queue, update) {
- // Append the update to the end of the list.
- if (queue.lastUpdate === null) {
- // Queue is empty
- queue.firstUpdate = queue.lastUpdate = update;
- } else {
- queue.lastUpdate.next = update;
- queue.lastUpdate = update;
- }
-}
-
-function enqueueUpdate(fiber, update) {
- // Update queues are created lazily.
- var alternate = fiber.alternate;
- var queue1 = void 0;
- var queue2 = void 0;
- if (alternate === null) {
- // There's only one fiber.
- queue1 = fiber.updateQueue;
- queue2 = null;
- if (queue1 === null) {
- queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState);
- }
- } else {
- // There are two owners.
- queue1 = fiber.updateQueue;
- queue2 = alternate.updateQueue;
- if (queue1 === null) {
- if (queue2 === null) {
- // Neither fiber has an update queue. Create new ones.
- queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState);
- queue2 = alternate.updateQueue = createUpdateQueue(
- alternate.memoizedState
- );
- } else {
- // Only one fiber has an update queue. Clone to create a new one.
- queue1 = fiber.updateQueue = cloneUpdateQueue(queue2);
- }
- } else {
- if (queue2 === null) {
- // Only one fiber has an update queue. Clone to create a new one.
- queue2 = alternate.updateQueue = cloneUpdateQueue(queue1);
- } else {
- // Both owners have an update queue.
- }
- }
- }
- if (queue2 === null || queue1 === queue2) {
- // There's only a single queue.
- appendUpdateToQueue(queue1, update);
- } else {
- // There are two queues. We need to append the update to both queues,
- // while accounting for the persistent structure of the list — we don't
- // want the same update to be added multiple times.
- if (queue1.lastUpdate === null || queue2.lastUpdate === null) {
- // One of the queues is not empty. We must add the update to both queues.
- appendUpdateToQueue(queue1, update);
- appendUpdateToQueue(queue2, update);
- } else {
- // Both queues are non-empty. The last update is the same in both lists,
- // because of structural sharing. So, only append to one of the lists.
- appendUpdateToQueue(queue1, update);
- // But we still need to update the `lastUpdate` pointer of queue2.
- queue2.lastUpdate = update;
- }
- }
-
- {
- if (
- fiber.tag === ClassComponent &&
- (currentlyProcessingQueue === queue1 ||
- (queue2 !== null && currentlyProcessingQueue === queue2)) &&
- !didWarnUpdateInsideUpdate
- ) {
- warningWithoutStack$1(
- false,
- "An update (setState, replaceState, or forceUpdate) was scheduled " +
- "from inside an update function. Update functions should be pure, " +
- "with zero side-effects. Consider using componentDidUpdate or a " +
- "callback."
- );
- didWarnUpdateInsideUpdate = true;
- }
- }
-}
-
-function enqueueCapturedUpdate(workInProgress, update) {
- // Captured updates go into a separate list, and only on the work-in-
- // progress queue.
- var workInProgressQueue = workInProgress.updateQueue;
- if (workInProgressQueue === null) {
- workInProgressQueue = workInProgress.updateQueue = createUpdateQueue(
- workInProgress.memoizedState
- );
- } else {
- // TODO: I put this here rather than createWorkInProgress so that we don't
- // clone the queue unnecessarily. There's probably a better way to
- // structure this.
- workInProgressQueue = ensureWorkInProgressQueueIsAClone(
- workInProgress,
- workInProgressQueue
- );
- }
-
- // Append the update to the end of the list.
- if (workInProgressQueue.lastCapturedUpdate === null) {
- // This is the first render phase update
- workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update;
- } else {
- workInProgressQueue.lastCapturedUpdate.next = update;
- workInProgressQueue.lastCapturedUpdate = update;
- }
-}
-
-function ensureWorkInProgressQueueIsAClone(workInProgress, queue) {
- var current = workInProgress.alternate;
- if (current !== null) {
- // If the work-in-progress queue is equal to the current queue,
- // we need to clone it first.
- if (queue === current.updateQueue) {
- queue = workInProgress.updateQueue = cloneUpdateQueue(queue);
- }
- }
- return queue;
-}
-
-function getStateFromUpdate(
- workInProgress,
- queue,
- update,
- prevState,
- nextProps,
- instance
-) {
- switch (update.tag) {
- case ReplaceState: {
- var _payload = update.payload;
- if (typeof _payload === "function") {
- // Updater function
- {
- if (
- debugRenderPhaseSideEffects ||
- (debugRenderPhaseSideEffectsForStrictMode &&
- workInProgress.mode & StrictMode)
- ) {
- _payload.call(instance, prevState, nextProps);
- }
- }
- return _payload.call(instance, prevState, nextProps);
- }
- // State object
- return _payload;
- }
- case CaptureUpdate: {
- workInProgress.effectTag =
- (workInProgress.effectTag & ~ShouldCapture) | DidCapture;
- }
- // Intentional fallthrough
- case UpdateState: {
- var _payload2 = update.payload;
- var partialState = void 0;
- if (typeof _payload2 === "function") {
- // Updater function
- {
- if (
- debugRenderPhaseSideEffects ||
- (debugRenderPhaseSideEffectsForStrictMode &&
- workInProgress.mode & StrictMode)
- ) {
- _payload2.call(instance, prevState, nextProps);
- }
- }
- partialState = _payload2.call(instance, prevState, nextProps);
- } else {
- // Partial state object
- partialState = _payload2;
- }
- if (partialState === null || partialState === undefined) {
- // Null and undefined are treated as no-ops.
- return prevState;
- }
- // Merge the partial state and the previous state.
- return Object.assign({}, prevState, partialState);
- }
- case ForceUpdate: {
- hasForceUpdate = true;
- return prevState;
- }
- }
- return prevState;
-}
-
-function processUpdateQueue(
- workInProgress,
- queue,
- props,
- instance,
- renderExpirationTime
-) {
- hasForceUpdate = false;
-
- queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue);
-
- {
- currentlyProcessingQueue = queue;
- }
-
- // These values may change as we process the queue.
- var newBaseState = queue.baseState;
- var newFirstUpdate = null;
- var newExpirationTime = NoWork;
-
- // Iterate through the list of updates to compute the result.
- var update = queue.firstUpdate;
- var resultState = newBaseState;
- while (update !== null) {
- var updateExpirationTime = update.expirationTime;
- if (updateExpirationTime < renderExpirationTime) {
- // This update does not have sufficient priority. Skip it.
- if (newFirstUpdate === null) {
- // This is the first skipped update. It will be the first update in
- // the new list.
- newFirstUpdate = update;
- // Since this is the first update that was skipped, the current result
- // is the new base state.
- newBaseState = resultState;
- }
- // Since this update will remain in the list, update the remaining
- // expiration time.
- if (newExpirationTime < updateExpirationTime) {
- newExpirationTime = updateExpirationTime;
- }
- } else {
- // This update does have sufficient priority. Process it and compute
- // a new result.
- resultState = getStateFromUpdate(
- workInProgress,
- queue,
- update,
- resultState,
- props,
- instance
- );
- var _callback = update.callback;
- if (_callback !== null) {
- workInProgress.effectTag |= Callback;
- // Set this to null, in case it was mutated during an aborted render.
- update.nextEffect = null;
- if (queue.lastEffect === null) {
- queue.firstEffect = queue.lastEffect = update;
- } else {
- queue.lastEffect.nextEffect = update;
- queue.lastEffect = update;
- }
- }
- }
- // Continue to the next update.
- update = update.next;
- }
-
- // Separately, iterate though the list of captured updates.
- var newFirstCapturedUpdate = null;
- update = queue.firstCapturedUpdate;
- while (update !== null) {
- var _updateExpirationTime = update.expirationTime;
- if (_updateExpirationTime < renderExpirationTime) {
- // This update does not have sufficient priority. Skip it.
- if (newFirstCapturedUpdate === null) {
- // This is the first skipped captured update. It will be the first
- // update in the new list.
- newFirstCapturedUpdate = update;
- // If this is the first update that was skipped, the current result is
- // the new base state.
- if (newFirstUpdate === null) {
- newBaseState = resultState;
- }
- }
- // Since this update will remain in the list, update the remaining
- // expiration time.
- if (newExpirationTime < _updateExpirationTime) {
- newExpirationTime = _updateExpirationTime;
- }
- } else {
- // This update does have sufficient priority. Process it and compute
- // a new result.
- resultState = getStateFromUpdate(
- workInProgress,
- queue,
- update,
- resultState,
- props,
- instance
- );
- var _callback2 = update.callback;
- if (_callback2 !== null) {
- workInProgress.effectTag |= Callback;
- // Set this to null, in case it was mutated during an aborted render.
- update.nextEffect = null;
- if (queue.lastCapturedEffect === null) {
- queue.firstCapturedEffect = queue.lastCapturedEffect = update;
- } else {
- queue.lastCapturedEffect.nextEffect = update;
- queue.lastCapturedEffect = update;
- }
- }
- }
- update = update.next;
- }
-
- if (newFirstUpdate === null) {
- queue.lastUpdate = null;
- }
- if (newFirstCapturedUpdate === null) {
- queue.lastCapturedUpdate = null;
- } else {
- workInProgress.effectTag |= Callback;
- }
- if (newFirstUpdate === null && newFirstCapturedUpdate === null) {
- // We processed every update, without skipping. That means the new base
- // state is the same as the result state.
- newBaseState = resultState;
- }
-
- queue.baseState = newBaseState;
- queue.firstUpdate = newFirstUpdate;
- queue.firstCapturedUpdate = newFirstCapturedUpdate;
-
- // Set the remaining expiration time to be whatever is remaining in the queue.
- // This should be fine because the only two other things that contribute to
- // expiration time are props and context. We're already in the middle of the
- // begin phase by the time we start processing the queue, so we've already
- // dealt with the props. Context in components that specify
- // shouldComponentUpdate is tricky; but we'll have to account for
- // that regardless.
- workInProgress.expirationTime = newExpirationTime;
- workInProgress.memoizedState = resultState;
-
- {
- currentlyProcessingQueue = null;
- }
-}
-
-function callCallback(callback, context) {
- invariant(
- typeof callback === "function",
- "Invalid argument passed as callback. Expected a function. Instead " +
- "received: %s",
- callback
- );
- callback.call(context);
-}
-
-function resetHasForceUpdateBeforeProcessing() {
- hasForceUpdate = false;
-}
-
-function checkHasForceUpdateAfterProcessing() {
- return hasForceUpdate;
-}
-
-function commitUpdateQueue(
- finishedWork,
- finishedQueue,
- instance,
- renderExpirationTime
-) {
- // If the finished render included captured updates, and there are still
- // lower priority updates left over, we need to keep the captured updates
- // in the queue so that they are rebased and not dropped once we process the
- // queue again at the lower priority.
- if (finishedQueue.firstCapturedUpdate !== null) {
- // Join the captured update list to the end of the normal list.
- if (finishedQueue.lastUpdate !== null) {
- finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate;
- finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate;
- }
- // Clear the list of captured updates.
- finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null;
- }
-
- // Commit the effects
- commitUpdateEffects(finishedQueue.firstEffect, instance);
- finishedQueue.firstEffect = finishedQueue.lastEffect = null;
-
- commitUpdateEffects(finishedQueue.firstCapturedEffect, instance);
- finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null;
-}
-
-function commitUpdateEffects(effect, instance) {
- while (effect !== null) {
- var _callback3 = effect.callback;
- if (_callback3 !== null) {
- effect.callback = null;
- callCallback(_callback3, instance);
- }
- effect = effect.nextEffect;
- }
-}
-
-function createCapturedValue(value, source) {
- // If the value is an error, call this function immediately after it is thrown
- // so the stack is accurate.
- return {
- value: value,
- source: source,
- stack: getStackByFiberInDevAndProd(source)
- };
-}
-
/**
* Similar to invariant but only logs a warning if the condition is not met.
* This can be used to log issues in development environments in critical
@@ -7177,1046 +6665,18 @@
var warning$1 = warning;
-var valueCursor = createCursor(null);
-
-var rendererSigil = void 0;
-{
- // Use this to detect multiple renderers using the same context
- rendererSigil = {};
-}
-
-var currentlyRenderingFiber = null;
-var lastContextDependency = null;
-var lastContextWithAllBitsObserved = null;
-
-function resetContextDependences() {
- // This is called right before React yields execution, to ensure `readContext`
- // cannot be called outside the render phase.
- currentlyRenderingFiber = null;
- lastContextDependency = null;
- lastContextWithAllBitsObserved = null;
-}
-
-function pushProvider(providerFiber, nextValue) {
- var context = providerFiber.type._context;
-
- if (isPrimaryRenderer) {
- push(valueCursor, context._currentValue, providerFiber);
-
- context._currentValue = nextValue;
- {
- !(
- context._currentRenderer === undefined ||
- context._currentRenderer === null ||
- context._currentRenderer === rendererSigil
- )
- ? warningWithoutStack$1(
- false,
- "Detected multiple renderers concurrently rendering the " +
- "same context provider. This is currently unsupported."
- )
- : void 0;
- context._currentRenderer = rendererSigil;
- }
- } else {
- push(valueCursor, context._currentValue2, providerFiber);
-
- context._currentValue2 = nextValue;
- {
- !(
- context._currentRenderer2 === undefined ||
- context._currentRenderer2 === null ||
- context._currentRenderer2 === rendererSigil
- )
- ? warningWithoutStack$1(
- false,
- "Detected multiple renderers concurrently rendering the " +
- "same context provider. This is currently unsupported."
- )
- : void 0;
- context._currentRenderer2 = rendererSigil;
- }
- }
-}
-
-function popProvider(providerFiber) {
- var currentValue = valueCursor.current;
-
- pop(valueCursor, providerFiber);
-
- var context = providerFiber.type._context;
- if (isPrimaryRenderer) {
- context._currentValue = currentValue;
- } else {
- context._currentValue2 = currentValue;
- }
-}
-
-function calculateChangedBits(context, newValue, oldValue) {
- // Use Object.is to compare the new context value to the old value. Inlined
- // Object.is polyfill.
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
- if (
- (oldValue === newValue &&
- (oldValue !== 0 || 1 / oldValue === 1 / newValue)) ||
- (oldValue !== oldValue && newValue !== newValue) // eslint-disable-line no-self-compare
- ) {
- // No change
- return 0;
- } else {
- var changedBits =
- typeof context._calculateChangedBits === "function"
- ? context._calculateChangedBits(oldValue, newValue)
- : maxSigned31BitInt;
-
- {
- !((changedBits & maxSigned31BitInt) === changedBits)
- ? warning$1(
- false,
- "calculateChangedBits: Expected the return value to be a " +
- "31-bit integer. Instead received: %s",
- changedBits
- )
- : void 0;
- }
- return changedBits | 0;
- }
-}
-
-function propagateContextChange(
- workInProgress,
- context,
- changedBits,
- renderExpirationTime
-) {
- var fiber = workInProgress.child;
- if (fiber !== null) {
- // Set the return pointer of the child to the work-in-progress fiber.
- fiber.return = workInProgress;
- }
- while (fiber !== null) {
- var nextFiber = void 0;
-
- // Visit this fiber.
- var dependency = fiber.firstContextDependency;
- if (dependency !== null) {
- do {
- // Check if the context matches.
- if (
- dependency.context === context &&
- (dependency.observedBits & changedBits) !== 0
- ) {
- // Match! Schedule an update on this fiber.
-
- if (fiber.tag === ClassComponent) {
- // Schedule a force update on the work-in-progress.
- var update = createUpdate(renderExpirationTime);
- update.tag = ForceUpdate;
- // TODO: Because we don't have a work-in-progress, this will add the
- // update to the current fiber, too, which means it will persist even if
- // this render is thrown away. Since it's a race condition, not sure it's
- // worth fixing.
- enqueueUpdate(fiber, update);
- }
-
- if (fiber.expirationTime < renderExpirationTime) {
- fiber.expirationTime = renderExpirationTime;
- }
- var alternate = fiber.alternate;
- if (
- alternate !== null &&
- alternate.expirationTime < renderExpirationTime
- ) {
- alternate.expirationTime = renderExpirationTime;
- }
- // Update the child expiration time of all the ancestors, including
- // the alternates.
- var node = fiber.return;
- while (node !== null) {
- alternate = node.alternate;
- if (node.childExpirationTime < renderExpirationTime) {
- node.childExpirationTime = renderExpirationTime;
- if (
- alternate !== null &&
- alternate.childExpirationTime < renderExpirationTime
- ) {
- alternate.childExpirationTime = renderExpirationTime;
- }
- } else if (
- alternate !== null &&
- alternate.childExpirationTime < renderExpirationTime
- ) {
- alternate.childExpirationTime = renderExpirationTime;
- } else {
- // Neither alternate was updated, which means the rest of the
- // ancestor path already has sufficient priority.
- break;
- }
- node = node.return;
- }
- }
- nextFiber = fiber.child;
- dependency = dependency.next;
- } while (dependency !== null);
- } else if (fiber.tag === ContextProvider) {
- // Don't scan deeper if this is a matching provider
- nextFiber = fiber.type === workInProgress.type ? null : fiber.child;
- } else {
- // Traverse down.
- nextFiber = fiber.child;
- }
-
- if (nextFiber !== null) {
- // Set the return pointer of the child to the work-in-progress fiber.
- nextFiber.return = fiber;
- } else {
- // No child. Traverse to next sibling.
- nextFiber = fiber;
- while (nextFiber !== null) {
- if (nextFiber === workInProgress) {
- // We're back to the root of this subtree. Exit.
- nextFiber = null;
- break;
- }
- var sibling = nextFiber.sibling;
- if (sibling !== null) {
- // Set the return pointer of the sibling to the work-in-progress fiber.
- sibling.return = nextFiber.return;
- nextFiber = sibling;
- break;
- }
- // No more siblings. Traverse up.
- nextFiber = nextFiber.return;
- }
- }
- fiber = nextFiber;
- }
-}
-
-function prepareToReadContext(workInProgress, renderExpirationTime) {
- currentlyRenderingFiber = workInProgress;
- lastContextDependency = null;
- lastContextWithAllBitsObserved = null;
-
- // Reset the work-in-progress list
- workInProgress.firstContextDependency = null;
-}
-
-function readContext(context, observedBits) {
- if (lastContextWithAllBitsObserved === context) {
- // Nothing to do. We already observe everything in this context.
- } else if (observedBits === false || observedBits === 0) {
- // Do not observe any updates.
- } else {
- var resolvedObservedBits = void 0; // Avoid deopting on observable arguments or heterogeneous types.
- if (
- typeof observedBits !== "number" ||
- observedBits === maxSigned31BitInt
- ) {
- // Observe all updates.
- lastContextWithAllBitsObserved = context;
- resolvedObservedBits = maxSigned31BitInt;
- } else {
- resolvedObservedBits = observedBits;
- }
-
- var contextItem = {
- context: context,
- observedBits: resolvedObservedBits,
- next: null
- };
-
- if (lastContextDependency === null) {
- invariant(
- currentlyRenderingFiber !== null,
- "Context can only be read while React is " +
- "rendering, e.g. inside the render method or getDerivedStateFromProps."
- );
- // This is the first dependency in the list
- currentlyRenderingFiber.firstContextDependency = lastContextDependency = contextItem;
- } else {
- // Append a new context item.
- lastContextDependency = lastContextDependency.next = contextItem;
- }
- }
- return isPrimaryRenderer ? context._currentValue : context._currentValue2;
-}
-
-var NoEffect$1 = /* */ 0;
-var UnmountSnapshot = /* */ 2;
-var UnmountMutation = /* */ 4;
-var MountMutation = /* */ 8;
-var UnmountLayout = /* */ 16;
-var MountLayout = /* */ 32;
-var MountPassive = /* */ 64;
-var UnmountPassive = /* */ 128;
-
-function areHookInputsEqual(arr1, arr2) {
- // Don't bother comparing lengths in prod because these arrays should be
- // passed inline.
- {
- !(arr1.length === arr2.length)
- ? warning$1(
- false,
- "Detected a variable number of hook dependencies. The length of the " +
- "dependencies array should be constant between renders.\n\n" +
- "Previous: %s\n" +
- "Incoming: %s",
- arr1.join(", "),
- arr2.join(", ")
- )
- : void 0;
- }
- for (var i = 0; i < arr1.length; i++) {
- // Inlined Object.is polyfill.
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
- var val1 = arr1[i];
- var val2 = arr2[i];
- if (
- (val1 === val2 && (val1 !== 0 || 1 / val1 === 1 / val2)) ||
- (val1 !== val1 && val2 !== val2) // eslint-disable-line no-self-compare
- ) {
- continue;
- }
- return false;
- }
- return true;
-}
-
-// These are set right before calling the component.
-var renderExpirationTime = NoWork;
-// The work-in-progress fiber. I've named it differently to distinguish it from
-// the work-in-progress hook.
-var currentlyRenderingFiber$1 = null;
-
-// Hooks are stored as a linked list on the fiber's memoizedState field. The
-// current hook list is the list that belongs to the current fiber. The
-// work-in-progress hook list is a new list that will be added to the
-// work-in-progress fiber.
-var firstCurrentHook = null;
-var currentHook = null;
-var firstWorkInProgressHook = null;
-var workInProgressHook = null;
-
-var remainingExpirationTime = NoWork;
-var componentUpdateQueue = null;
-
-// Updates scheduled during render will trigger an immediate re-render at the
-// end of the current pass. We can't store these updates on the normal queue,
-// because if the work is aborted, they should be discarded. Because this is
-// a relatively rare case, we also don't want to add an additional field to
-// either the hook or queue object types. So we store them in a lazily create
-// map of queue -> render-phase updates, which are discarded once the component
-// completes without re-rendering.
-
-// Whether the work-in-progress hook is a re-rendered hook
-var isReRender = false;
-// Whether an update was scheduled during the currently executing render pass.
-var didScheduleRenderPhaseUpdate = false;
-// Lazily created map of render-phase updates
-var renderPhaseUpdates = null;
-// Counter to prevent infinite loops.
-var numberOfReRenders = 0;
-var RE_RENDER_LIMIT = 25;
-
-function resolveCurrentlyRenderingFiber() {
- invariant(
- currentlyRenderingFiber$1 !== null,
- "Hooks can only be called inside the body of a function component."
- );
- return currentlyRenderingFiber$1;
-}
-
-function prepareToUseHooks(current, workInProgress, nextRenderExpirationTime) {
- if (!enableHooks) {
- return;
- }
- renderExpirationTime = nextRenderExpirationTime;
- currentlyRenderingFiber$1 = workInProgress;
- firstCurrentHook = current !== null ? current.memoizedState : null;
-
- // The following should have already been reset
- // currentHook = null;
- // workInProgressHook = null;
-
- // remainingExpirationTime = NoWork;
- // componentUpdateQueue = null;
-
- // isReRender = false;
- // didScheduleRenderPhaseUpdate = false;
- // renderPhaseUpdates = null;
- // numberOfReRenders = 0;
-}
-
-function finishHooks(Component, props, children, refOrContext) {
- if (!enableHooks) {
- return children;
- }
-
- // This must be called after every function component to prevent hooks from
- // being used in classes.
-
- while (didScheduleRenderPhaseUpdate) {
- // Updates were scheduled during the render phase. They are stored in
- // the `renderPhaseUpdates` map. Call the component again, reusing the
- // work-in-progress hooks and applying the additional updates on top. Keep
- // restarting until no more updates are scheduled.
- didScheduleRenderPhaseUpdate = false;
- numberOfReRenders += 1;
-
- // Start over from the beginning of the list
- currentHook = null;
- workInProgressHook = null;
- componentUpdateQueue = null;
-
- children = Component(props, refOrContext);
- }
- renderPhaseUpdates = null;
- numberOfReRenders = 0;
-
- var renderedWork = currentlyRenderingFiber$1;
-
- renderedWork.memoizedState = firstWorkInProgressHook;
- renderedWork.expirationTime = remainingExpirationTime;
- renderedWork.updateQueue = componentUpdateQueue;
-
- var didRenderTooFewHooks = currentHook !== null && currentHook.next !== null;
-
- renderExpirationTime = NoWork;
- currentlyRenderingFiber$1 = null;
-
- firstCurrentHook = null;
- currentHook = null;
- firstWorkInProgressHook = null;
- workInProgressHook = null;
-
- remainingExpirationTime = NoWork;
- componentUpdateQueue = null;
-
- // Always set during createWorkInProgress
- // isReRender = false;
-
- // These were reset above
- // didScheduleRenderPhaseUpdate = false;
- // renderPhaseUpdates = null;
- // numberOfReRenders = 0;
-
- invariant(
- !didRenderTooFewHooks,
- "Rendered fewer hooks than expected. This may be caused by an accidental " +
- "early return statement."
- );
-
- return children;
-}
-
-function resetHooks() {
- if (!enableHooks) {
- return;
- }
-
- // This is called instead of `finishHooks` if the component throws. It's also
- // called inside mountIndeterminateComponent if we determine the component
- // is a module-style component.
- renderExpirationTime = NoWork;
- currentlyRenderingFiber$1 = null;
-
- firstCurrentHook = null;
- currentHook = null;
- firstWorkInProgressHook = null;
- workInProgressHook = null;
-
- remainingExpirationTime = NoWork;
- componentUpdateQueue = null;
-
- // Always set during createWorkInProgress
- // isReRender = false;
-
- didScheduleRenderPhaseUpdate = false;
- renderPhaseUpdates = null;
- numberOfReRenders = 0;
-}
-
-function createHook() {
- return {
- memoizedState: null,
-
- baseState: null,
- queue: null,
- baseUpdate: null,
-
- next: null
- };
-}
-
-function cloneHook(hook) {
- return {
- memoizedState: hook.memoizedState,
-
- baseState: hook.baseState,
- queue: hook.queue,
- baseUpdate: hook.baseUpdate,
-
- next: null
- };
-}
-
-function createWorkInProgressHook() {
- if (workInProgressHook === null) {
- // This is the first hook in the list
- if (firstWorkInProgressHook === null) {
- isReRender = false;
- currentHook = firstCurrentHook;
- if (currentHook === null) {
- // This is a newly mounted hook
- workInProgressHook = createHook();
- } else {
- // Clone the current hook.
- workInProgressHook = cloneHook(currentHook);
- }
- firstWorkInProgressHook = workInProgressHook;
- } else {
- // There's already a work-in-progress. Reuse it.
- isReRender = true;
- currentHook = firstCurrentHook;
- workInProgressHook = firstWorkInProgressHook;
- }
- } else {
- if (workInProgressHook.next === null) {
- isReRender = false;
- var hook = void 0;
- if (currentHook === null) {
- // This is a newly mounted hook
- hook = createHook();
- } else {
- currentHook = currentHook.next;
- if (currentHook === null) {
- // This is a newly mounted hook
- hook = createHook();
- } else {
- // Clone the current hook.
- hook = cloneHook(currentHook);
- }
- }
- // Append to the end of the list
- workInProgressHook = workInProgressHook.next = hook;
- } else {
- // There's already a work-in-progress. Reuse it.
- isReRender = true;
- workInProgressHook = workInProgressHook.next;
- currentHook = currentHook !== null ? currentHook.next : null;
- }
- }
- return workInProgressHook;
-}
-
-function createFunctionComponentUpdateQueue() {
- return {
- lastEffect: null
- };
-}
-
-function basicStateReducer(state, action) {
- return typeof action === "function" ? action(state) : action;
-}
-
-function useContext(context, observedBits) {
- // Ensure we're in a function component (class components support only the
- // .unstable_read() form)
- resolveCurrentlyRenderingFiber();
- return readContext(context, observedBits);
-}
-
-function useState(initialState) {
- return useReducer(
- basicStateReducer,
- // useReducer has a special case to support lazy useState initializers
- initialState
- );
-}
-
-function useReducer(reducer, initialState, initialAction) {
- currentlyRenderingFiber$1 = resolveCurrentlyRenderingFiber();
- workInProgressHook = createWorkInProgressHook();
- var queue = workInProgressHook.queue;
- if (queue !== null) {
- // Already have a queue, so this is an update.
- if (isReRender) {
- // This is a re-render. Apply the new render phase updates to the previous
- var _dispatch2 = queue.dispatch;
- if (renderPhaseUpdates !== null) {
- // Render phase updates are stored in a map of queue -> linked list
- var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
- if (firstRenderPhaseUpdate !== undefined) {
- renderPhaseUpdates.delete(queue);
- var newState = workInProgressHook.memoizedState;
- var update = firstRenderPhaseUpdate;
- do {
- // Process this render phase update. We don't have to check the
- // priority because it will always be the same as the current
- // render's.
- var _action = update.action;
- newState = reducer(newState, _action);
- update = update.next;
- } while (update !== null);
-
- workInProgressHook.memoizedState = newState;
-
- // Don't persist the state accumlated from the render phase updates to
- // the base state unless the queue is empty.
- // TODO: Not sure if this is the desired semantics, but it's what we
- // do for gDSFP. I can't remember why.
- if (workInProgressHook.baseUpdate === queue.last) {
- workInProgressHook.baseState = newState;
- }
-
- return [newState, _dispatch2];
- }
- }
- return [workInProgressHook.memoizedState, _dispatch2];
- }
-
- // The last update in the entire queue
- var _last = queue.last;
- // The last update that is part of the base state.
- var _baseUpdate = workInProgressHook.baseUpdate;
-
- // Find the first unprocessed update.
- var first = void 0;
- if (_baseUpdate !== null) {
- if (_last !== null) {
- // For the first update, the queue is a circular linked list where
- // `queue.last.next = queue.first`. Once the first update commits, and
- // the `baseUpdate` is no longer empty, we can unravel the list.
- _last.next = null;
- }
- first = _baseUpdate.next;
- } else {
- first = _last !== null ? _last.next : null;
- }
- if (first !== null) {
- var _newState = workInProgressHook.baseState;
- var newBaseState = null;
- var newBaseUpdate = null;
- var prevUpdate = _baseUpdate;
- var _update = first;
- var didSkip = false;
- do {
- var updateExpirationTime = _update.expirationTime;
- if (updateExpirationTime < renderExpirationTime) {
- // Priority is insufficient. Skip this update. If this is the first
- // skipped update, the previous update/state is the new base
- // update/state.
- if (!didSkip) {
- didSkip = true;
- newBaseUpdate = prevUpdate;
- newBaseState = _newState;
- }
- // Update the remaining priority in the queue.
- if (updateExpirationTime > remainingExpirationTime) {
- remainingExpirationTime = updateExpirationTime;
- }
- } else {
- // Process this update.
- var _action2 = _update.action;
- _newState = reducer(_newState, _action2);
- }
- prevUpdate = _update;
- _update = _update.next;
- } while (_update !== null && _update !== first);
-
- if (!didSkip) {
- newBaseUpdate = prevUpdate;
- newBaseState = _newState;
- }
-
- workInProgressHook.memoizedState = _newState;
- workInProgressHook.baseUpdate = newBaseUpdate;
- workInProgressHook.baseState = newBaseState;
- }
-
- var _dispatch = queue.dispatch;
- return [workInProgressHook.memoizedState, _dispatch];
- }
-
- // There's no existing queue, so this is the initial render.
- if (reducer === basicStateReducer) {
- // Special case for `useState`.
- if (typeof initialState === "function") {
- initialState = initialState();
- }
- } else if (initialAction !== undefined && initialAction !== null) {
- initialState = reducer(initialState, initialAction);
- }
- workInProgressHook.memoizedState = workInProgressHook.baseState = initialState;
- queue = workInProgressHook.queue = {
- last: null,
- dispatch: null
- };
- var dispatch = (queue.dispatch = dispatchAction.bind(
- null,
- currentlyRenderingFiber$1,
- queue
- ));
- return [workInProgressHook.memoizedState, dispatch];
-}
-
-function pushEffect(tag, create, destroy, inputs) {
- var effect = {
- tag: tag,
- create: create,
- destroy: destroy,
- inputs: inputs,
- // Circular
- next: null
- };
- if (componentUpdateQueue === null) {
- componentUpdateQueue = createFunctionComponentUpdateQueue();
- componentUpdateQueue.lastEffect = effect.next = effect;
- } else {
- var _lastEffect = componentUpdateQueue.lastEffect;
- if (_lastEffect === null) {
- componentUpdateQueue.lastEffect = effect.next = effect;
- } else {
- var firstEffect = _lastEffect.next;
- _lastEffect.next = effect;
- effect.next = firstEffect;
- componentUpdateQueue.lastEffect = effect;
- }
- }
- return effect;
-}
-
-function useRef(initialValue) {
- currentlyRenderingFiber$1 = resolveCurrentlyRenderingFiber();
- workInProgressHook = createWorkInProgressHook();
- var ref = void 0;
-
- if (workInProgressHook.memoizedState === null) {
- ref = { current: initialValue };
- {
- Object.seal(ref);
- }
- workInProgressHook.memoizedState = ref;
- } else {
- ref = workInProgressHook.memoizedState;
- }
- return ref;
-}
-
-function useLayoutEffect(create, inputs) {
- useEffectImpl(Update, UnmountMutation | MountLayout, create, inputs);
-}
-
-function useEffect(create, inputs) {
- useEffectImpl(
- Update | Passive,
- UnmountPassive | MountPassive,
- create,
- inputs
- );
-}
-
-function useEffectImpl(fiberEffectTag, hookEffectTag, create, inputs) {
- currentlyRenderingFiber$1 = resolveCurrentlyRenderingFiber();
- workInProgressHook = createWorkInProgressHook();
-
- var nextInputs = inputs !== undefined && inputs !== null ? inputs : [create];
- var destroy = null;
- if (currentHook !== null) {
- var prevEffect = currentHook.memoizedState;
- destroy = prevEffect.destroy;
- if (areHookInputsEqual(nextInputs, prevEffect.inputs)) {
- pushEffect(NoEffect$1, create, destroy, nextInputs);
- return;
- }
- }
-
- currentlyRenderingFiber$1.effectTag |= fiberEffectTag;
- workInProgressHook.memoizedState = pushEffect(
- hookEffectTag,
- create,
- destroy,
- nextInputs
- );
-}
-
-function useImperativeMethods(ref, create, inputs) {
- // TODO: If inputs are provided, should we skip comparing the ref itself?
- var nextInputs =
- inputs !== null && inputs !== undefined
- ? inputs.concat([ref])
- : [ref, create];
-
- // TODO: I've implemented this on top of useEffect because it's almost the
- // same thing, and it would require an equal amount of code. It doesn't seem
- // like a common enough use case to justify the additional size.
- useLayoutEffect(function() {
- if (typeof ref === "function") {
- var refCallback = ref;
- var _inst = create();
- refCallback(_inst);
- return function() {
- return refCallback(null);
- };
- } else if (ref !== null && ref !== undefined) {
- var refObject = ref;
- var _inst2 = create();
- refObject.current = _inst2;
- return function() {
- refObject.current = null;
- };
- }
- }, nextInputs);
-}
-
-function useCallback(callback, inputs) {
- currentlyRenderingFiber$1 = resolveCurrentlyRenderingFiber();
- workInProgressHook = createWorkInProgressHook();
-
- var nextInputs =
- inputs !== undefined && inputs !== null ? inputs : [callback];
-
- var prevState = workInProgressHook.memoizedState;
- if (prevState !== null) {
- var prevInputs = prevState[1];
- if (areHookInputsEqual(nextInputs, prevInputs)) {
- return prevState[0];
- }
- }
- workInProgressHook.memoizedState = [callback, nextInputs];
- return callback;
-}
-
-function useMemo(nextCreate, inputs) {
- currentlyRenderingFiber$1 = resolveCurrentlyRenderingFiber();
- workInProgressHook = createWorkInProgressHook();
-
- var nextInputs =
- inputs !== undefined && inputs !== null ? inputs : [nextCreate];
-
- var prevState = workInProgressHook.memoizedState;
- if (prevState !== null) {
- var prevInputs = prevState[1];
- if (areHookInputsEqual(nextInputs, prevInputs)) {
- return prevState[0];
- }
- }
-
- var nextValue = nextCreate();
- workInProgressHook.memoizedState = [nextValue, nextInputs];
- return nextValue;
-}
-
-function dispatchAction(fiber, queue, action) {
- invariant(
- numberOfReRenders < RE_RENDER_LIMIT,
- "Too many re-renders. React limits the number of renders to prevent " +
- "an infinite loop."
- );
-
- var alternate = fiber.alternate;
- if (
- fiber === currentlyRenderingFiber$1 ||
- (alternate !== null && alternate === currentlyRenderingFiber$1)
- ) {
- // This is a render phase update. Stash it in a lazily-created map of
- // queue -> linked list of updates. After this render pass, we'll restart
- // and apply the stashed updates on top of the work-in-progress hook.
- didScheduleRenderPhaseUpdate = true;
- var update = {
- expirationTime: renderExpirationTime,
- action: action,
- next: null
- };
- if (renderPhaseUpdates === null) {
- renderPhaseUpdates = new Map();
- }
- var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
- if (firstRenderPhaseUpdate === undefined) {
- renderPhaseUpdates.set(queue, update);
- } else {
- // Append the update to the end of the list.
- var lastRenderPhaseUpdate = firstRenderPhaseUpdate;
- while (lastRenderPhaseUpdate.next !== null) {
- lastRenderPhaseUpdate = lastRenderPhaseUpdate.next;
- }
- lastRenderPhaseUpdate.next = update;
- }
- } else {
- var currentTime = requestCurrentTime();
- var _expirationTime = computeExpirationForFiber(currentTime, fiber);
- var _update2 = {
- expirationTime: _expirationTime,
- action: action,
- next: null
- };
- flushPassiveEffects();
- // Append the update to the end of the list.
- var _last2 = queue.last;
- if (_last2 === null) {
- // This is the first update. Create a circular list.
- _update2.next = _update2;
- } else {
- var first = _last2.next;
- if (first !== null) {
- // Still circular.
- _update2.next = first;
- }
- _last2.next = _update2;
- }
- queue.last = _update2;
- scheduleWork(fiber, _expirationTime);
- }
-}
-
-var NO_CONTEXT = {};
-
-var contextStackCursor$1 = createCursor(NO_CONTEXT);
-var contextFiberStackCursor = createCursor(NO_CONTEXT);
-var rootInstanceStackCursor = createCursor(NO_CONTEXT);
-
-function requiredContext(c) {
- invariant(
- c !== NO_CONTEXT,
- "Expected host context to exist. This error is likely caused by a bug " +
- "in React. Please file an issue."
- );
- return c;
-}
-
-function getRootHostContainer() {
- var rootInstance = requiredContext(rootInstanceStackCursor.current);
- return rootInstance;
-}
-
-function pushHostContainer(fiber, nextRootInstance) {
- // Push current root instance onto the stack;
- // This allows us to reset root when portals are popped.
- push(rootInstanceStackCursor, nextRootInstance, fiber);
- // Track the context and the Fiber that provided it.
- // This enables us to pop only Fibers that provide unique contexts.
- push(contextFiberStackCursor, fiber, fiber);
-
- // Finally, we need to push the host context to the stack.
- // However, we can't just call getRootHostContext() and push it because
- // we'd have a different number of entries on the stack depending on
- // whether getRootHostContext() throws somewhere in renderer code or not.
- // So we push an empty value first. This lets us safely unwind on errors.
- push(contextStackCursor$1, NO_CONTEXT, fiber);
- var nextRootContext = getRootHostContext(nextRootInstance);
- // Now that we know this function doesn't throw, replace it.
- pop(contextStackCursor$1, fiber);
- push(contextStackCursor$1, nextRootContext, fiber);
-}
-
-function popHostContainer(fiber) {
- pop(contextStackCursor$1, fiber);
- pop(contextFiberStackCursor, fiber);
- pop(rootInstanceStackCursor, fiber);
-}
-
-function getHostContext() {
- var context = requiredContext(contextStackCursor$1.current);
- return context;
-}
-
-function pushHostContext(fiber) {
- var rootInstance = requiredContext(rootInstanceStackCursor.current);
- var context = requiredContext(contextStackCursor$1.current);
- var nextContext = getChildHostContext(context, fiber.type, rootInstance);
-
- // Don't push this Fiber's context unless it's unique.
- if (context === nextContext) {
- return;
- }
-
- // Track the context and the Fiber that provided it.
- // This enables us to pop only Fibers that provide unique contexts.
- push(contextFiberStackCursor, fiber, fiber);
- push(contextStackCursor$1, nextContext, fiber);
-}
-
-function popHostContext(fiber) {
- // Do not pop unless this Fiber provided the current context.
- // pushHostContext() only pushes Fibers that provide unique contexts.
- if (contextFiberStackCursor.current !== fiber) {
- return;
- }
-
- pop(contextStackCursor$1, fiber);
- pop(contextFiberStackCursor, fiber);
-}
-
-var commitTime = 0;
-var profilerStartTime = -1;
-
-function getCommitTime() {
- return commitTime;
-}
-
-function recordCommitTime() {
- if (!enableProfilerTimer) {
- return;
- }
- commitTime = now$$1();
-}
-
-function startProfilerTimer(fiber) {
- if (!enableProfilerTimer) {
- return;
- }
-
- profilerStartTime = now$$1();
-
- if (fiber.actualStartTime < 0) {
- fiber.actualStartTime = now$$1();
- }
-}
-
-function stopProfilerTimerIfRunning(fiber) {
- if (!enableProfilerTimer) {
- return;
- }
- profilerStartTime = -1;
-}
-
-function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) {
- if (!enableProfilerTimer) {
- return;
- }
-
- if (profilerStartTime >= 0) {
- var elapsedTime = now$$1() - profilerStartTime;
- fiber.actualDuration += elapsedTime;
- if (overrideBaseTime) {
- fiber.selfBaseDuration = elapsedTime;
- }
- profilerStartTime = -1;
- }
-}
-
-/*eslint-disable no-self-compare */
-
-var hasOwnProperty = Object.prototype.hasOwnProperty;
-
/**
* inlined Object.is polyfill to avoid requiring consumers ship their own
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
*/
function is(x, y) {
- // SameValue algorithm
- if (x === y) {
- // Steps 1-5, 7-10
- // Steps 6.b-6.e: +0 != -0
- // Added the nonzero y check to make Flow happy, but it is redundant
- return x !== 0 || y !== 0 || 1 / x === 1 / y;
- } else {
- // Step 6.a: NaN == NaN
- return x !== x && y !== y;
- }
+ return (
+ (x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y) // eslint-disable-line no-self-compare
+ );
}
+var hasOwnProperty = Object.prototype.hasOwnProperty;
+
/**
* Performs equality by iterating through keys on an object and returning false
* when any key has values which are not strictly equal between the arguments.
@@ -8317,19 +6777,19 @@
}
}
);
+ // Handle synchronous thenables.
+ switch (lazyComponent._status) {
+ case Resolved:
+ return lazyComponent._result;
+ case Rejected:
+ throw lazyComponent._result;
+ }
lazyComponent._result = _thenable;
throw _thenable;
}
}
}
-var ReactCurrentOwner$4 = ReactSharedInternals.ReactCurrentOwner;
-
-function readContext$1(contextType) {
- var dispatcher = ReactCurrentOwner$4.currentDispatcher;
- return dispatcher.readContext(contextType);
-}
-
var fakeInternalInstance = {};
var isArray$1 = Array.isArray;
@@ -8839,7 +7299,7 @@
}
}
- context = readContext$1(contextType);
+ context = readContext(contextType);
} else {
unmaskedContext = getUnmaskedContext(workInProgress, ctor, true);
var contextTypes = ctor.contextTypes;
@@ -9041,7 +7501,7 @@
var contextType = ctor.contextType;
if (typeof contextType === "object" && contextType !== null) {
- instance.context = readContext$1(contextType);
+ instance.context = readContext(contextType);
} else {
var unmaskedContext = getUnmaskedContext(workInProgress, ctor, true);
instance.context = getMaskedContext(workInProgress, unmaskedContext);
@@ -9149,7 +7609,7 @@
var contextType = ctor.contextType;
var nextContext = void 0;
if (typeof contextType === "object" && contextType !== null) {
- nextContext = readContext$1(contextType);
+ nextContext = readContext(contextType);
} else {
var nextLegacyUnmaskedContext = getUnmaskedContext(
workInProgress,
@@ -9298,7 +7758,7 @@
var contextType = ctor.contextType;
var nextContext = void 0;
if (typeof contextType === "object" && contextType !== null) {
- nextContext = readContext$1(contextType);
+ nextContext = readContext(contextType);
} else {
var nextUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true);
nextContext = getMaskedContext(workInProgress, nextUnmaskedContext);
@@ -9488,7 +7948,7 @@
child._store.validated = true;
var currentComponentErrorInfo =
- "Each child in an array or iterator should have a unique " +
+ "Each child in a list should have a unique " +
'"key" prop. See https://fb.me/react-warning-keys for ' +
"more information." +
getCurrentFiberStackInDev();
@@ -9499,7 +7959,7 @@
warning$1(
false,
- "Each child in an array or iterator should have a unique " +
+ "Each child in a list should have a unique " +
'"key" prop. See https://fb.me/react-warning-keys for ' +
"more information."
);
@@ -9542,7 +8002,8 @@
var ownerFiber = owner;
invariant(
ownerFiber.tag === ClassComponent,
- "Function components cannot have refs."
+ "Function components cannot have refs. " +
+ "Did you mean to use React.forwardRef()?"
);
inst = ownerFiber.stateNode;
}
@@ -10106,7 +8567,7 @@
newChildren,
expirationTime
) {
- // This algorithm can't optimize by searching from boths ends since we
+ // This algorithm can't optimize by searching from both ends since we
// don't have backpointers on fibers. I'm trying to see how far we can get
// with that model. If it ends up not being worth the tradeoffs, we can
// add it later.
@@ -10748,6 +9209,1387 @@
newChild.sibling = null;
}
+var NO_CONTEXT = {};
+
+var contextStackCursor$1 = createCursor(NO_CONTEXT);
+var contextFiberStackCursor = createCursor(NO_CONTEXT);
+var rootInstanceStackCursor = createCursor(NO_CONTEXT);
+
+function requiredContext(c) {
+ invariant(
+ c !== NO_CONTEXT,
+ "Expected host context to exist. This error is likely caused by a bug " +
+ "in React. Please file an issue."
+ );
+ return c;
+}
+
+function getRootHostContainer() {
+ var rootInstance = requiredContext(rootInstanceStackCursor.current);
+ return rootInstance;
+}
+
+function pushHostContainer(fiber, nextRootInstance) {
+ // Push current root instance onto the stack;
+ // This allows us to reset root when portals are popped.
+ push(rootInstanceStackCursor, nextRootInstance, fiber);
+ // Track the context and the Fiber that provided it.
+ // This enables us to pop only Fibers that provide unique contexts.
+ push(contextFiberStackCursor, fiber, fiber);
+
+ // Finally, we need to push the host context to the stack.
+ // However, we can't just call getRootHostContext() and push it because
+ // we'd have a different number of entries on the stack depending on
+ // whether getRootHostContext() throws somewhere in renderer code or not.
+ // So we push an empty value first. This lets us safely unwind on errors.
+ push(contextStackCursor$1, NO_CONTEXT, fiber);
+ var nextRootContext = getRootHostContext(nextRootInstance);
+ // Now that we know this function doesn't throw, replace it.
+ pop(contextStackCursor$1, fiber);
+ push(contextStackCursor$1, nextRootContext, fiber);
+}
+
+function popHostContainer(fiber) {
+ pop(contextStackCursor$1, fiber);
+ pop(contextFiberStackCursor, fiber);
+ pop(rootInstanceStackCursor, fiber);
+}
+
+function getHostContext() {
+ var context = requiredContext(contextStackCursor$1.current);
+ return context;
+}
+
+function pushHostContext(fiber) {
+ var rootInstance = requiredContext(rootInstanceStackCursor.current);
+ var context = requiredContext(contextStackCursor$1.current);
+ var nextContext = getChildHostContext(context, fiber.type, rootInstance);
+
+ // Don't push this Fiber's context unless it's unique.
+ if (context === nextContext) {
+ return;
+ }
+
+ // Track the context and the Fiber that provided it.
+ // This enables us to pop only Fibers that provide unique contexts.
+ push(contextFiberStackCursor, fiber, fiber);
+ push(contextStackCursor$1, nextContext, fiber);
+}
+
+function popHostContext(fiber) {
+ // Do not pop unless this Fiber provided the current context.
+ // pushHostContext() only pushes Fibers that provide unique contexts.
+ if (contextFiberStackCursor.current !== fiber) {
+ return;
+ }
+
+ pop(contextStackCursor$1, fiber);
+ pop(contextFiberStackCursor, fiber);
+}
+
+var NoEffect$1 = /* */ 0;
+var UnmountSnapshot = /* */ 2;
+var UnmountMutation = /* */ 4;
+var MountMutation = /* */ 8;
+var UnmountLayout = /* */ 16;
+var MountLayout = /* */ 32;
+var MountPassive = /* */ 64;
+var UnmountPassive = /* */ 128;
+
+var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher;
+
+var didWarnAboutMismatchedHooksForComponent = void 0;
+{
+ didWarnAboutMismatchedHooksForComponent = new Set();
+}
+
+// These are set right before calling the component.
+var renderExpirationTime = NoWork;
+// The work-in-progress fiber. I've named it differently to distinguish it from
+// the work-in-progress hook.
+var currentlyRenderingFiber$1 = null;
+
+// Hooks are stored as a linked list on the fiber's memoizedState field. The
+// current hook list is the list that belongs to the current fiber. The
+// work-in-progress hook list is a new list that will be added to the
+// work-in-progress fiber.
+var firstCurrentHook = null;
+var currentHook = null;
+var nextCurrentHook = null;
+var firstWorkInProgressHook = null;
+var workInProgressHook = null;
+var nextWorkInProgressHook = null;
+
+var remainingExpirationTime = NoWork;
+var componentUpdateQueue = null;
+var sideEffectTag = 0;
+
+// Updates scheduled during render will trigger an immediate re-render at the
+// end of the current pass. We can't store these updates on the normal queue,
+// because if the work is aborted, they should be discarded. Because this is
+// a relatively rare case, we also don't want to add an additional field to
+// either the hook or queue object types. So we store them in a lazily create
+// map of queue -> render-phase updates, which are discarded once the component
+// completes without re-rendering.
+
+// Whether an update was scheduled during the currently executing render pass.
+var didScheduleRenderPhaseUpdate = false;
+// Lazily created map of render-phase updates
+var renderPhaseUpdates = null;
+// Counter to prevent infinite loops.
+var numberOfReRenders = 0;
+var RE_RENDER_LIMIT = 25;
+
+// In DEV, this is the name of the currently executing primitive hook
+var currentHookNameInDev = null;
+
+function warnOnHookMismatchInDev() {
+ {
+ var componentName = getComponentName(currentlyRenderingFiber$1.type);
+ if (!didWarnAboutMismatchedHooksForComponent.has(componentName)) {
+ didWarnAboutMismatchedHooksForComponent.add(componentName);
+
+ var secondColumnStart = 22;
+
+ var table = "";
+ var prevHook = firstCurrentHook;
+ var nextHook = firstWorkInProgressHook;
+ var n = 1;
+ while (prevHook !== null && nextHook !== null) {
+ var oldHookName = prevHook._debugType;
+ var newHookName = nextHook._debugType;
+
+ var row = n + ". " + oldHookName;
+
+ // Extra space so second column lines up
+ // lol @ IE not supporting String#repeat
+ while (row.length < secondColumnStart) {
+ row += " ";
+ }
+
+ row += newHookName + "\n";
+
+ table += row;
+ prevHook = prevHook.next;
+ nextHook = nextHook.next;
+ n++;
+ }
+
+ warning$1(
+ false,
+ "React has detected a change in the order of Hooks called by %s. " +
+ "This will lead to bugs and errors if not fixed. " +
+ "For more information, read the Rules of Hooks: https://fb.me/rules-of-hooks\n\n" +
+ " Previous render Next render\n" +
+ " -------------------------------\n" +
+ "%s" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
+ componentName,
+ table
+ );
+ }
+ }
+}
+
+function throwInvalidHookError() {
+ invariant(
+ false,
+ "Hooks can only be called inside the body of a function component. " +
+ "(https://fb.me/react-invalid-hook-call)"
+ );
+}
+
+function areHookInputsEqual(nextDeps, prevDeps) {
+ if (prevDeps === null) {
+ {
+ warning$1(
+ false,
+ "%s received a final argument during this render, but not during " +
+ "the previous render. Even though the final argument is optional, " +
+ "its type cannot change between renders.",
+ currentHookNameInDev
+ );
+ }
+ return false;
+ }
+
+ {
+ // Don't bother comparing lengths in prod because these arrays should be
+ // passed inline.
+ if (nextDeps.length !== prevDeps.length) {
+ warning$1(
+ false,
+ "The final argument passed to %s changed size between renders. The " +
+ "order and size of this array must remain constant.\n\n" +
+ "Previous: %s\n" +
+ "Incoming: %s",
+ currentHookNameInDev,
+ "[" + nextDeps.join(", ") + "]",
+ "[" + prevDeps.join(", ") + "]"
+ );
+ }
+ }
+ for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
+ if (is(nextDeps[i], prevDeps[i])) {
+ continue;
+ }
+ return false;
+ }
+ return true;
+}
+
+function renderWithHooks(
+ current,
+ workInProgress,
+ Component,
+ props,
+ refOrContext,
+ nextRenderExpirationTime
+) {
+ renderExpirationTime = nextRenderExpirationTime;
+ currentlyRenderingFiber$1 = workInProgress;
+ firstCurrentHook = nextCurrentHook =
+ current !== null ? current.memoizedState : null;
+
+ // The following should have already been reset
+ // currentHook = null;
+ // workInProgressHook = null;
+
+ // remainingExpirationTime = NoWork;
+ // componentUpdateQueue = null;
+
+ // didScheduleRenderPhaseUpdate = false;
+ // renderPhaseUpdates = null;
+ // numberOfReRenders = 0;
+ // sideEffectTag = 0;
+
+ {
+ ReactCurrentDispatcher$1.current =
+ nextCurrentHook === null
+ ? HooksDispatcherOnMountInDEV
+ : HooksDispatcherOnUpdateInDEV;
+ }
+
+ var children = Component(props, refOrContext);
+
+ if (didScheduleRenderPhaseUpdate) {
+ do {
+ didScheduleRenderPhaseUpdate = false;
+ numberOfReRenders += 1;
+
+ // Start over from the beginning of the list
+ firstCurrentHook = nextCurrentHook =
+ current !== null ? current.memoizedState : null;
+ nextWorkInProgressHook = firstWorkInProgressHook;
+
+ currentHook = null;
+ workInProgressHook = null;
+ componentUpdateQueue = null;
+
+ ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdateInDEV;
+
+ children = Component(props, refOrContext);
+ } while (didScheduleRenderPhaseUpdate);
+
+ renderPhaseUpdates = null;
+ numberOfReRenders = 0;
+ }
+
+ {
+ currentHookNameInDev = null;
+ }
+
+ // We can assume the previous dispatcher is always this one, since we set it
+ // at the beginning of the render phase and there's no re-entrancy.
+ ReactCurrentDispatcher$1.current = ContextOnlyDispatcher;
+
+ var renderedWork = currentlyRenderingFiber$1;
+
+ renderedWork.memoizedState = firstWorkInProgressHook;
+ renderedWork.expirationTime = remainingExpirationTime;
+ renderedWork.updateQueue = componentUpdateQueue;
+ renderedWork.effectTag |= sideEffectTag;
+
+ var didRenderTooFewHooks = currentHook !== null && currentHook.next !== null;
+
+ renderExpirationTime = NoWork;
+ currentlyRenderingFiber$1 = null;
+
+ firstCurrentHook = null;
+ currentHook = null;
+ nextCurrentHook = null;
+ firstWorkInProgressHook = null;
+ workInProgressHook = null;
+ nextWorkInProgressHook = null;
+
+ remainingExpirationTime = NoWork;
+ componentUpdateQueue = null;
+ sideEffectTag = 0;
+
+ // These were reset above
+ // didScheduleRenderPhaseUpdate = false;
+ // renderPhaseUpdates = null;
+ // numberOfReRenders = 0;
+
+ invariant(
+ !didRenderTooFewHooks,
+ "Rendered fewer hooks than expected. This may be caused by an accidental " +
+ "early return statement."
+ );
+
+ return children;
+}
+
+function bailoutHooks(current, workInProgress, expirationTime) {
+ workInProgress.updateQueue = current.updateQueue;
+ workInProgress.effectTag &= ~(Passive | Update);
+ if (current.expirationTime <= expirationTime) {
+ current.expirationTime = NoWork;
+ }
+}
+
+function resetHooks() {
+ // We can assume the previous dispatcher is always this one, since we set it
+ // at the beginning of the render phase and there's no re-entrancy.
+ ReactCurrentDispatcher$1.current = ContextOnlyDispatcher;
+
+ // This is used to reset the state of this module when a component throws.
+ // It's also called inside mountIndeterminateComponent if we determine the
+ // component is a module-style component.
+ renderExpirationTime = NoWork;
+ currentlyRenderingFiber$1 = null;
+
+ firstCurrentHook = null;
+ currentHook = null;
+ nextCurrentHook = null;
+ firstWorkInProgressHook = null;
+ workInProgressHook = null;
+ nextWorkInProgressHook = null;
+
+ remainingExpirationTime = NoWork;
+ componentUpdateQueue = null;
+ sideEffectTag = 0;
+
+ {
+ currentHookNameInDev = null;
+ }
+
+ didScheduleRenderPhaseUpdate = false;
+ renderPhaseUpdates = null;
+ numberOfReRenders = 0;
+}
+
+function mountWorkInProgressHook() {
+ var hook = {
+ memoizedState: null,
+
+ baseState: null,
+ queue: null,
+ baseUpdate: null,
+
+ next: null
+ };
+
+ {
+ hook._debugType = currentHookNameInDev;
+ }
+ if (workInProgressHook === null) {
+ // This is the first hook in the list
+ firstWorkInProgressHook = workInProgressHook = hook;
+ } else {
+ // Append to the end of the list
+ workInProgressHook = workInProgressHook.next = hook;
+ }
+ return workInProgressHook;
+}
+
+function updateWorkInProgressHook() {
+ // This function is used both for updates and for re-renders triggered by a
+ // render phase update. It assumes there is either a current hook we can
+ // clone, or a work-in-progress hook from a previous render pass that we can
+ // use as a base. When we reach the end of the base list, we must switch to
+ // the dispatcher used for mounts.
+ if (nextWorkInProgressHook !== null) {
+ // There's already a work-in-progress. Reuse it.
+ workInProgressHook = nextWorkInProgressHook;
+ nextWorkInProgressHook = workInProgressHook.next;
+
+ currentHook = nextCurrentHook;
+ nextCurrentHook = currentHook !== null ? currentHook.next : null;
+ } else {
+ // Clone from the current hook.
+ invariant(
+ nextCurrentHook !== null,
+ "Rendered more hooks than during the previous render."
+ );
+ currentHook = nextCurrentHook;
+
+ var newHook = {
+ memoizedState: currentHook.memoizedState,
+
+ baseState: currentHook.baseState,
+ queue: currentHook.queue,
+ baseUpdate: currentHook.baseUpdate,
+
+ next: null
+ };
+
+ if (workInProgressHook === null) {
+ // This is the first hook in the list.
+ workInProgressHook = firstWorkInProgressHook = newHook;
+ } else {
+ // Append to the end of the list.
+ workInProgressHook = workInProgressHook.next = newHook;
+ }
+ nextCurrentHook = currentHook.next;
+
+ {
+ newHook._debugType = currentHookNameInDev;
+ if (currentHookNameInDev !== currentHook._debugType) {
+ warnOnHookMismatchInDev();
+ }
+ }
+ }
+ return workInProgressHook;
+}
+
+function createFunctionComponentUpdateQueue() {
+ return {
+ lastEffect: null
+ };
+}
+
+function basicStateReducer(state, action) {
+ return typeof action === "function" ? action(state) : action;
+}
+
+function mountContext(context, observedBits) {
+ {
+ mountWorkInProgressHook();
+ }
+ return readContext(context, observedBits);
+}
+
+function updateContext(context, observedBits) {
+ {
+ updateWorkInProgressHook();
+ }
+ return readContext(context, observedBits);
+}
+
+function mountReducer(reducer, initialArg, init) {
+ var hook = mountWorkInProgressHook();
+ var initialState = void 0;
+ if (init !== undefined) {
+ initialState = init(initialArg);
+ } else {
+ initialState = initialArg;
+ }
+ hook.memoizedState = hook.baseState = initialState;
+ var queue = (hook.queue = {
+ last: null,
+ dispatch: null,
+ eagerReducer: reducer,
+ eagerState: initialState
+ });
+ var dispatch = (queue.dispatch = dispatchAction.bind(
+ null,
+ // Flow doesn't know this is non-null, but we do.
+ currentlyRenderingFiber$1,
+ queue
+ ));
+ return [hook.memoizedState, dispatch];
+}
+
+function updateReducer(reducer, initialArg, init) {
+ var hook = updateWorkInProgressHook();
+ var queue = hook.queue;
+ invariant(
+ queue !== null,
+ "Should have a queue. This is likely a bug in React. Please file an issue."
+ );
+
+ if (numberOfReRenders > 0) {
+ // This is a re-render. Apply the new render phase updates to the previous
+ var _dispatch = queue.dispatch;
+ if (renderPhaseUpdates !== null) {
+ // Render phase updates are stored in a map of queue -> linked list
+ var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+ if (firstRenderPhaseUpdate !== undefined) {
+ renderPhaseUpdates.delete(queue);
+ var newState = hook.memoizedState;
+ var update = firstRenderPhaseUpdate;
+ do {
+ // Process this render phase update. We don't have to check the
+ // priority because it will always be the same as the current
+ // render's.
+ var _action = update.action;
+ newState = reducer(newState, _action);
+ update = update.next;
+ } while (update !== null);
+
+ // Mark that the fiber performed work, but only if the new state is
+ // different from the current state.
+ if (!is(newState, hook.memoizedState)) {
+ markWorkInProgressReceivedUpdate();
+ }
+
+ hook.memoizedState = newState;
+ // Don't persist the state accumlated from the render phase updates to
+ // the base state unless the queue is empty.
+ // TODO: Not sure if this is the desired semantics, but it's what we
+ // do for gDSFP. I can't remember why.
+ if (hook.baseUpdate === queue.last) {
+ hook.baseState = newState;
+ }
+
+ queue.eagerReducer = reducer;
+ queue.eagerState = newState;
+
+ return [newState, _dispatch];
+ }
+ }
+ return [hook.memoizedState, _dispatch];
+ }
+
+ // The last update in the entire queue
+ var last = queue.last;
+ // The last update that is part of the base state.
+ var baseUpdate = hook.baseUpdate;
+ var baseState = hook.baseState;
+
+ // Find the first unprocessed update.
+ var first = void 0;
+ if (baseUpdate !== null) {
+ if (last !== null) {
+ // For the first update, the queue is a circular linked list where
+ // `queue.last.next = queue.first`. Once the first update commits, and
+ // the `baseUpdate` is no longer empty, we can unravel the list.
+ last.next = null;
+ }
+ first = baseUpdate.next;
+ } else {
+ first = last !== null ? last.next : null;
+ }
+ if (first !== null) {
+ var _newState = baseState;
+ var newBaseState = null;
+ var newBaseUpdate = null;
+ var prevUpdate = baseUpdate;
+ var _update = first;
+ var didSkip = false;
+ do {
+ var updateExpirationTime = _update.expirationTime;
+ if (updateExpirationTime < renderExpirationTime) {
+ // Priority is insufficient. Skip this update. If this is the first
+ // skipped update, the previous update/state is the new base
+ // update/state.
+ if (!didSkip) {
+ didSkip = true;
+ newBaseUpdate = prevUpdate;
+ newBaseState = _newState;
+ }
+ // Update the remaining priority in the queue.
+ if (updateExpirationTime > remainingExpirationTime) {
+ remainingExpirationTime = updateExpirationTime;
+ }
+ } else {
+ // Process this update.
+ if (_update.eagerReducer === reducer) {
+ // If this update was processed eagerly, and its reducer matches the
+ // current reducer, we can use the eagerly computed state.
+ _newState = _update.eagerState;
+ } else {
+ var _action2 = _update.action;
+ _newState = reducer(_newState, _action2);
+ }
+ }
+ prevUpdate = _update;
+ _update = _update.next;
+ } while (_update !== null && _update !== first);
+
+ if (!didSkip) {
+ newBaseUpdate = prevUpdate;
+ newBaseState = _newState;
+ }
+
+ // Mark that the fiber performed work, but only if the new state is
+ // different from the current state.
+ if (!is(_newState, hook.memoizedState)) {
+ markWorkInProgressReceivedUpdate();
+ }
+
+ hook.memoizedState = _newState;
+ hook.baseUpdate = newBaseUpdate;
+ hook.baseState = newBaseState;
+
+ queue.eagerReducer = reducer;
+ queue.eagerState = _newState;
+ }
+
+ var dispatch = queue.dispatch;
+ return [hook.memoizedState, dispatch];
+}
+
+function mountState(initialState) {
+ var hook = mountWorkInProgressHook();
+ if (typeof initialState === "function") {
+ initialState = initialState();
+ }
+ hook.memoizedState = hook.baseState = initialState;
+ var queue = (hook.queue = {
+ last: null,
+ dispatch: null,
+ eagerReducer: basicStateReducer,
+ eagerState: initialState
+ });
+ var dispatch = (queue.dispatch = dispatchAction.bind(
+ null,
+ // Flow doesn't know this is non-null, but we do.
+ currentlyRenderingFiber$1,
+ queue
+ ));
+ return [hook.memoizedState, dispatch];
+}
+
+function updateState(initialState) {
+ return updateReducer(basicStateReducer, initialState);
+}
+
+function pushEffect(tag, create, destroy, deps) {
+ var effect = {
+ tag: tag,
+ create: create,
+ destroy: destroy,
+ deps: deps,
+ // Circular
+ next: null
+ };
+ if (componentUpdateQueue === null) {
+ componentUpdateQueue = createFunctionComponentUpdateQueue();
+ componentUpdateQueue.lastEffect = effect.next = effect;
+ } else {
+ var _lastEffect = componentUpdateQueue.lastEffect;
+ if (_lastEffect === null) {
+ componentUpdateQueue.lastEffect = effect.next = effect;
+ } else {
+ var firstEffect = _lastEffect.next;
+ _lastEffect.next = effect;
+ effect.next = firstEffect;
+ componentUpdateQueue.lastEffect = effect;
+ }
+ }
+ return effect;
+}
+
+function mountRef(initialValue) {
+ var hook = mountWorkInProgressHook();
+ var ref = { current: initialValue };
+ {
+ Object.seal(ref);
+ }
+ hook.memoizedState = ref;
+ return ref;
+}
+
+function updateRef(initialValue) {
+ var hook = updateWorkInProgressHook();
+ return hook.memoizedState;
+}
+
+function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) {
+ var hook = mountWorkInProgressHook();
+ var nextDeps = deps === undefined ? null : deps;
+ sideEffectTag |= fiberEffectTag;
+ hook.memoizedState = pushEffect(hookEffectTag, create, undefined, nextDeps);
+}
+
+function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) {
+ var hook = updateWorkInProgressHook();
+ var nextDeps = deps === undefined ? null : deps;
+ var destroy = undefined;
+
+ if (currentHook !== null) {
+ var prevEffect = currentHook.memoizedState;
+ destroy = prevEffect.destroy;
+ if (nextDeps !== null) {
+ var prevDeps = prevEffect.deps;
+ if (areHookInputsEqual(nextDeps, prevDeps)) {
+ pushEffect(NoEffect$1, create, destroy, nextDeps);
+ return;
+ }
+ }
+ }
+
+ sideEffectTag |= fiberEffectTag;
+ hook.memoizedState = pushEffect(hookEffectTag, create, destroy, nextDeps);
+}
+
+function mountEffect(create, deps) {
+ return mountEffectImpl(
+ Update | Passive,
+ UnmountPassive | MountPassive,
+ create,
+ deps
+ );
+}
+
+function updateEffect(create, deps) {
+ return updateEffectImpl(
+ Update | Passive,
+ UnmountPassive | MountPassive,
+ create,
+ deps
+ );
+}
+
+function mountLayoutEffect(create, deps) {
+ return mountEffectImpl(Update, UnmountMutation | MountLayout, create, deps);
+}
+
+function updateLayoutEffect(create, deps) {
+ return updateEffectImpl(Update, UnmountMutation | MountLayout, create, deps);
+}
+
+function imperativeHandleEffect(create, ref) {
+ if (typeof ref === "function") {
+ var refCallback = ref;
+ var _inst = create();
+ refCallback(_inst);
+ return function() {
+ refCallback(null);
+ };
+ } else if (ref !== null && ref !== undefined) {
+ var refObject = ref;
+ {
+ !refObject.hasOwnProperty("current")
+ ? warning$1(
+ false,
+ "Expected useImperativeHandle() first argument to either be a " +
+ "ref callback or React.createRef() object. Instead received: %s.",
+ "an object with keys {" + Object.keys(refObject).join(", ") + "}"
+ )
+ : void 0;
+ }
+ var _inst2 = create();
+ refObject.current = _inst2;
+ return function() {
+ refObject.current = null;
+ };
+ }
+}
+
+function mountImperativeHandle(ref, create, deps) {
+ {
+ !(typeof create === "function")
+ ? warning$1(
+ false,
+ "Expected useImperativeHandle() second argument to be a function " +
+ "that creates a handle. Instead received: %s.",
+ create !== null ? typeof create : "null"
+ )
+ : void 0;
+ }
+
+ // TODO: If deps are provided, should we skip comparing the ref itself?
+ var effectDeps =
+ deps !== null && deps !== undefined ? deps.concat([ref]) : null;
+
+ return mountEffectImpl(
+ Update,
+ UnmountMutation | MountLayout,
+ imperativeHandleEffect.bind(null, create, ref),
+ effectDeps
+ );
+}
+
+function updateImperativeHandle(ref, create, deps) {
+ {
+ !(typeof create === "function")
+ ? warning$1(
+ false,
+ "Expected useImperativeHandle() second argument to be a function " +
+ "that creates a handle. Instead received: %s.",
+ create !== null ? typeof create : "null"
+ )
+ : void 0;
+ }
+
+ // TODO: If deps are provided, should we skip comparing the ref itself?
+ var effectDeps =
+ deps !== null && deps !== undefined ? deps.concat([ref]) : null;
+
+ return updateEffectImpl(
+ Update,
+ UnmountMutation | MountLayout,
+ imperativeHandleEffect.bind(null, create, ref),
+ effectDeps
+ );
+}
+
+function mountDebugValue(value, formatterFn) {
+ // This hook is normally a no-op.
+ // The react-debug-hooks package injects its own implementation
+ // so that e.g. DevTools can display custom hook values.
+}
+
+var updateDebugValue = mountDebugValue;
+
+function mountCallback(callback, deps) {
+ var hook = mountWorkInProgressHook();
+ var nextDeps = deps === undefined ? null : deps;
+ hook.memoizedState = [callback, nextDeps];
+ return callback;
+}
+
+function updateCallback(callback, deps) {
+ var hook = updateWorkInProgressHook();
+ var nextDeps = deps === undefined ? null : deps;
+ var prevState = hook.memoizedState;
+ if (prevState !== null) {
+ if (nextDeps !== null) {
+ var prevDeps = prevState[1];
+ if (areHookInputsEqual(nextDeps, prevDeps)) {
+ return prevState[0];
+ }
+ }
+ }
+ hook.memoizedState = [callback, nextDeps];
+ return callback;
+}
+
+function mountMemo(nextCreate, deps) {
+ var hook = mountWorkInProgressHook();
+ var nextDeps = deps === undefined ? null : deps;
+ var nextValue = nextCreate();
+ hook.memoizedState = [nextValue, nextDeps];
+ return nextValue;
+}
+
+function updateMemo(nextCreate, deps) {
+ var hook = updateWorkInProgressHook();
+ var nextDeps = deps === undefined ? null : deps;
+ var prevState = hook.memoizedState;
+ if (prevState !== null) {
+ // Assume these are defined. If they're not, areHookInputsEqual will warn.
+ if (nextDeps !== null) {
+ var prevDeps = prevState[1];
+ if (areHookInputsEqual(nextDeps, prevDeps)) {
+ return prevState[0];
+ }
+ }
+ }
+ var nextValue = nextCreate();
+ hook.memoizedState = [nextValue, nextDeps];
+ return nextValue;
+}
+
+// in a test-like environment, we want to warn if dispatchAction()
+// is called outside of a batchedUpdates/TestUtils.act(...) call.
+var shouldWarnForUnbatchedSetState = false;
+
+{
+ // jest isn't a 'global', it's just exposed to tests via a wrapped function
+ // further, this isn't a test file, so flow doesn't recognize the symbol. So...
+ // $FlowExpectedError - because requirements don't give a damn about your type sigs.
+ if ("undefined" !== typeof jest) {
+ shouldWarnForUnbatchedSetState = true;
+ }
+}
+
+function dispatchAction(fiber, queue, action) {
+ invariant(
+ numberOfReRenders < RE_RENDER_LIMIT,
+ "Too many re-renders. React limits the number of renders to prevent " +
+ "an infinite loop."
+ );
+
+ {
+ !(arguments.length <= 3)
+ ? warning$1(
+ false,
+ "State updates from the useState() and useReducer() Hooks don't support the " +
+ "second callback argument. To execute a side effect after " +
+ "rendering, declare it in the component body with useEffect()."
+ )
+ : void 0;
+ }
+
+ var alternate = fiber.alternate;
+ if (
+ fiber === currentlyRenderingFiber$1 ||
+ (alternate !== null && alternate === currentlyRenderingFiber$1)
+ ) {
+ // This is a render phase update. Stash it in a lazily-created map of
+ // queue -> linked list of updates. After this render pass, we'll restart
+ // and apply the stashed updates on top of the work-in-progress hook.
+ didScheduleRenderPhaseUpdate = true;
+ var update = {
+ expirationTime: renderExpirationTime,
+ action: action,
+ eagerReducer: null,
+ eagerState: null,
+ next: null
+ };
+ if (renderPhaseUpdates === null) {
+ renderPhaseUpdates = new Map();
+ }
+ var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+ if (firstRenderPhaseUpdate === undefined) {
+ renderPhaseUpdates.set(queue, update);
+ } else {
+ // Append the update to the end of the list.
+ var lastRenderPhaseUpdate = firstRenderPhaseUpdate;
+ while (lastRenderPhaseUpdate.next !== null) {
+ lastRenderPhaseUpdate = lastRenderPhaseUpdate.next;
+ }
+ lastRenderPhaseUpdate.next = update;
+ }
+ } else {
+ flushPassiveEffects();
+
+ var currentTime = requestCurrentTime();
+ var _expirationTime = computeExpirationForFiber(currentTime, fiber);
+
+ var _update2 = {
+ expirationTime: _expirationTime,
+ action: action,
+ eagerReducer: null,
+ eagerState: null,
+ next: null
+ };
+
+ // Append the update to the end of the list.
+ var _last = queue.last;
+ if (_last === null) {
+ // This is the first update. Create a circular list.
+ _update2.next = _update2;
+ } else {
+ var first = _last.next;
+ if (first !== null) {
+ // Still circular.
+ _update2.next = first;
+ }
+ _last.next = _update2;
+ }
+ queue.last = _update2;
+
+ if (
+ fiber.expirationTime === NoWork &&
+ (alternate === null || alternate.expirationTime === NoWork)
+ ) {
+ // The queue is currently empty, which means we can eagerly compute the
+ // next state before entering the render phase. If the new state is the
+ // same as the current state, we may be able to bail out entirely.
+ var _eagerReducer = queue.eagerReducer;
+ if (_eagerReducer !== null) {
+ var prevDispatcher = void 0;
+ {
+ prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
+ }
+ try {
+ var currentState = queue.eagerState;
+ var _eagerState = _eagerReducer(currentState, action);
+ // Stash the eagerly computed state, and the reducer used to compute
+ // it, on the update object. If the reducer hasn't changed by the
+ // time we enter the render phase, then the eager state can be used
+ // without calling the reducer again.
+ _update2.eagerReducer = _eagerReducer;
+ _update2.eagerState = _eagerState;
+ if (is(_eagerState, currentState)) {
+ // Fast path. We can bail out without scheduling React to re-render.
+ // It's still possible that we'll need to rebase this update later,
+ // if the component re-renders for a different reason and by that
+ // time the reducer has changed.
+ return;
+ }
+ } catch (error) {
+ // Suppress the error. It will throw again in the render phase.
+ } finally {
+ {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ }
+ }
+ }
+ {
+ if (shouldWarnForUnbatchedSetState === true) {
+ warnIfNotCurrentlyBatchingInDev(fiber);
+ }
+ }
+ scheduleWork(fiber, _expirationTime);
+ }
+}
+
+var ContextOnlyDispatcher = {
+ readContext: readContext,
+
+ useCallback: throwInvalidHookError,
+ useContext: throwInvalidHookError,
+ useEffect: throwInvalidHookError,
+ useImperativeHandle: throwInvalidHookError,
+ useLayoutEffect: throwInvalidHookError,
+ useMemo: throwInvalidHookError,
+ useReducer: throwInvalidHookError,
+ useRef: throwInvalidHookError,
+ useState: throwInvalidHookError,
+ useDebugValue: throwInvalidHookError
+};
+
+var HooksDispatcherOnMountInDEV = null;
+var HooksDispatcherOnUpdateInDEV = null;
+var InvalidNestedHooksDispatcherOnMountInDEV = null;
+var InvalidNestedHooksDispatcherOnUpdateInDEV = null;
+
+{
+ var warnInvalidContextAccess = function() {
+ warning$1(
+ false,
+ "Context can only be read while React is rendering. " +
+ "In classes, you can read it in the render method or getDerivedStateFromProps. " +
+ "In function components, you can read it directly in the function body, but not " +
+ "inside Hooks like useReducer() or useMemo()."
+ );
+ };
+
+ var warnInvalidHookAccess = function() {
+ warning$1(
+ false,
+ "Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. " +
+ "You can only call Hooks at the top level of your React function. " +
+ "For more information, see " +
+ "https://fb.me/rules-of-hooks"
+ );
+ };
+
+ HooksDispatcherOnMountInDEV = {
+ readContext: function(context, observedBits) {
+ return readContext(context, observedBits);
+ },
+ useCallback: function(callback, deps) {
+ currentHookNameInDev = "useCallback";
+ return mountCallback(callback, deps);
+ },
+ useContext: function(context, observedBits) {
+ currentHookNameInDev = "useContext";
+ return mountContext(context, observedBits);
+ },
+ useEffect: function(create, deps) {
+ currentHookNameInDev = "useEffect";
+ return mountEffect(create, deps);
+ },
+ useImperativeHandle: function(ref, create, deps) {
+ currentHookNameInDev = "useImperativeHandle";
+ return mountImperativeHandle(ref, create, deps);
+ },
+ useLayoutEffect: function(create, deps) {
+ currentHookNameInDev = "useLayoutEffect";
+ return mountLayoutEffect(create, deps);
+ },
+ useMemo: function(create, deps) {
+ currentHookNameInDev = "useMemo";
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;
+ try {
+ return mountMemo(create, deps);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useReducer: function(reducer, initialArg, init) {
+ currentHookNameInDev = "useReducer";
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;
+ try {
+ return mountReducer(reducer, initialArg, init);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useRef: function(initialValue) {
+ currentHookNameInDev = "useRef";
+ return mountRef(initialValue);
+ },
+ useState: function(initialState) {
+ currentHookNameInDev = "useState";
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;
+ try {
+ return mountState(initialState);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useDebugValue: function(value, formatterFn) {
+ currentHookNameInDev = "useDebugValue";
+ return mountDebugValue(value, formatterFn);
+ }
+ };
+
+ HooksDispatcherOnUpdateInDEV = {
+ readContext: function(context, observedBits) {
+ return readContext(context, observedBits);
+ },
+ useCallback: function(callback, deps) {
+ currentHookNameInDev = "useCallback";
+ return updateCallback(callback, deps);
+ },
+ useContext: function(context, observedBits) {
+ currentHookNameInDev = "useContext";
+ return updateContext(context, observedBits);
+ },
+ useEffect: function(create, deps) {
+ currentHookNameInDev = "useEffect";
+ return updateEffect(create, deps);
+ },
+ useImperativeHandle: function(ref, create, deps) {
+ currentHookNameInDev = "useImperativeHandle";
+ return updateImperativeHandle(ref, create, deps);
+ },
+ useLayoutEffect: function(create, deps) {
+ currentHookNameInDev = "useLayoutEffect";
+ return updateLayoutEffect(create, deps);
+ },
+ useMemo: function(create, deps) {
+ currentHookNameInDev = "useMemo";
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
+ try {
+ return updateMemo(create, deps);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useReducer: function(reducer, initialArg, init) {
+ currentHookNameInDev = "useReducer";
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
+ try {
+ return updateReducer(reducer, initialArg, init);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useRef: function(initialValue) {
+ currentHookNameInDev = "useRef";
+ return updateRef(initialValue);
+ },
+ useState: function(initialState) {
+ currentHookNameInDev = "useState";
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
+ try {
+ return updateState(initialState);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useDebugValue: function(value, formatterFn) {
+ currentHookNameInDev = "useDebugValue";
+ return updateDebugValue(value, formatterFn);
+ }
+ };
+
+ InvalidNestedHooksDispatcherOnMountInDEV = {
+ readContext: function(context, observedBits) {
+ warnInvalidContextAccess();
+ return readContext(context, observedBits);
+ },
+ useCallback: function(callback, deps) {
+ currentHookNameInDev = "useCallback";
+ warnInvalidHookAccess();
+ return mountCallback(callback, deps);
+ },
+ useContext: function(context, observedBits) {
+ currentHookNameInDev = "useContext";
+ warnInvalidHookAccess();
+ return mountContext(context, observedBits);
+ },
+ useEffect: function(create, deps) {
+ currentHookNameInDev = "useEffect";
+ warnInvalidHookAccess();
+ return mountEffect(create, deps);
+ },
+ useImperativeHandle: function(ref, create, deps) {
+ currentHookNameInDev = "useImperativeHandle";
+ warnInvalidHookAccess();
+ return mountImperativeHandle(ref, create, deps);
+ },
+ useLayoutEffect: function(create, deps) {
+ currentHookNameInDev = "useLayoutEffect";
+ warnInvalidHookAccess();
+ return mountLayoutEffect(create, deps);
+ },
+ useMemo: function(create, deps) {
+ currentHookNameInDev = "useMemo";
+ warnInvalidHookAccess();
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;
+ try {
+ return mountMemo(create, deps);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useReducer: function(reducer, initialArg, init) {
+ currentHookNameInDev = "useReducer";
+ warnInvalidHookAccess();
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;
+ try {
+ return mountReducer(reducer, initialArg, init);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useRef: function(initialValue) {
+ currentHookNameInDev = "useRef";
+ warnInvalidHookAccess();
+ return mountRef(initialValue);
+ },
+ useState: function(initialState) {
+ currentHookNameInDev = "useState";
+ warnInvalidHookAccess();
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;
+ try {
+ return mountState(initialState);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useDebugValue: function(value, formatterFn) {
+ currentHookNameInDev = "useDebugValue";
+ warnInvalidHookAccess();
+ return mountDebugValue(value, formatterFn);
+ }
+ };
+
+ InvalidNestedHooksDispatcherOnUpdateInDEV = {
+ readContext: function(context, observedBits) {
+ warnInvalidContextAccess();
+ return readContext(context, observedBits);
+ },
+ useCallback: function(callback, deps) {
+ currentHookNameInDev = "useCallback";
+ warnInvalidHookAccess();
+ return updateCallback(callback, deps);
+ },
+ useContext: function(context, observedBits) {
+ currentHookNameInDev = "useContext";
+ warnInvalidHookAccess();
+ return updateContext(context, observedBits);
+ },
+ useEffect: function(create, deps) {
+ currentHookNameInDev = "useEffect";
+ warnInvalidHookAccess();
+ return updateEffect(create, deps);
+ },
+ useImperativeHandle: function(ref, create, deps) {
+ currentHookNameInDev = "useImperativeHandle";
+ warnInvalidHookAccess();
+ return updateImperativeHandle(ref, create, deps);
+ },
+ useLayoutEffect: function(create, deps) {
+ currentHookNameInDev = "useLayoutEffect";
+ warnInvalidHookAccess();
+ return updateLayoutEffect(create, deps);
+ },
+ useMemo: function(create, deps) {
+ currentHookNameInDev = "useMemo";
+ warnInvalidHookAccess();
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
+ try {
+ return updateMemo(create, deps);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useReducer: function(reducer, initialArg, init) {
+ currentHookNameInDev = "useReducer";
+ warnInvalidHookAccess();
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
+ try {
+ return updateReducer(reducer, initialArg, init);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useRef: function(initialValue) {
+ currentHookNameInDev = "useRef";
+ warnInvalidHookAccess();
+ return updateRef(initialValue);
+ },
+ useState: function(initialState) {
+ currentHookNameInDev = "useState";
+ warnInvalidHookAccess();
+ var prevDispatcher = ReactCurrentDispatcher$1.current;
+ ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
+ try {
+ return updateState(initialState);
+ } finally {
+ ReactCurrentDispatcher$1.current = prevDispatcher;
+ }
+ },
+ useDebugValue: function(value, formatterFn) {
+ currentHookNameInDev = "useDebugValue";
+ warnInvalidHookAccess();
+ return updateDebugValue(value, formatterFn);
+ }
+ };
+}
+
+var commitTime = 0;
+var profilerStartTime = -1;
+
+function getCommitTime() {
+ return commitTime;
+}
+
+function recordCommitTime() {
+ if (!enableProfilerTimer) {
+ return;
+ }
+ commitTime = now$$1();
+}
+
+function startProfilerTimer(fiber) {
+ if (!enableProfilerTimer) {
+ return;
+ }
+
+ profilerStartTime = now$$1();
+
+ if (fiber.actualStartTime < 0) {
+ fiber.actualStartTime = now$$1();
+ }
+}
+
+function stopProfilerTimerIfRunning(fiber) {
+ if (!enableProfilerTimer) {
+ return;
+ }
+ profilerStartTime = -1;
+}
+
+function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) {
+ if (!enableProfilerTimer) {
+ return;
+ }
+
+ if (profilerStartTime >= 0) {
+ var elapsedTime = now$$1() - profilerStartTime;
+ fiber.actualDuration += elapsedTime;
+ if (overrideBaseTime) {
+ fiber.selfBaseDuration = elapsedTime;
+ }
+ profilerStartTime = -1;
+ }
+}
+
// The deepest Fiber on the stack involved in a hydration context.
// This may have been an insertion or a hydration.
var hydrationParentFiber = null;
@@ -10766,6 +10608,18 @@
return true;
}
+function reenterHydrationStateFromDehydratedSuspenseInstance(fiber) {
+ if (!supportsHydration) {
+ return false;
+ }
+
+ var suspenseInstance = fiber.stateNode;
+ nextHydratableInstance = getNextHydratableSibling(suspenseInstance);
+ popToNextHostParent(fiber);
+ isHydrating = true;
+ return true;
+}
+
function deleteHydratableInstance(returnFiber, instance) {
{
switch (returnFiber.tag) {
@@ -10820,6 +10674,9 @@
var text = fiber.pendingProps;
didNotFindHydratableContainerTextInstance(parentContainer, text);
break;
+ case SuspenseComponent:
+ didNotFindHydratableContainerSuspenseInstance(parentContainer);
+ break;
}
break;
}
@@ -10848,6 +10705,13 @@
_text
);
break;
+ case SuspenseComponent:
+ didNotFindHydratableSuspenseInstance(
+ parentType,
+ parentProps,
+ parentInstance
+ );
+ break;
}
break;
}
@@ -10878,6 +10742,18 @@
}
return false;
}
+ case SuspenseComponent: {
+ if (enableSuspenseServerRenderer) {
+ var suspenseInstance = canHydrateSuspenseInstance(nextInstance);
+ if (suspenseInstance !== null) {
+ // Downgrade the tag to a dehydrated component until we've hydrated it.
+ fiber.tag = DehydratedSuspenseComponent;
+ fiber.stateNode = suspenseInstance;
+ return true;
+ }
+ }
+ return false;
+ }
default:
return false;
}
@@ -10998,12 +10874,32 @@
return shouldUpdate;
}
+function skipPastDehydratedSuspenseInstance(fiber) {
+ if (!supportsHydration) {
+ invariant(
+ false,
+ "Expected skipPastDehydratedSuspenseInstance() to never be called. " +
+ "This error is likely caused by a bug in React. Please file an issue."
+ );
+ }
+ var suspenseInstance = fiber.stateNode;
+ invariant(
+ suspenseInstance,
+ "Expected to have a hydrated suspense instance. " +
+ "This error is likely caused by a bug in React. Please file an issue."
+ );
+ nextHydratableInstance = getNextHydratableInstanceAfterSuspenseInstance(
+ suspenseInstance
+ );
+}
+
function popToNextHostParent(fiber) {
var parent = fiber.return;
while (
parent !== null &&
parent.tag !== HostComponent &&
- parent.tag !== HostRoot
+ parent.tag !== HostRoot &&
+ parent.tag !== DehydratedSuspenseComponent
) {
parent = parent.return;
}
@@ -11067,6 +10963,8 @@
var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner;
+var didReceiveUpdate = false;
+
var didWarnAboutBadClass = void 0;
var didWarnAboutContextTypeOnFunctionComponent = void 0;
var didWarnAboutGetDerivedStateOnFunctionComponent = void 0;
@@ -11153,6 +11051,10 @@
nextProps,
renderExpirationTime
) {
+ // TODO: current can be non-null here even if the component
+ // hasn't yet mounted. This happens after the first render suspends.
+ // We'll need to figure out if this is fine or can cause issues.
+
{
if (workInProgress.type !== workInProgress.elementType) {
// Lazy component props can't be validated in createElement
@@ -11176,14 +11078,45 @@
// The rest is a fork of updateFunctionComponent
var nextChildren = void 0;
prepareToReadContext(workInProgress, renderExpirationTime);
- prepareToUseHooks(current$$1, workInProgress, renderExpirationTime);
{
ReactCurrentOwner$3.current = workInProgress;
setCurrentPhase("render");
- nextChildren = render(nextProps, ref);
+ nextChildren = renderWithHooks(
+ current$$1,
+ workInProgress,
+ render,
+ nextProps,
+ ref,
+ renderExpirationTime
+ );
+ if (
+ debugRenderPhaseSideEffects ||
+ (debugRenderPhaseSideEffectsForStrictMode &&
+ workInProgress.mode & StrictMode)
+ ) {
+ // Only double-render components with Hooks
+ if (workInProgress.memoizedState !== null) {
+ nextChildren = renderWithHooks(
+ current$$1,
+ workInProgress,
+ render,
+ nextProps,
+ ref,
+ renderExpirationTime
+ );
+ }
+ }
setCurrentPhase(null);
}
- nextChildren = finishHooks(render, nextProps, nextChildren, ref);
+
+ if (current$$1 !== null && !didReceiveUpdate) {
+ bailoutHooks(current$$1, workInProgress, renderExpirationTime);
+ return bailoutOnAlreadyFinishedWork(
+ current$$1,
+ workInProgress,
+ renderExpirationTime
+ );
+ }
// React DevTools reads this flag.
workInProgress.effectTag |= PerformedWork;
@@ -11311,6 +11244,10 @@
updateExpirationTime,
renderExpirationTime
) {
+ // TODO: current can be non-null here even if the component
+ // hasn't yet mounted. This happens when the inner render suspends.
+ // We'll need to figure out if this is fine or can cause issues.
+
{
if (workInProgress.type !== workInProgress.elementType) {
// Lazy component props can't be validated in createElement
@@ -11335,12 +11272,14 @@
// Inner propTypes will be validated in the function component path.
}
}
- if (current$$1 !== null && updateExpirationTime < renderExpirationTime) {
+ if (current$$1 !== null) {
var prevProps = current$$1.memoizedProps;
if (
shallowEqual(prevProps, nextProps) &&
current$$1.ref === workInProgress.ref
) {
+ didReceiveUpdate = false;
+ if (updateExpirationTime < renderExpirationTime) {
return bailoutOnAlreadyFinishedWork(
current$$1,
workInProgress,
@@ -11348,6 +11287,7 @@
);
}
}
+ }
return updateFunctionComponent(
current$$1,
workInProgress,
@@ -11434,14 +11374,45 @@
var nextChildren = void 0;
prepareToReadContext(workInProgress, renderExpirationTime);
- prepareToUseHooks(current$$1, workInProgress, renderExpirationTime);
{
ReactCurrentOwner$3.current = workInProgress;
setCurrentPhase("render");
- nextChildren = Component(nextProps, context);
+ nextChildren = renderWithHooks(
+ current$$1,
+ workInProgress,
+ Component,
+ nextProps,
+ context,
+ renderExpirationTime
+ );
+ if (
+ debugRenderPhaseSideEffects ||
+ (debugRenderPhaseSideEffectsForStrictMode &&
+ workInProgress.mode & StrictMode)
+ ) {
+ // Only double-render components with Hooks
+ if (workInProgress.memoizedState !== null) {
+ nextChildren = renderWithHooks(
+ current$$1,
+ workInProgress,
+ Component,
+ nextProps,
+ context,
+ renderExpirationTime
+ );
+ }
+ }
setCurrentPhase(null);
}
- nextChildren = finishHooks(Component, nextProps, nextChildren, context);
+
+ if (current$$1 !== null && !didReceiveUpdate) {
+ bailoutHooks(current$$1, workInProgress, renderExpirationTime);
+ return bailoutOnAlreadyFinishedWork(
+ current$$1,
+ workInProgress,
+ renderExpirationTime
+ );
+ }
// React DevTools reads this flag.
workInProgress.effectTag |= PerformedWork;
@@ -11776,7 +11747,7 @@
shouldDeprioritizeSubtree(type, nextProps)
) {
// Schedule this fiber to re-render at offscreen priority. Then bailout.
- workInProgress.expirationTime = Never;
+ workInProgress.expirationTime = workInProgress.childExpirationTime = Never;
return null;
}
@@ -11829,6 +11800,9 @@
var child = void 0;
switch (resolvedTag) {
case FunctionComponent: {
+ {
+ validateFunctionComponentInDev(workInProgress, Component);
+ }
child = updateFunctionComponent(
null,
workInProgress,
@@ -11989,7 +11963,6 @@
var context = getMaskedContext(workInProgress, unmaskedContext);
prepareToReadContext(workInProgress, renderExpirationTime);
- prepareToUseHooks(null, workInProgress, renderExpirationTime);
var value = void 0;
@@ -12017,7 +11990,14 @@
}
ReactCurrentOwner$3.current = workInProgress;
- value = Component(props, context);
+ value = renderWithHooks(
+ null,
+ workInProgress,
+ Component,
+ props,
+ context,
+ renderExpirationTime
+ );
}
// React DevTools reads this flag.
workInProgress.effectTag |= PerformedWork;
@@ -12071,7 +12051,25 @@
} else {
// Proceed under the assumption that this is a function component
workInProgress.tag = FunctionComponent;
- value = finishHooks(Component, props, value, context);
+ {
+ if (
+ debugRenderPhaseSideEffects ||
+ (debugRenderPhaseSideEffectsForStrictMode &&
+ workInProgress.mode & StrictMode)
+ ) {
+ // Only double-render components with Hooks
+ if (workInProgress.memoizedState !== null) {
+ value = renderWithHooks(
+ null,
+ workInProgress,
+ Component,
+ props,
+ context,
+ renderExpirationTime
+ );
+ }
+ }
+ }
reconcileChildren(null, workInProgress, value, renderExpirationTime);
{
validateFunctionComponentInDev(workInProgress, Component);
@@ -12107,7 +12105,8 @@
warning$1(
false,
"Function components cannot be given refs. " +
- "Attempts to access this ref will fail.%s",
+ "Attempts to access this ref will fail. " +
+ "Did you mean to use React.forwardRef()?%s",
info
);
}
@@ -12202,6 +12201,22 @@
// children -- we skip over the primary children entirely.
var next = void 0;
if (current$$1 === null) {
+ if (enableSuspenseServerRenderer) {
+ // If we're currently hydrating, try to hydrate this boundary.
+ // But only if this has a fallback.
+ if (nextProps.fallback !== undefined) {
+ tryToClaimNextHydratableInstance(workInProgress);
+ // This could've changed the tag if this was a dehydrated suspense component.
+ if (workInProgress.tag === DehydratedSuspenseComponent) {
+ return updateDehydratedSuspenseComponent(
+ null,
+ workInProgress,
+ renderExpirationTime
+ );
+ }
+ }
+ }
+
// This is the initial mount. This branch is pretty simple because there's
// no previous state that needs to be preserved.
if (nextDidTimeout) {
@@ -12396,6 +12411,7 @@
);
}
}
+ workInProgress.stateNode = current$$1.stateNode;
}
workInProgress.memoizedState = nextState;
@@ -12403,6 +12419,107 @@
return next;
}
+function updateDehydratedSuspenseComponent(
+ current$$1,
+ workInProgress,
+ renderExpirationTime
+) {
+ if (current$$1 === null) {
+ // During the first pass, we'll bail out and not drill into the children.
+ // Instead, we'll leave the content in place and try to hydrate it later.
+ workInProgress.expirationTime = Never;
+ return null;
+ }
+ if ((workInProgress.effectTag & DidCapture) !== NoEffect) {
+ // Something suspended. Leave the existing children in place.
+ // TODO: In non-concurrent mode, should we commit the nodes we have hydrated so far?
+ workInProgress.child = null;
+ return null;
+ }
+ // We use childExpirationTime to indicate that a child might depend on context, so if
+ // any context has changed, we need to treat is as if the input might have changed.
+ var hasContextChanged$$1 =
+ current$$1.childExpirationTime >= renderExpirationTime;
+ var suspenseInstance = current$$1.stateNode;
+ if (
+ didReceiveUpdate ||
+ hasContextChanged$$1 ||
+ isSuspenseInstanceFallback(suspenseInstance)
+ ) {
+ // This boundary has changed since the first render. This means that we are now unable to
+ // hydrate it. We might still be able to hydrate it using an earlier expiration time but
+ // during this render we can't. Instead, we're going to delete the whole subtree and
+ // instead inject a new real Suspense boundary to take its place, which may render content
+ // or fallback. The real Suspense boundary will suspend for a while so we have some time
+ // to ensure it can produce real content, but all state and pending events will be lost.
+
+ // Alternatively, this boundary is in a permanent fallback state. In this case, we'll never
+ // get an update and we'll never be able to hydrate the final content. Let's just try the
+ // client side render instead.
+
+ // Detach from the current dehydrated boundary.
+ current$$1.alternate = null;
+ workInProgress.alternate = null;
+
+ // Insert a deletion in the effect list.
+ var returnFiber = workInProgress.return;
+ invariant(
+ returnFiber !== null,
+ "Suspense boundaries are never on the root. " +
+ "This is probably a bug in React."
+ );
+ var last = returnFiber.lastEffect;
+ if (last !== null) {
+ last.nextEffect = current$$1;
+ returnFiber.lastEffect = current$$1;
+ } else {
+ returnFiber.firstEffect = returnFiber.lastEffect = current$$1;
+ }
+ current$$1.nextEffect = null;
+ current$$1.effectTag = Deletion;
+
+ // Upgrade this work in progress to a real Suspense component.
+ workInProgress.tag = SuspenseComponent;
+ workInProgress.stateNode = null;
+ workInProgress.memoizedState = null;
+ // This is now an insertion.
+ workInProgress.effectTag |= Placement;
+ // Retry as a real Suspense component.
+ return updateSuspenseComponent(null, workInProgress, renderExpirationTime);
+ } else if (isSuspenseInstancePending(suspenseInstance)) {
+ // This component is still pending more data from the server, so we can't hydrate its
+ // content. We treat it as if this component suspended itself. It might seem as if
+ // we could just try to render it client-side instead. However, this will perform a
+ // lot of unnecessary work and is unlikely to complete since it often will suspend
+ // on missing data anyway. Additionally, the server might be able to render more
+ // than we can on the client yet. In that case we'd end up with more fallback states
+ // on the client than if we just leave it alone. If the server times out or errors
+ // these should update this boundary to the permanent Fallback state instead.
+ // Mark it as having captured (i.e. suspended).
+ workInProgress.effectTag |= DidCapture;
+ // Leave the children in place. I.e. empty.
+ workInProgress.child = null;
+ // Register a callback to retry this boundary once the server has sent the result.
+ registerSuspenseInstanceRetry(
+ suspenseInstance,
+ retryTimedOutBoundary.bind(null, current$$1)
+ );
+ return null;
+ } else {
+ // This is the first attempt.
+ reenterHydrationStateFromDehydratedSuspenseInstance(workInProgress);
+ var nextProps = workInProgress.pendingProps;
+ var nextChildren = nextProps.children;
+ workInProgress.child = mountChildFibers(
+ workInProgress,
+ null,
+ nextChildren,
+ renderExpirationTime
+ );
+ return workInProgress.child;
+ }
+}
+
function updatePortalComponent(
current$$1,
workInProgress,
@@ -12566,6 +12683,10 @@
return workInProgress.child;
}
+function markWorkInProgressReceivedUpdate() {
+ didReceiveUpdate = true;
+}
+
function bailoutOnAlreadyFinishedWork(
current$$1,
workInProgress,
@@ -12575,7 +12696,7 @@
if (current$$1 !== null) {
// Reuse previous context list
- workInProgress.firstContextDependency = current$$1.firstContextDependency;
+ workInProgress.contextDependencies = current$$1.contextDependencies;
}
if (enableProfilerTimer) {
@@ -12604,11 +12725,13 @@
if (current$$1 !== null) {
var oldProps = current$$1.memoizedProps;
var newProps = workInProgress.pendingProps;
- if (
- oldProps === newProps &&
- !hasContextChanged() &&
- updateExpirationTime < renderExpirationTime
- ) {
+
+ if (oldProps !== newProps || hasContextChanged()) {
+ // If props or context changed, mark the fiber as having performed work.
+ // This may be unset if the props are determined to be equal later (memo).
+ didReceiveUpdate = true;
+ } else if (updateExpirationTime < renderExpirationTime) {
+ didReceiveUpdate = false;
// This fiber does not have any pending work. Bailout without entering
// the begin phase. There's still some bookkeeping we that needs to be done
// in this optimized path, mostly pushing stuff onto the stack.
@@ -12683,6 +12806,15 @@
}
break;
}
+ case DehydratedSuspenseComponent: {
+ if (enableSuspenseServerRenderer) {
+ // We know that this component will suspend again because if it has
+ // been unsuspended it has committed as a regular Suspense component.
+ // If it needs to be retried, it should have work scheduled on it.
+ workInProgress.effectTag |= DidCapture;
+ break;
+ }
+ }
}
return bailoutOnAlreadyFinishedWork(
current$$1,
@@ -12690,6 +12822,8 @@
renderExpirationTime
);
}
+ } else {
+ didReceiveUpdate = false;
}
// Before entering the begin phase, clear the expiration time.
@@ -12854,13 +12988,930 @@
renderExpirationTime
);
}
- default:
+ case DehydratedSuspenseComponent: {
+ if (enableSuspenseServerRenderer) {
+ return updateDehydratedSuspenseComponent(
+ current$$1,
+ workInProgress,
+ renderExpirationTime
+ );
+ }
+ break;
+ }
+ }
invariant(
false,
"Unknown unit of work tag. This error is likely caused by a bug in " +
"React. Please file an issue."
);
+}
+
+var valueCursor = createCursor(null);
+
+var rendererSigil = void 0;
+{
+ // Use this to detect multiple renderers using the same context
+ rendererSigil = {};
+}
+
+var currentlyRenderingFiber = null;
+var lastContextDependency = null;
+var lastContextWithAllBitsObserved = null;
+
+var isDisallowedContextReadInDEV = false;
+
+function resetContextDependences() {
+ // This is called right before React yields execution, to ensure `readContext`
+ // cannot be called outside the render phase.
+ currentlyRenderingFiber = null;
+ lastContextDependency = null;
+ lastContextWithAllBitsObserved = null;
+ {
+ isDisallowedContextReadInDEV = false;
+ }
+}
+
+function enterDisallowedContextReadInDEV() {
+ {
+ isDisallowedContextReadInDEV = true;
+ }
+}
+
+function exitDisallowedContextReadInDEV() {
+ {
+ isDisallowedContextReadInDEV = false;
+ }
+}
+
+function pushProvider(providerFiber, nextValue) {
+ var context = providerFiber.type._context;
+
+ if (isPrimaryRenderer) {
+ push(valueCursor, context._currentValue, providerFiber);
+
+ context._currentValue = nextValue;
+ {
+ !(
+ context._currentRenderer === undefined ||
+ context._currentRenderer === null ||
+ context._currentRenderer === rendererSigil
+ )
+ ? warningWithoutStack$1(
+ false,
+ "Detected multiple renderers concurrently rendering the " +
+ "same context provider. This is currently unsupported."
+ )
+ : void 0;
+ context._currentRenderer = rendererSigil;
+ }
+ } else {
+ push(valueCursor, context._currentValue2, providerFiber);
+
+ context._currentValue2 = nextValue;
+ {
+ !(
+ context._currentRenderer2 === undefined ||
+ context._currentRenderer2 === null ||
+ context._currentRenderer2 === rendererSigil
+ )
+ ? warningWithoutStack$1(
+ false,
+ "Detected multiple renderers concurrently rendering the " +
+ "same context provider. This is currently unsupported."
+ )
+ : void 0;
+ context._currentRenderer2 = rendererSigil;
+ }
+ }
+}
+
+function popProvider(providerFiber) {
+ var currentValue = valueCursor.current;
+
+ pop(valueCursor, providerFiber);
+
+ var context = providerFiber.type._context;
+ if (isPrimaryRenderer) {
+ context._currentValue = currentValue;
+ } else {
+ context._currentValue2 = currentValue;
+ }
+}
+
+function calculateChangedBits(context, newValue, oldValue) {
+ if (is(oldValue, newValue)) {
+ // No change
+ return 0;
+ } else {
+ var changedBits =
+ typeof context._calculateChangedBits === "function"
+ ? context._calculateChangedBits(oldValue, newValue)
+ : maxSigned31BitInt;
+
+ {
+ !((changedBits & maxSigned31BitInt) === changedBits)
+ ? warning$1(
+ false,
+ "calculateChangedBits: Expected the return value to be a " +
+ "31-bit integer. Instead received: %s",
+ changedBits
+ )
+ : void 0;
+ }
+ return changedBits | 0;
+ }
+}
+
+function scheduleWorkOnParentPath(parent, renderExpirationTime) {
+ // Update the child expiration time of all the ancestors, including
+ // the alternates.
+ var node = parent;
+ while (node !== null) {
+ var alternate = node.alternate;
+ if (node.childExpirationTime < renderExpirationTime) {
+ node.childExpirationTime = renderExpirationTime;
+ if (
+ alternate !== null &&
+ alternate.childExpirationTime < renderExpirationTime
+ ) {
+ alternate.childExpirationTime = renderExpirationTime;
+ }
+ } else if (
+ alternate !== null &&
+ alternate.childExpirationTime < renderExpirationTime
+ ) {
+ alternate.childExpirationTime = renderExpirationTime;
+ } else {
+ // Neither alternate was updated, which means the rest of the
+ // ancestor path already has sufficient priority.
+ break;
+ }
+ node = node.return;
+ }
+}
+
+function propagateContextChange(
+ workInProgress,
+ context,
+ changedBits,
+ renderExpirationTime
+) {
+ var fiber = workInProgress.child;
+ if (fiber !== null) {
+ // Set the return pointer of the child to the work-in-progress fiber.
+ fiber.return = workInProgress;
+ }
+ while (fiber !== null) {
+ var nextFiber = void 0;
+
+ // Visit this fiber.
+ var list = fiber.contextDependencies;
+ if (list !== null) {
+ nextFiber = fiber.child;
+
+ var dependency = list.first;
+ while (dependency !== null) {
+ // Check if the context matches.
+ if (
+ dependency.context === context &&
+ (dependency.observedBits & changedBits) !== 0
+ ) {
+ // Match! Schedule an update on this fiber.
+
+ if (fiber.tag === ClassComponent) {
+ // Schedule a force update on the work-in-progress.
+ var update = createUpdate(renderExpirationTime);
+ update.tag = ForceUpdate;
+ // TODO: Because we don't have a work-in-progress, this will add the
+ // update to the current fiber, too, which means it will persist even if
+ // this render is thrown away. Since it's a race condition, not sure it's
+ // worth fixing.
+ enqueueUpdate(fiber, update);
+ }
+
+ if (fiber.expirationTime < renderExpirationTime) {
+ fiber.expirationTime = renderExpirationTime;
+ }
+ var alternate = fiber.alternate;
+ if (
+ alternate !== null &&
+ alternate.expirationTime < renderExpirationTime
+ ) {
+ alternate.expirationTime = renderExpirationTime;
+ }
+
+ scheduleWorkOnParentPath(fiber.return, renderExpirationTime);
+
+ // Mark the expiration time on the list, too.
+ if (list.expirationTime < renderExpirationTime) {
+ list.expirationTime = renderExpirationTime;
+ }
+
+ // Since we already found a match, we can stop traversing the
+ // dependency list.
+ break;
+ }
+ dependency = dependency.next;
+ }
+ } else if (fiber.tag === ContextProvider) {
+ // Don't scan deeper if this is a matching provider
+ nextFiber = fiber.type === workInProgress.type ? null : fiber.child;
+ } else if (
+ enableSuspenseServerRenderer &&
+ fiber.tag === DehydratedSuspenseComponent
+ ) {
+ // If a dehydrated suspense component is in this subtree, we don't know
+ // if it will have any context consumers in it. The best we can do is
+ // mark it as having updates on its children.
+ if (fiber.expirationTime < renderExpirationTime) {
+ fiber.expirationTime = renderExpirationTime;
+ }
+ var _alternate = fiber.alternate;
+ if (
+ _alternate !== null &&
+ _alternate.expirationTime < renderExpirationTime
+ ) {
+ _alternate.expirationTime = renderExpirationTime;
+ }
+ // This is intentionally passing this fiber as the parent
+ // because we want to schedule this fiber as having work
+ // on its children. We'll use the childExpirationTime on
+ // this fiber to indicate that a context has changed.
+ scheduleWorkOnParentPath(fiber, renderExpirationTime);
+ nextFiber = fiber.sibling;
+ } else {
+ // Traverse down.
+ nextFiber = fiber.child;
+ }
+
+ if (nextFiber !== null) {
+ // Set the return pointer of the child to the work-in-progress fiber.
+ nextFiber.return = fiber;
+ } else {
+ // No child. Traverse to next sibling.
+ nextFiber = fiber;
+ while (nextFiber !== null) {
+ if (nextFiber === workInProgress) {
+ // We're back to the root of this subtree. Exit.
+ nextFiber = null;
+ break;
+ }
+ var sibling = nextFiber.sibling;
+ if (sibling !== null) {
+ // Set the return pointer of the sibling to the work-in-progress fiber.
+ sibling.return = nextFiber.return;
+ nextFiber = sibling;
+ break;
+ }
+ // No more siblings. Traverse up.
+ nextFiber = nextFiber.return;
+ }
+ }
+ fiber = nextFiber;
+ }
+}
+
+function prepareToReadContext(workInProgress, renderExpirationTime) {
+ currentlyRenderingFiber = workInProgress;
+ lastContextDependency = null;
+ lastContextWithAllBitsObserved = null;
+
+ var currentDependencies = workInProgress.contextDependencies;
+ if (
+ currentDependencies !== null &&
+ currentDependencies.expirationTime >= renderExpirationTime
+ ) {
+ // Context list has a pending update. Mark that this fiber performed work.
+ markWorkInProgressReceivedUpdate();
+ }
+
+ // Reset the work-in-progress list
+ workInProgress.contextDependencies = null;
+}
+
+function readContext(context, observedBits) {
+ {
+ // This warning would fire if you read context inside a Hook like useMemo.
+ // Unlike the class check below, it's not enforced in production for perf.
+ !!isDisallowedContextReadInDEV
+ ? warning$1(
+ false,
+ "Context can only be read while React is rendering. " +
+ "In classes, you can read it in the render method or getDerivedStateFromProps. " +
+ "In function components, you can read it directly in the function body, but not " +
+ "inside Hooks like useReducer() or useMemo()."
+ )
+ : void 0;
+ }
+
+ if (lastContextWithAllBitsObserved === context) {
+ // Nothing to do. We already observe everything in this context.
+ } else if (observedBits === false || observedBits === 0) {
+ // Do not observe any updates.
+ } else {
+ var resolvedObservedBits = void 0; // Avoid deopting on observable arguments or heterogeneous types.
+ if (
+ typeof observedBits !== "number" ||
+ observedBits === maxSigned31BitInt
+ ) {
+ // Observe all updates.
+ lastContextWithAllBitsObserved = context;
+ resolvedObservedBits = maxSigned31BitInt;
+ } else {
+ resolvedObservedBits = observedBits;
+ }
+
+ var contextItem = {
+ context: context,
+ observedBits: resolvedObservedBits,
+ next: null
+ };
+
+ if (lastContextDependency === null) {
+ invariant(
+ currentlyRenderingFiber !== null,
+ "Context can only be read while React is rendering. " +
+ "In classes, you can read it in the render method or getDerivedStateFromProps. " +
+ "In function components, you can read it directly in the function body, but not " +
+ "inside Hooks like useReducer() or useMemo()."
+ );
+
+ // This is the first dependency for this component. Create a new list.
+ lastContextDependency = contextItem;
+ currentlyRenderingFiber.contextDependencies = {
+ first: contextItem,
+ expirationTime: NoWork
+ };
+ } else {
+ // Append a new context item.
+ lastContextDependency = lastContextDependency.next = contextItem;
+ }
+ }
+ return isPrimaryRenderer ? context._currentValue : context._currentValue2;
+}
+
+// UpdateQueue is a linked list of prioritized updates.
+//
+// Like fibers, update queues come in pairs: a current queue, which represents
+// the visible state of the screen, and a work-in-progress queue, which can be
+// mutated and processed asynchronously before it is committed — a form of
+// double buffering. If a work-in-progress render is discarded before finishing,
+// we create a new work-in-progress by cloning the current queue.
+//
+// Both queues share a persistent, singly-linked list structure. To schedule an
+// update, we append it to the end of both queues. Each queue maintains a
+// pointer to first update in the persistent list that hasn't been processed.
+// The work-in-progress pointer always has a position equal to or greater than
+// the current queue, since we always work on that one. The current queue's
+// pointer is only updated during the commit phase, when we swap in the
+// work-in-progress.
+//
+// For example:
+//
+// Current pointer: A - B - C - D - E - F
+// Work-in-progress pointer: D - E - F
+// ^
+// The work-in-progress queue has
+// processed more updates than current.
+//
+// The reason we append to both queues is because otherwise we might drop
+// updates without ever processing them. For example, if we only add updates to
+// the work-in-progress queue, some updates could be lost whenever a work-in
+// -progress render restarts by cloning from current. Similarly, if we only add
+// updates to the current queue, the updates will be lost whenever an already
+// in-progress queue commits and swaps with the current queue. However, by
+// adding to both queues, we guarantee that the update will be part of the next
+// work-in-progress. (And because the work-in-progress queue becomes the
+// current queue once it commits, there's no danger of applying the same
+// update twice.)
+//
+// Prioritization
+// --------------
+//
+// Updates are not sorted by priority, but by insertion; new updates are always
+// appended to the end of the list.
+//
+// The priority is still important, though. When processing the update queue
+// during the render phase, only the updates with sufficient priority are
+// included in the result. If we skip an update because it has insufficient
+// priority, it remains in the queue to be processed later, during a lower
+// priority render. Crucially, all updates subsequent to a skipped update also
+// remain in the queue *regardless of their priority*. That means high priority
+// updates are sometimes processed twice, at two separate priorities. We also
+// keep track of a base state, that represents the state before the first
+// update in the queue is applied.
+//
+// For example:
+//
+// Given a base state of '', and the following queue of updates
+//
+// A1 - B2 - C1 - D2
+//
+// where the number indicates the priority, and the update is applied to the
+// previous state by appending a letter, React will process these updates as
+// two separate renders, one per distinct priority level:
+//
+// First render, at priority 1:
+// Base state: ''
+// Updates: [A1, C1]
+// Result state: 'AC'
+//
+// Second render, at priority 2:
+// Base state: 'A' <- The base state does not include C1,
+// because B2 was skipped.
+// Updates: [B2, C1, D2] <- C1 was rebased on top of B2
+// Result state: 'ABCD'
+//
+// Because we process updates in insertion order, and rebase high priority
+// updates when preceding updates are skipped, the final result is deterministic
+// regardless of priority. Intermediate state may vary according to system
+// resources, but the final state is always the same.
+
+var UpdateState = 0;
+var ReplaceState = 1;
+var ForceUpdate = 2;
+var CaptureUpdate = 3;
+
+// Global state that is reset at the beginning of calling `processUpdateQueue`.
+// It should only be read right after calling `processUpdateQueue`, via
+// `checkHasForceUpdateAfterProcessing`.
+var hasForceUpdate = false;
+
+var didWarnUpdateInsideUpdate = void 0;
+var currentlyProcessingQueue = void 0;
+var resetCurrentlyProcessingQueue = void 0;
+{
+ didWarnUpdateInsideUpdate = false;
+ currentlyProcessingQueue = null;
+ resetCurrentlyProcessingQueue = function() {
+ currentlyProcessingQueue = null;
+ };
+}
+
+function createUpdateQueue(baseState) {
+ var queue = {
+ baseState: baseState,
+ firstUpdate: null,
+ lastUpdate: null,
+ firstCapturedUpdate: null,
+ lastCapturedUpdate: null,
+ firstEffect: null,
+ lastEffect: null,
+ firstCapturedEffect: null,
+ lastCapturedEffect: null
+ };
+ return queue;
+}
+
+function cloneUpdateQueue(currentQueue) {
+ var queue = {
+ baseState: currentQueue.baseState,
+ firstUpdate: currentQueue.firstUpdate,
+ lastUpdate: currentQueue.lastUpdate,
+
+ // TODO: With resuming, if we bail out and resuse the child tree, we should
+ // keep these effects.
+ firstCapturedUpdate: null,
+ lastCapturedUpdate: null,
+
+ firstEffect: null,
+ lastEffect: null,
+
+ firstCapturedEffect: null,
+ lastCapturedEffect: null
+ };
+ return queue;
+}
+
+function createUpdate(expirationTime) {
+ return {
+ expirationTime: expirationTime,
+
+ tag: UpdateState,
+ payload: null,
+ callback: null,
+
+ next: null,
+ nextEffect: null
+ };
+}
+
+function appendUpdateToQueue(queue, update) {
+ // Append the update to the end of the list.
+ if (queue.lastUpdate === null) {
+ // Queue is empty
+ queue.firstUpdate = queue.lastUpdate = update;
+ } else {
+ queue.lastUpdate.next = update;
+ queue.lastUpdate = update;
+ }
+}
+
+function enqueueUpdate(fiber, update) {
+ // Update queues are created lazily.
+ var alternate = fiber.alternate;
+ var queue1 = void 0;
+ var queue2 = void 0;
+ if (alternate === null) {
+ // There's only one fiber.
+ queue1 = fiber.updateQueue;
+ queue2 = null;
+ if (queue1 === null) {
+ queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState);
+ }
+ } else {
+ // There are two owners.
+ queue1 = fiber.updateQueue;
+ queue2 = alternate.updateQueue;
+ if (queue1 === null) {
+ if (queue2 === null) {
+ // Neither fiber has an update queue. Create new ones.
+ queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState);
+ queue2 = alternate.updateQueue = createUpdateQueue(
+ alternate.memoizedState
+ );
+ } else {
+ // Only one fiber has an update queue. Clone to create a new one.
+ queue1 = fiber.updateQueue = cloneUpdateQueue(queue2);
+ }
+ } else {
+ if (queue2 === null) {
+ // Only one fiber has an update queue. Clone to create a new one.
+ queue2 = alternate.updateQueue = cloneUpdateQueue(queue1);
+ } else {
+ // Both owners have an update queue.
+ }
+ }
+ }
+ if (queue2 === null || queue1 === queue2) {
+ // There's only a single queue.
+ appendUpdateToQueue(queue1, update);
+ } else {
+ // There are two queues. We need to append the update to both queues,
+ // while accounting for the persistent structure of the list — we don't
+ // want the same update to be added multiple times.
+ if (queue1.lastUpdate === null || queue2.lastUpdate === null) {
+ // One of the queues is not empty. We must add the update to both queues.
+ appendUpdateToQueue(queue1, update);
+ appendUpdateToQueue(queue2, update);
+ } else {
+ // Both queues are non-empty. The last update is the same in both lists,
+ // because of structural sharing. So, only append to one of the lists.
+ appendUpdateToQueue(queue1, update);
+ // But we still need to update the `lastUpdate` pointer of queue2.
+ queue2.lastUpdate = update;
+ }
+ }
+
+ {
+ if (
+ fiber.tag === ClassComponent &&
+ (currentlyProcessingQueue === queue1 ||
+ (queue2 !== null && currentlyProcessingQueue === queue2)) &&
+ !didWarnUpdateInsideUpdate
+ ) {
+ warningWithoutStack$1(
+ false,
+ "An update (setState, replaceState, or forceUpdate) was scheduled " +
+ "from inside an update function. Update functions should be pure, " +
+ "with zero side-effects. Consider using componentDidUpdate or a " +
+ "callback."
+ );
+ didWarnUpdateInsideUpdate = true;
+ }
+ }
+}
+
+function enqueueCapturedUpdate(workInProgress, update) {
+ // Captured updates go into a separate list, and only on the work-in-
+ // progress queue.
+ var workInProgressQueue = workInProgress.updateQueue;
+ if (workInProgressQueue === null) {
+ workInProgressQueue = workInProgress.updateQueue = createUpdateQueue(
+ workInProgress.memoizedState
+ );
+ } else {
+ // TODO: I put this here rather than createWorkInProgress so that we don't
+ // clone the queue unnecessarily. There's probably a better way to
+ // structure this.
+ workInProgressQueue = ensureWorkInProgressQueueIsAClone(
+ workInProgress,
+ workInProgressQueue
+ );
+ }
+
+ // Append the update to the end of the list.
+ if (workInProgressQueue.lastCapturedUpdate === null) {
+ // This is the first render phase update
+ workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update;
+ } else {
+ workInProgressQueue.lastCapturedUpdate.next = update;
+ workInProgressQueue.lastCapturedUpdate = update;
+ }
+}
+
+function ensureWorkInProgressQueueIsAClone(workInProgress, queue) {
+ var current = workInProgress.alternate;
+ if (current !== null) {
+ // If the work-in-progress queue is equal to the current queue,
+ // we need to clone it first.
+ if (queue === current.updateQueue) {
+ queue = workInProgress.updateQueue = cloneUpdateQueue(queue);
+ }
+ }
+ return queue;
+}
+
+function getStateFromUpdate(
+ workInProgress,
+ queue,
+ update,
+ prevState,
+ nextProps,
+ instance
+) {
+ switch (update.tag) {
+ case ReplaceState: {
+ var _payload = update.payload;
+ if (typeof _payload === "function") {
+ // Updater function
+ {
+ enterDisallowedContextReadInDEV();
+ if (
+ debugRenderPhaseSideEffects ||
+ (debugRenderPhaseSideEffectsForStrictMode &&
+ workInProgress.mode & StrictMode)
+ ) {
+ _payload.call(instance, prevState, nextProps);
+ }
+ }
+ var nextState = _payload.call(instance, prevState, nextProps);
+ {
+ exitDisallowedContextReadInDEV();
+ }
+ return nextState;
+ }
+ // State object
+ return _payload;
+ }
+ case CaptureUpdate: {
+ workInProgress.effectTag =
+ (workInProgress.effectTag & ~ShouldCapture) | DidCapture;
+ }
+ // Intentional fallthrough
+ case UpdateState: {
+ var _payload2 = update.payload;
+ var partialState = void 0;
+ if (typeof _payload2 === "function") {
+ // Updater function
+ {
+ enterDisallowedContextReadInDEV();
+ if (
+ debugRenderPhaseSideEffects ||
+ (debugRenderPhaseSideEffectsForStrictMode &&
+ workInProgress.mode & StrictMode)
+ ) {
+ _payload2.call(instance, prevState, nextProps);
+ }
+ }
+ partialState = _payload2.call(instance, prevState, nextProps);
+ {
+ exitDisallowedContextReadInDEV();
+ }
+ } else {
+ // Partial state object
+ partialState = _payload2;
+ }
+ if (partialState === null || partialState === undefined) {
+ // Null and undefined are treated as no-ops.
+ return prevState;
+ }
+ // Merge the partial state and the previous state.
+ return Object.assign({}, prevState, partialState);
+ }
+ case ForceUpdate: {
+ hasForceUpdate = true;
+ return prevState;
+ }
+ }
+ return prevState;
+}
+
+function processUpdateQueue(
+ workInProgress,
+ queue,
+ props,
+ instance,
+ renderExpirationTime
+) {
+ hasForceUpdate = false;
+
+ queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue);
+
+ {
+ currentlyProcessingQueue = queue;
+ }
+
+ // These values may change as we process the queue.
+ var newBaseState = queue.baseState;
+ var newFirstUpdate = null;
+ var newExpirationTime = NoWork;
+
+ // Iterate through the list of updates to compute the result.
+ var update = queue.firstUpdate;
+ var resultState = newBaseState;
+ while (update !== null) {
+ var updateExpirationTime = update.expirationTime;
+ if (updateExpirationTime < renderExpirationTime) {
+ // This update does not have sufficient priority. Skip it.
+ if (newFirstUpdate === null) {
+ // This is the first skipped update. It will be the first update in
+ // the new list.
+ newFirstUpdate = update;
+ // Since this is the first update that was skipped, the current result
+ // is the new base state.
+ newBaseState = resultState;
+ }
+ // Since this update will remain in the list, update the remaining
+ // expiration time.
+ if (newExpirationTime < updateExpirationTime) {
+ newExpirationTime = updateExpirationTime;
+ }
+ } else {
+ // This update does have sufficient priority. Process it and compute
+ // a new result.
+ resultState = getStateFromUpdate(
+ workInProgress,
+ queue,
+ update,
+ resultState,
+ props,
+ instance
+ );
+ var _callback = update.callback;
+ if (_callback !== null) {
+ workInProgress.effectTag |= Callback;
+ // Set this to null, in case it was mutated during an aborted render.
+ update.nextEffect = null;
+ if (queue.lastEffect === null) {
+ queue.firstEffect = queue.lastEffect = update;
+ } else {
+ queue.lastEffect.nextEffect = update;
+ queue.lastEffect = update;
+ }
+ }
+ }
+ // Continue to the next update.
+ update = update.next;
+ }
+
+ // Separately, iterate though the list of captured updates.
+ var newFirstCapturedUpdate = null;
+ update = queue.firstCapturedUpdate;
+ while (update !== null) {
+ var _updateExpirationTime = update.expirationTime;
+ if (_updateExpirationTime < renderExpirationTime) {
+ // This update does not have sufficient priority. Skip it.
+ if (newFirstCapturedUpdate === null) {
+ // This is the first skipped captured update. It will be the first
+ // update in the new list.
+ newFirstCapturedUpdate = update;
+ // If this is the first update that was skipped, the current result is
+ // the new base state.
+ if (newFirstUpdate === null) {
+ newBaseState = resultState;
+ }
}
+ // Since this update will remain in the list, update the remaining
+ // expiration time.
+ if (newExpirationTime < _updateExpirationTime) {
+ newExpirationTime = _updateExpirationTime;
+ }
+ } else {
+ // This update does have sufficient priority. Process it and compute
+ // a new result.
+ resultState = getStateFromUpdate(
+ workInProgress,
+ queue,
+ update,
+ resultState,
+ props,
+ instance
+ );
+ var _callback2 = update.callback;
+ if (_callback2 !== null) {
+ workInProgress.effectTag |= Callback;
+ // Set this to null, in case it was mutated during an aborted render.
+ update.nextEffect = null;
+ if (queue.lastCapturedEffect === null) {
+ queue.firstCapturedEffect = queue.lastCapturedEffect = update;
+ } else {
+ queue.lastCapturedEffect.nextEffect = update;
+ queue.lastCapturedEffect = update;
+ }
+ }
+ }
+ update = update.next;
+ }
+
+ if (newFirstUpdate === null) {
+ queue.lastUpdate = null;
+ }
+ if (newFirstCapturedUpdate === null) {
+ queue.lastCapturedUpdate = null;
+ } else {
+ workInProgress.effectTag |= Callback;
+ }
+ if (newFirstUpdate === null && newFirstCapturedUpdate === null) {
+ // We processed every update, without skipping. That means the new base
+ // state is the same as the result state.
+ newBaseState = resultState;
+ }
+
+ queue.baseState = newBaseState;
+ queue.firstUpdate = newFirstUpdate;
+ queue.firstCapturedUpdate = newFirstCapturedUpdate;
+
+ // Set the remaining expiration time to be whatever is remaining in the queue.
+ // This should be fine because the only two other things that contribute to
+ // expiration time are props and context. We're already in the middle of the
+ // begin phase by the time we start processing the queue, so we've already
+ // dealt with the props. Context in components that specify
+ // shouldComponentUpdate is tricky; but we'll have to account for
+ // that regardless.
+ workInProgress.expirationTime = newExpirationTime;
+ workInProgress.memoizedState = resultState;
+
+ {
+ currentlyProcessingQueue = null;
+ }
+}
+
+function callCallback(callback, context) {
+ invariant(
+ typeof callback === "function",
+ "Invalid argument passed as callback. Expected a function. Instead " +
+ "received: %s",
+ callback
+ );
+ callback.call(context);
+}
+
+function resetHasForceUpdateBeforeProcessing() {
+ hasForceUpdate = false;
+}
+
+function checkHasForceUpdateAfterProcessing() {
+ return hasForceUpdate;
+}
+
+function commitUpdateQueue(
+ finishedWork,
+ finishedQueue,
+ instance,
+ renderExpirationTime
+) {
+ // If the finished render included captured updates, and there are still
+ // lower priority updates left over, we need to keep the captured updates
+ // in the queue so that they are rebased and not dropped once we process the
+ // queue again at the lower priority.
+ if (finishedQueue.firstCapturedUpdate !== null) {
+ // Join the captured update list to the end of the normal list.
+ if (finishedQueue.lastUpdate !== null) {
+ finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate;
+ finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate;
+ }
+ // Clear the list of captured updates.
+ finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null;
+ }
+
+ // Commit the effects
+ commitUpdateEffects(finishedQueue.firstEffect, instance);
+ finishedQueue.firstEffect = finishedQueue.lastEffect = null;
+
+ commitUpdateEffects(finishedQueue.firstCapturedEffect, instance);
+ finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null;
+}
+
+function commitUpdateEffects(effect, instance) {
+ while (effect !== null) {
+ var _callback3 = effect.callback;
+ if (_callback3 !== null) {
+ effect.callback = null;
+ callCallback(_callback3, instance);
+ }
+ effect = effect.nextEffect;
+ }
+}
+
+function createCapturedValue(value, source) {
+ // If the value is an error, call this function immediately after it is thrown
+ // so the stack is accurate.
+ return {
+ value: value,
+ source: source,
+ stack: getStackByFiberInDevAndProd(source)
+ };
}
function markUpdate(workInProgress) {
@@ -13464,7 +14515,12 @@
var nextDidTimeout = nextState !== null;
var prevDidTimeout = current !== null && current.memoizedState !== null;
- if (current !== null && !nextDidTimeout && prevDidTimeout) {
+ if (current === null) {
+ // In cases where we didn't find a suitable hydration boundary we never
+ // downgraded this to a DehydratedSuspenseComponent, but we still need to
+ // pop the hydration state since we might be inside the insertion tree.
+ popHydrationState(workInProgress);
+ } else if (!nextDidTimeout && prevDidTimeout) {
// We just switched from the fallback to the normal children. Delete
// the fallback.
// TODO: Would it be better to store the fallback fragment on
@@ -13483,18 +14539,10 @@
}
}
- // The children either timed out after previously being visible, or
- // were restored after previously being hidden. Schedule an effect
- // to update their visiblity.
- if (
- //
- nextDidTimeout !== prevDidTimeout ||
- // Outside concurrent mode, the primary children commit in an
- // inconsistent state, even if they are hidden. So if they are hidden,
- // we need to schedule an effect to re-hide them, just in case.
- ((workInProgress.effectTag & ConcurrentMode) === NoContext &&
- nextDidTimeout)
- ) {
+ if (nextDidTimeout || prevDidTimeout) {
+ // If the children are hidden, or if they were previous hidden, schedule
+ // an effect to toggle their visibility. This is also used to attach a
+ // retry listener to the promise.
workInProgress.effectTag |= Update;
}
break;
@@ -13526,6 +14574,29 @@
}
break;
}
+ case DehydratedSuspenseComponent: {
+ if (enableSuspenseServerRenderer) {
+ if (current === null) {
+ var _wasHydrated2 = popHydrationState(workInProgress);
+ invariant(
+ _wasHydrated2,
+ "A dehydrated suspense component was completed without a hydrated node. " +
+ "This is probably a bug in React."
+ );
+ skipPastDehydratedSuspenseInstance(workInProgress);
+ } else if ((workInProgress.effectTag & DidCapture) === NoEffect) {
+ // This boundary did not suspend so it's now hydrated.
+ // To handle any future suspense cases, we're going to now upgrade it
+ // to a Suspense component. We detach it from the existing current fiber.
+ current.alternate = null;
+ workInProgress.alternate = null;
+ workInProgress.tag = SuspenseComponent;
+ workInProgress.memoizedState = null;
+ workInProgress.stateNode = null;
+ }
+ }
+ break;
+ }
default:
invariant(
false,
@@ -13537,7 +14608,7 @@
return null;
}
-function shouldCaptureSuspense(current, workInProgress) {
+function shouldCaptureSuspense(workInProgress) {
// In order to capture, the Suspense component must have a fallback prop.
if (workInProgress.memoizedProps.fallback === undefined) {
return false;
@@ -13669,6 +14740,8 @@
didWarnAboutUndefinedSnapshotBeforeUpdate = new Set();
}
+var PossiblyWeakSet$1 = typeof WeakSet === "function" ? WeakSet : Set;
+
function logError(boundary, errorInfo) {
var source = errorInfo.source;
var stack = errorInfo.stack;
@@ -13847,9 +14920,6 @@
}
function commitHookEffectList(unmountTag, mountTag, finishedWork) {
- if (!enableHooks) {
- return;
- }
var updateQueue = finishedWork.updateQueue;
var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;
if (lastEffect !== null) {
@@ -13859,24 +14929,27 @@
if ((effect.tag & unmountTag) !== NoEffect$1) {
// Unmount
var destroy = effect.destroy;
- effect.destroy = null;
- if (destroy !== null) {
+ effect.destroy = undefined;
+ if (destroy !== undefined) {
destroy();
}
}
if ((effect.tag & mountTag) !== NoEffect$1) {
// Mount
var create = effect.create;
- var _destroy = create();
- if (typeof _destroy !== "function") {
+ effect.destroy = create();
+
{
- if (_destroy !== null && _destroy !== undefined) {
- warningWithoutStack$1(
- false,
- "useEffect function must return a cleanup function or " +
- "nothing.%s%s",
- typeof _destroy.then === "function"
- ? "\n\nIt looks like you wrote useEffect(async () => ...) or returned a Promise. " +
+ var _destroy = effect.destroy;
+ if (_destroy !== undefined && typeof _destroy !== "function") {
+ var addendum = void 0;
+ if (_destroy === null) {
+ addendum =
+ " You returned null. If your effect does not require clean " +
+ "up, return undefined (or nothing).";
+ } else if (typeof _destroy.then === "function") {
+ addendum =
+ "\n\nIt looks like you wrote useEffect(async () => ...) or returned a Promise. " +
"Instead, you may write an async function separately " +
"and then call it from inside the effect:\n\n" +
"async function fetchComment(commentId) {\n" +
@@ -13886,15 +14959,19 @@
" fetchComment(commentId);\n" +
"}, [commentId]);\n\n" +
"In the future, React will provide a more idiomatic solution for data fetching " +
- "that doesn't involve writing effects manually."
- : "",
+ "that doesn't involve writing effects manually.";
+ } else {
+ addendum = " You returned: " + _destroy;
+ }
+ warningWithoutStack$1(
+ false,
+ "An Effect function must not return anything besides a function, " +
+ "which is used for clean-up.%s%s",
+ addendum,
getStackByFiberInDevAndProd(finishedWork)
);
}
}
- _destroy = null;
- }
- effect.destroy = _destroy;
}
effect = effect.next;
} while (effect !== firstEffect);
@@ -14139,7 +15216,7 @@
function hideOrUnhideAllChildren(finishedWork, isHidden) {
if (supportsMutation) {
- // We only have the top Fiber that was inserted but we need recurse down its
+ // We only have the top Fiber that was inserted but we need to recurse down its
var node = finishedWork;
while (true) {
if (node.tag === HostComponent) {
@@ -14247,7 +15324,7 @@
var effect = firstEffect;
do {
var destroy = effect.destroy;
- if (destroy !== null) {
+ if (destroy !== undefined) {
safelyCallDestroy(current$$1, destroy);
}
effect = effect.next;
@@ -14421,7 +15498,11 @@
}
node.sibling.return = node.return;
node = node.sibling;
- while (node.tag !== HostComponent && node.tag !== HostText) {
+ while (
+ node.tag !== HostComponent &&
+ node.tag !== HostText &&
+ node.tag !== DehydratedSuspenseComponent
+ ) {
// If it is not host node and, we might have a host node inside it.
// Try to search down until we find one.
if (node.effectTag & Placement) {
@@ -14483,7 +15564,7 @@
}
var before = getHostSibling(finishedWork);
- // We only have the top Fiber that was inserted but we need recurse down its
+ // We only have the top Fiber that was inserted but we need to recurse down its
// children to find all the terminal nodes.
var node = finishedWork;
while (true) {
@@ -14525,7 +15606,7 @@
}
function unmountHostComponents(current$$1) {
- // We only have the top Fiber that was deleted but we need recurse down its
+ // We only have the top Fiber that was deleted but we need to recurse down its
var node = current$$1;
// Each iteration, currentParent is populated with node's host parent if not
@@ -14574,13 +15655,23 @@
removeChild(currentParent, node.stateNode);
}
// Don't visit children because we already visited them.
+ } else if (
+ enableSuspenseServerRenderer &&
+ node.tag === DehydratedSuspenseComponent
+ ) {
+ // Delete the dehydrated suspense boundary and all of its content.
+ if (currentParentIsContainer) {
+ clearSuspenseBoundaryFromContainer(currentParent, node.stateNode);
+ } else {
+ clearSuspenseBoundary(currentParent, node.stateNode);
+ }
} else if (node.tag === HostPortal) {
+ if (node.child !== null) {
// When we go into a portal, it becomes the parent to remove from.
// We will reassign it back when we pop the portal on the way up.
currentParent = node.stateNode.containerInfo;
currentParentIsContainer = true;
// Visit children because portals might contain host components.
- if (node.child !== null) {
node.child.return = node;
node = node.child;
continue;
@@ -14725,6 +15816,30 @@
if (primaryChildParent !== null) {
hideOrUnhideAllChildren(primaryChildParent, newDidTimeout);
}
+
+ // If this boundary just timed out, then it will have a set of thenables.
+ // For each thenable, attach a listener so that when it resolves, React
+ // attempts to re-render the boundary in the primary (pre-timeout) state.
+ var thenables = finishedWork.updateQueue;
+ if (thenables !== null) {
+ finishedWork.updateQueue = null;
+ var retryCache = finishedWork.stateNode;
+ if (retryCache === null) {
+ retryCache = finishedWork.stateNode = new PossiblyWeakSet$1();
+ }
+ thenables.forEach(function(thenable) {
+ // Memoize using the boundary fiber to prevent redundant listeners.
+ var retry = resolveRetryThenable.bind(null, finishedWork, thenable);
+ if (enableSchedulerTracing) {
+ retry = tracing.unstable_wrap(retry);
+ }
+ if (!retryCache.has(thenable)) {
+ retryCache.add(thenable);
+ thenable.then(retry, retry);
+ }
+ });
+ }
+
return;
}
case IncompleteClassComponent: {
@@ -14747,6 +15862,9 @@
resetTextContent(current$$1.stateNode);
}
+var PossiblyWeakSet = typeof WeakSet === "function" ? WeakSet : Set;
+var PossiblyWeakMap = typeof WeakMap === "function" ? WeakMap : Map;
+
function createRootErrorUpdate(fiber, errorInfo, expirationTime) {
var update = createUpdate(expirationTime);
// Unmount the root by rendering null.
@@ -14810,6 +15928,39 @@
return update;
}
+function attachPingListener(root, renderExpirationTime, thenable) {
+ // Attach a listener to the promise to "ping" the root and retry. But
+ // only if one does not already exist for the current render expiration
+ // time (which acts like a "thread ID" here).
+ var pingCache = root.pingCache;
+ var threadIDs = void 0;
+ if (pingCache === null) {
+ pingCache = root.pingCache = new PossiblyWeakMap();
+ threadIDs = new Set();
+ pingCache.set(thenable, threadIDs);
+ } else {
+ threadIDs = pingCache.get(thenable);
+ if (threadIDs === undefined) {
+ threadIDs = new Set();
+ pingCache.set(thenable, threadIDs);
+ }
+ }
+ if (!threadIDs.has(renderExpirationTime)) {
+ // Memoize using the thread ID to prevent redundant listeners.
+ threadIDs.add(renderExpirationTime);
+ var ping = pingSuspendedRoot.bind(
+ null,
+ root,
+ thenable,
+ renderExpirationTime
+ );
+ if (enableSchedulerTracing) {
+ ping = tracing.unstable_wrap(ping);
+ }
+ thenable.then(ping, ping);
+ }
+}
+
function throwException(
root,
returnFiber,
@@ -14864,6 +16015,9 @@
}
}
}
+ // If there is a DehydratedSuspenseComponent we don't have to do anything because
+ // if something suspends inside it, we will simply leave that as dehydrated. It
+ // will never timeout.
_workInProgress = _workInProgress.return;
} while (_workInProgress !== null);
@@ -14872,29 +16026,19 @@
do {
if (
_workInProgress.tag === SuspenseComponent &&
- shouldCaptureSuspense(_workInProgress.alternate, _workInProgress)
+ shouldCaptureSuspense(_workInProgress)
) {
// Found the nearest boundary.
- // If the boundary is not in concurrent mode, we should not suspend, and
- // likewise, when the promise resolves, we should ping synchronously.
- var pingTime =
- (_workInProgress.mode & ConcurrentMode) === NoEffect
- ? Sync
- : renderExpirationTime;
-
- // Attach a listener to the promise to "ping" the root and retry.
- var onResolveOrReject = retrySuspendedRoot.bind(
- null,
- root,
- _workInProgress,
- sourceFiber,
- pingTime
- );
- if (enableSchedulerTracing) {
- onResolveOrReject = tracing.unstable_wrap(onResolveOrReject);
+ // Stash the promise on the boundary fiber. If the boundary times out, we'll
+ var thenables = _workInProgress.updateQueue;
+ if (thenables === null) {
+ var updateQueue = new Set();
+ updateQueue.add(thenable);
+ _workInProgress.updateQueue = updateQueue;
+ } else {
+ thenables.add(thenable);
}
- thenable.then(onResolveOrReject, onResolveOrReject);
// If the boundary is outside of concurrent mode, we should *not*
// suspend the commit. Pretend as if the suspended component rendered
@@ -14913,18 +16057,25 @@
sourceFiber.effectTag &= ~(LifecycleEffectMask | Incomplete);
if (sourceFiber.tag === ClassComponent) {
- var _current = sourceFiber.alternate;
- if (_current === null) {
+ var currentSourceFiber = sourceFiber.alternate;
+ if (currentSourceFiber === null) {
// This is a new mount. Change the tag so it's not mistaken for a
// completed class component. For example, we should not call
// componentWillUnmount if it is deleted.
sourceFiber.tag = IncompleteClassComponent;
+ } else {
+ // When we try rendering again, we should not reuse the current fiber,
+ // since it's known to be in an inconsistent state. Use a force updte to
+ // prevent a bail out.
+ var update = createUpdate(Sync);
+ update.tag = ForceUpdate;
+ enqueueUpdate(sourceFiber, update);
}
}
- // The source fiber did not complete. Mark it with the current
- // render priority to indicate that it still has pending work.
- sourceFiber.expirationTime = renderExpirationTime;
+ // The source fiber did not complete. Mark it with Sync priority to
+ // indicate that it still has pending work.
+ sourceFiber.expirationTime = Sync;
// Exit without suspending.
return;
@@ -14933,9 +16084,11 @@
// Confirmed that the boundary is in a concurrent mode tree. Continue
// with the normal suspend path.
+ attachPingListener(root, renderExpirationTime, thenable);
+
var absoluteTimeoutMs = void 0;
if (earliestTimeoutMs === -1) {
- // If no explicit threshold is given, default to an abitrarily large
+ // If no explicit threshold is given, default to an arbitrarily large
// value. The actual size doesn't matter because the threshold for the
// whole tree will be clamped to the expiration time.
absoluteTimeoutMs = maxSigned31BitInt;
@@ -14971,6 +16124,40 @@
_workInProgress.effectTag |= ShouldCapture;
_workInProgress.expirationTime = renderExpirationTime;
return;
+ } else if (
+ enableSuspenseServerRenderer &&
+ _workInProgress.tag === DehydratedSuspenseComponent
+ ) {
+ attachPingListener(root, renderExpirationTime, thenable);
+
+ // Since we already have a current fiber, we can eagerly add a retry listener.
+ var retryCache = _workInProgress.memoizedState;
+ if (retryCache === null) {
+ retryCache = _workInProgress.memoizedState = new PossiblyWeakSet();
+ var _current = _workInProgress.alternate;
+ invariant(
+ _current,
+ "A dehydrated suspense boundary must commit before trying to render. " +
+ "This is probably a bug in React."
+ );
+ _current.memoizedState = retryCache;
+ }
+ // Memoize using the boundary fiber to prevent redundant listeners.
+ if (!retryCache.has(thenable)) {
+ retryCache.add(thenable);
+ var retry = resolveRetryThenable.bind(
+ null,
+ _workInProgress,
+ thenable
+ );
+ if (enableSchedulerTracing) {
+ retry = tracing.unstable_wrap(retry);
+ }
+ thenable.then(retry, retry);
+ }
+ _workInProgress.effectTag |= ShouldCapture;
+ _workInProgress.expirationTime = renderExpirationTime;
+ return;
}
// This boundary already captured during this render. Continue to the next
// boundary.
@@ -15000,12 +16187,12 @@
var _errorInfo = value;
workInProgress.effectTag |= ShouldCapture;
workInProgress.expirationTime = renderExpirationTime;
- var update = createRootErrorUpdate(
+ var _update = createRootErrorUpdate(
workInProgress,
_errorInfo,
renderExpirationTime
);
- enqueueCapturedUpdate(workInProgress, update);
+ enqueueCapturedUpdate(workInProgress, _update);
return;
}
case ClassComponent:
@@ -15023,12 +16210,12 @@
workInProgress.effectTag |= ShouldCapture;
workInProgress.expirationTime = renderExpirationTime;
// Schedule the error boundary to re-render using updated state
- var _update = createClassErrorUpdate(
+ var _update2 = createClassErrorUpdate(
workInProgress,
errorInfo,
renderExpirationTime
);
- enqueueCapturedUpdate(workInProgress, _update);
+ enqueueCapturedUpdate(workInProgress, _update2);
return;
}
break;
@@ -15066,6 +16253,7 @@
return workInProgress;
}
case HostComponent: {
+ // TODO: popHydrationState
popHostContext(workInProgress);
return null;
}
@@ -15078,6 +16266,19 @@
}
return null;
}
+ case DehydratedSuspenseComponent: {
+ if (enableSuspenseServerRenderer) {
+ // TODO: popHydrationState
+ var _effectTag3 = workInProgress.effectTag;
+ if (_effectTag3 & ShouldCapture) {
+ workInProgress.effectTag =
+ (_effectTag3 & ~ShouldCapture) | DidCapture;
+ // Captured a suspense effect. Re-render the boundary.
+ return workInProgress;
+ }
+ }
+ return null;
+ }
case HostPortal:
popHostContainer(workInProgress);
return null;
@@ -15118,22 +16319,7 @@
}
}
-var Dispatcher = {
- readContext: readContext,
- useCallback: useCallback,
- useContext: useContext,
- useEffect: useEffect,
- useImperativeMethods: useImperativeMethods,
- useLayoutEffect: useLayoutEffect,
- useMemo: useMemo,
- useReducer: useReducer,
- useRef: useRef,
- useState: useState
-};
-var DispatcherWithoutHooks = {
- readContext: readContext
-};
-
+var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
var ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner;
var didWarnAboutStateTransition = void 0;
@@ -15206,11 +16392,6 @@
};
}
-// Represents the expiration time that incoming updates should use. (If this
-// is NoWork, use the default strategy: async updates in async mode, sync
-// updates in sync mode.)
-var expirationContext = NoWork;
-
var isWorking = false;
// The next work in progress fiber that we're currently working on.
@@ -15443,6 +16624,9 @@
}
}
while (nextEffect !== null) {
+ {
+ setCurrentFiber(nextEffect);
+ }
var effectTag = nextEffect.effectTag;
if (effectTag & (Update | Callback)) {
@@ -15461,12 +16645,15 @@
commitAttachRef(nextEffect);
}
- if (enableHooks && effectTag & Passive) {
+ if (effectTag & Passive) {
rootWithPendingPassiveEffects = finishedRoot;
}
nextEffect = nextEffect.nextEffect;
}
+ {
+ resetCurrentFiber();
+ }
}
function commitPassiveEffects(root, firstEffect) {
@@ -15480,6 +16667,10 @@
var effect = firstEffect;
do {
+ {
+ setCurrentFiber(effect);
+ }
+
if (effect.effectTag & Passive) {
var didError = false;
var error = void 0;
@@ -15496,6 +16687,9 @@
}
effect = effect.nextEffect;
} while (effect !== null);
+ {
+ resetCurrentFiber();
+ }
isRendering = previousIsRendering;
@@ -15504,6 +16698,10 @@
if (rootExpirationTime !== NoWork) {
requestWork(root, rootExpirationTime);
}
+ // Flush any sync work that was scheduled by effects
+ if (!isBatchingUpdates && !isRendering) {
+ performSyncWork();
+ }
}
function isAlreadyFailedLegacyErrorBoundary(instance) {
@@ -15522,8 +16720,10 @@
}
function flushPassiveEffects() {
+ if (passiveEffectCallbackHandle !== null) {
+ cancelPassiveEffects(passiveEffectCallbackHandle);
+ }
if (passiveEffectCallback !== null) {
- scheduler.unstable_cancelCallback(passiveEffectCallbackHandle);
// We call the scheduled callback instead of commitPassiveEffects directly
// to ensure tracing works correctly.
passiveEffectCallback();
@@ -15697,11 +16897,7 @@
}
}
- if (
- enableHooks &&
- firstEffect !== null &&
- rootWithPendingPassiveEffects !== null
- ) {
+ if (firstEffect !== null && rootWithPendingPassiveEffects !== null) {
// This commit included a passive effect. These do not need to fire until
// after the next paint. Schedule an callback to fire them in an async
// event. To ensure serial execution, the callback will be flushed early if
@@ -15713,7 +16909,12 @@
// here because that code is still in flux.
callback = tracing.unstable_wrap(callback);
}
- passiveEffectCallbackHandle = scheduler.unstable_scheduleCallback(callback);
+ passiveEffectCallbackHandle = scheduler.unstable_runWithPriority(
+ scheduler.unstable_NormalPriority,
+ function() {
+ return schedulePassiveEffects(callback);
+ }
+ );
passiveEffectCallback = callback;
}
@@ -16116,7 +17317,7 @@
}
} else {
// Flush asynchronous work until there's a higher priority event
- while (nextUnitOfWork !== null && !shouldYieldToRenderer()) {
+ while (nextUnitOfWork !== null && !shouldYield$$1()) {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
}
}
@@ -16132,11 +17333,8 @@
flushPassiveEffects();
isWorking = true;
- if (enableHooks) {
- ReactCurrentOwner$2.currentDispatcher = Dispatcher;
- } else {
- ReactCurrentOwner$2.currentDispatcher = DispatcherWithoutHooks;
- }
+ var previousDispatcher = ReactCurrentDispatcher.current;
+ ReactCurrentDispatcher.current = ContextOnlyDispatcher;
var expirationTime = root.nextExpirationTimeToWorkOn;
@@ -16190,7 +17388,7 @@
subscriber.onWorkStarted(interactions, threadID);
} catch (error) {
// Work thrown by an interaction tracing subscriber should be rethrown,
- // But only once it's safe (to avoid leaveing the scheduler in an invalid state).
+ // But only once it's safe (to avoid leaving the scheduler in an invalid state).
// Store the error for now and we'll re-throw in finishRendering().
if (!hasUnhandledError) {
hasUnhandledError = true;
@@ -16297,7 +17495,7 @@
// We're done performing work. Time to clean up.
isWorking = false;
- ReactCurrentOwner$2.currentDispatcher = null;
+ ReactCurrentDispatcher.current = previousDispatcher;
resetContextDependences();
resetHooks();
@@ -16367,7 +17565,7 @@
return;
} else if (
// There's no lower priority work, but we're rendering asynchronously.
- // Synchronsouly attempt to render the same level one more time. This is
+ // Synchronously attempt to render the same level one more time. This is
// similar to a suspend, but without a timeout because we're not waiting
// for a promise to resolve.
!root.didError &&
@@ -16481,52 +17679,58 @@
}
function computeExpirationForFiber(currentTime, fiber) {
+ var priorityLevel = scheduler.unstable_getCurrentPriorityLevel();
+
var expirationTime = void 0;
- if (expirationContext !== NoWork) {
- // An explicit expiration context was set;
- expirationTime = expirationContext;
- } else if (isWorking) {
- if (isCommitting$1) {
- // Updates that occur during the commit phase should have sync priority
- // by default.
+ if ((fiber.mode & ConcurrentMode) === NoContext) {
+ // Outside of concurrent mode, updates are always synchronous.
expirationTime = Sync;
- } else {
- // Updates during the render phase should expire at the same time as
- // the work that is being rendered.
+ } else if (isWorking && !isCommitting$1) {
+ // During render phase, updates expire during as the current render.
expirationTime = nextRenderExpirationTime;
- }
} else {
- // No explicit expiration context was set, and we're not currently
- // performing work. Calculate a new expiration time.
- if (fiber.mode & ConcurrentMode) {
- if (isBatchingInteractiveUpdates) {
- // This is an interactive update
+ switch (priorityLevel) {
+ case scheduler.unstable_ImmediatePriority:
+ expirationTime = Sync;
+ break;
+ case scheduler.unstable_UserBlockingPriority:
expirationTime = computeInteractiveExpiration(currentTime);
- } else {
- // This is an async update
+ break;
+ case scheduler.unstable_NormalPriority:
+ // This is a normal, concurrent update
expirationTime = computeAsyncExpiration(currentTime);
+ break;
+ case scheduler.unstable_LowPriority:
+ case scheduler.unstable_IdlePriority:
+ expirationTime = Never;
+ break;
+ default:
+ invariant(
+ false,
+ "Unknown priority level. This error is likely caused by a bug in " +
+ "React. Please file an issue."
+ );
}
+
// If we're in the middle of rendering a tree, do not update at the same
// expiration time that is already rendering.
if (nextRoot !== null && expirationTime === nextRenderExpirationTime) {
expirationTime -= 1;
}
- } else {
- // This is a sync update
- expirationTime = Sync;
- }
}
- if (isBatchingInteractiveUpdates) {
- // This is an interactive update. Keep track of the lowest pending
- // interactive expiration time. This allows us to synchronously flush
- // all interactive updates when needed.
- if (
- lowestPriorityPendingInteractiveExpirationTime === NoWork ||
- expirationTime < lowestPriorityPendingInteractiveExpirationTime
+
+ // Keep track of the lowest pending interactive expiration time. This
+ // allows us to synchronously flush all interactive updates
+ // when needed.
+ // TODO: Move this to renderer?
+ if (
+ priorityLevel === scheduler.unstable_UserBlockingPriority &&
+ (lowestPriorityPendingInteractiveExpirationTime === NoWork ||
+ expirationTime < lowestPriorityPendingInteractiveExpirationTime)
) {
lowestPriorityPendingInteractiveExpirationTime = expirationTime;
}
- }
+
return expirationTime;
}
@@ -16544,57 +17748,77 @@
nextRenderDidError = true;
}
-function retrySuspendedRoot(root, boundaryFiber, sourceFiber, suspendedTime) {
- var retryTime = void 0;
-
- if (isPriorityLevelSuspended(root, suspendedTime)) {
- // Ping at the original level
- retryTime = suspendedTime;
-
- markPingedPriorityLevel(root, retryTime);
- } else {
- // Suspense already timed out. Compute a new expiration time
- var currentTime = requestCurrentTime();
- retryTime = computeExpirationForFiber(currentTime, boundaryFiber);
- markPendingPriorityLevel(root, retryTime);
+function pingSuspendedRoot(root, thenable, pingTime) {
+ // A promise that previously suspended React from committing has resolved.
+ // If React is still suspended, try again at the previous level (pingTime).
+
+ var pingCache = root.pingCache;
+ if (pingCache !== null) {
+ // The thenable resolved, so we no longer need to memoize, because it will
+ // never be thrown again.
+ pingCache.delete(thenable);
}
- // TODO: If the suspense fiber has already rendered the primary children
- // without suspending (that is, all of the promises have already resolved),
- // we should not trigger another update here. One case this happens is when
- // we are in sync mode and a single promise is thrown both on initial render
- // and on update; we attach two .then(retrySuspendedRoot) callbacks and each
- // one performs Sync work, rerendering the Suspense.
-
- if ((boundaryFiber.mode & ConcurrentMode) !== NoContext) {
- if (root === nextRoot && nextRenderExpirationTime === suspendedTime) {
+ if (nextRoot !== null && nextRenderExpirationTime === pingTime) {
// Received a ping at the same priority level at which we're currently
// rendering. Restart from the root.
nextRoot = null;
+ } else {
+ // Confirm that the root is still suspended at this level. Otherwise exit.
+ if (isPriorityLevelSuspended(root, pingTime)) {
+ // Ping at the original level
+ markPingedPriorityLevel(root, pingTime);
+ var rootExpirationTime = root.expirationTime;
+ if (rootExpirationTime !== NoWork) {
+ requestWork(root, rootExpirationTime);
}
}
-
- scheduleWorkToRoot(boundaryFiber, retryTime);
- if ((boundaryFiber.mode & ConcurrentMode) === NoContext) {
- // Outside of concurrent mode, we must schedule an update on the source
- // fiber, too, since it already committed in an inconsistent state and
- // therefore does not have any pending work.
- scheduleWorkToRoot(sourceFiber, retryTime);
- var sourceTag = sourceFiber.tag;
- if (sourceTag === ClassComponent && sourceFiber.stateNode !== null) {
- // When we try rendering again, we should not reuse the current fiber,
- // since it's known to be in an inconsistent state. Use a force updte to
- // prevent a bail out.
- var update = createUpdate(retryTime);
- update.tag = ForceUpdate;
- enqueueUpdate(sourceFiber, update);
- }
}
+}
+function retryTimedOutBoundary(boundaryFiber) {
+ var currentTime = requestCurrentTime();
+ var retryTime = computeExpirationForFiber(currentTime, boundaryFiber);
+ var root = scheduleWorkToRoot(boundaryFiber, retryTime);
+ if (root !== null) {
+ markPendingPriorityLevel(root, retryTime);
var rootExpirationTime = root.expirationTime;
if (rootExpirationTime !== NoWork) {
requestWork(root, rootExpirationTime);
}
+ }
+}
+
+function resolveRetryThenable(boundaryFiber, thenable) {
+ // The boundary fiber (a Suspense component) previously timed out and was
+ // rendered in its fallback state. One of the promises that suspended it has
+ // resolved, which means at least part of the tree was likely unblocked. Try
+ var retryCache = void 0;
+ if (enableSuspenseServerRenderer) {
+ switch (boundaryFiber.tag) {
+ case SuspenseComponent:
+ retryCache = boundaryFiber.stateNode;
+ break;
+ case DehydratedSuspenseComponent:
+ retryCache = boundaryFiber.memoizedState;
+ break;
+ default:
+ invariant(
+ false,
+ "Pinged unknown suspense boundary type. " +
+ "This is probably a bug in React."
+ );
+ }
+ } else {
+ retryCache = boundaryFiber.stateNode;
+ }
+ if (retryCache !== null) {
+ // The thenable resolved, so we no longer need to memoize, because it will
+ // never be thrown again.
+ retryCache.delete(thenable);
+ }
+
+ retryTimedOutBoundary(boundaryFiber);
}
function scheduleWorkToRoot(fiber, expirationTime) {
@@ -16683,6 +17907,27 @@
return root;
}
+function warnIfNotCurrentlyBatchingInDev(fiber) {
+ {
+ if (isRendering === false && isBatchingUpdates === false) {
+ warningWithoutStack$1(
+ false,
+ "An update to %s inside a test was not wrapped in act(...).\n\n" +
+ "When testing, code that causes React state updates should be wrapped into act(...):\n\n" +
+ "act(() => {\n" +
+ " /* fire events that update state */\n" +
+ "});\n" +
+ "/* assert on the output */\n\n" +
+ "This ensures that you're testing the behavior the user would see in the browser." +
+ " Learn more at https://fb.me/react-wrap-tests-with-act" +
+ "%s",
+ getComponentName(fiber.type),
+ getStackByFiberInDevAndProd(fiber)
+ );
+ }
+ }
+}
+
function scheduleWork(fiber, expirationTime) {
var root = scheduleWorkToRoot(fiber, expirationTime);
if (root === null) {
@@ -16754,7 +17999,6 @@
var isBatchingUpdates = false;
var isUnbatchingUpdates = false;
-var isBatchingInteractiveUpdates = false;
var completedBatches = null;
@@ -16820,7 +18064,7 @@
msUntilTimeout
) {
root.expirationTime = rootExpirationTime;
- if (msUntilTimeout === 0 && !shouldYieldToRenderer()) {
+ if (msUntilTimeout === 0 && !shouldYield$$1()) {
// Don't wait an additional tick. Commit the tree immediately.
root.pendingCommitExpirationTime = suspendedExpirationTime;
root.finishedWork = finishedWork;
@@ -17017,24 +18261,8 @@
nextFlushedExpirationTime = highestPriorityWork;
}
-// TODO: This wrapper exists because many of the older tests (the ones that use
-// flushDeferredPri) rely on the number of times `shouldYield` is called. We
-// should get rid of it.
-var didYield = false;
-function shouldYieldToRenderer() {
- if (didYield) {
- return true;
- }
- if (shouldYield$$1()) {
- didYield = true;
- return true;
- }
- return false;
-}
-
-function performAsyncWork() {
- try {
- if (!shouldYieldToRenderer()) {
+function performAsyncWork(didTimeout) {
+ if (didTimeout) {
// The callback timed out. That means at least one update has expired.
// Iterate through the root schedule. If they contain expired work, set
// the next render expiration time to the current time. This has the effect
@@ -17051,9 +18279,6 @@
}
}
performWork(NoWork, true);
- } finally {
- didYield = false;
- }
}
function performSyncWork() {
@@ -17079,7 +18304,7 @@
nextFlushedRoot !== null &&
nextFlushedExpirationTime !== NoWork &&
minExpirationTime <= nextFlushedExpirationTime &&
- !(didYield && currentRendererTime > nextFlushedExpirationTime)
+ !(shouldYield$$1() && currentRendererTime > nextFlushedExpirationTime)
) {
performWorkOnRoot(
nextFlushedRoot,
@@ -17223,7 +18448,7 @@
if (_finishedWork !== null) {
// We've completed the root. Check the if we should yield one more time
// before committing.
- if (!shouldYieldToRenderer()) {
+ if (!shouldYield$$1()) {
// Still time left. Commit the root.
completeRoot(root, _finishedWork, expirationTime);
} else {
@@ -17270,7 +18495,12 @@
lastCommittedRootDuringThisBatch = root;
nestedUpdateCount = 0;
}
+ scheduler.unstable_runWithPriority(
+ scheduler.unstable_ImmediatePriority,
+ function() {
commitRoot(root, finishedWork);
+ }
+ );
}
function onUncaughtError(error) {
@@ -17304,9 +18534,6 @@
}
function interactiveUpdates$1(fn, a, b) {
- if (isBatchingInteractiveUpdates) {
- return fn(a, b);
- }
// If there are any pending interactive updates, synchronously flush them.
// This needs to happen before we read any handlers, because the effect of
// the previous event may influence which handlers are called during
@@ -17320,14 +18547,16 @@
performWork(lowestPriorityPendingInteractiveExpirationTime, false);
lowestPriorityPendingInteractiveExpirationTime = NoWork;
}
- var previousIsBatchingInteractiveUpdates = isBatchingInteractiveUpdates;
var previousIsBatchingUpdates = isBatchingUpdates;
- isBatchingInteractiveUpdates = true;
isBatchingUpdates = true;
try {
+ return scheduler.unstable_runWithPriority(
+ scheduler.unstable_UserBlockingPriority,
+ function() {
return fn(a, b);
+ }
+ );
} finally {
- isBatchingInteractiveUpdates = previousIsBatchingInteractiveUpdates;
isBatchingUpdates = previousIsBatchingUpdates;
if (!isBatchingUpdates && !isRendering) {
performSyncWork();
@@ -17555,11 +18784,43 @@
}
}
+var overrideProps = null;
+
+{
+ var copyWithSetImpl = function(obj, path, idx, value) {
+ if (idx >= path.length) {
+ return value;
+ }
+ var key = path[idx];
+ var updated = Array.isArray(obj) ? obj.slice() : Object.assign({}, obj);
+ // $FlowFixMe number or string is fine here
+ updated[key] = copyWithSetImpl(obj[key], path, idx + 1, value);
+ return updated;
+ };
+
+ var copyWithSet = function(obj, path, value) {
+ return copyWithSetImpl(obj, path, 0, value);
+ };
+
+ // Support DevTools props for function components, forwardRef, memo, host components, etc.
+ overrideProps = function(fiber, path, value) {
+ flushPassiveEffects();
+ fiber.pendingProps = copyWithSet(fiber.memoizedProps, path, value);
+ if (fiber.alternate) {
+ fiber.alternate.pendingProps = fiber.pendingProps;
+ }
+ scheduleWork(fiber, Sync);
+ };
+}
+
function injectIntoDevTools(devToolsConfig) {
var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance;
+ var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
return injectInternals(
Object.assign({}, devToolsConfig, {
+ overrideProps: overrideProps,
+ currentDispatcherRef: ReactCurrentDispatcher,
findHostInstanceByFiber: function(fiber) {
var hostFiber = findCurrentHostFiber(fiber);
if (hostFiber === null) {
@@ -17602,7 +18863,7 @@
// TODO: this is special because it gets imported during build.
-var ReactVersion = "16.6.1";
+var ReactVersion = "16.8.3";
// Modules provided by RN:
var NativeMethodsMixin = function(findNodeHandle, findHostInstance) {
@@ -17696,6 +18957,17 @@
* Manipulation](docs/direct-manipulation.html)).
*/
setNativeProps: function(nativeProps) {
+ {
+ if (warnAboutDeprecatedSetNativeProps) {
+ warningWithoutStack$1(
+ false,
+ "Warning: Calling ref.setNativeProps(nativeProps) " +
+ "is deprecated and will be removed in a future release. " +
+ "Use the setNativeProps export from the react-native package instead." +
+ "\n\timport {setNativeProps} from 'react-native';\n\tsetNativeProps(ref, nativeProps);\n"
+ );
+ }
+ }
// Class components don't have viewConfig -> validateAttributes.
// Nor does it make sense to set native props on a non-native component.
// Instead, find the nearest host component and set props on it.
@@ -17717,7 +18989,10 @@
return;
}
- var viewConfig = maybeInstance.viewConfig;
+ var nativeTag =
+ maybeInstance._nativeTag || maybeInstance.canonical._nativeTag;
+ var viewConfig =
+ maybeInstance.viewConfig || maybeInstance.canonical.viewConfig;
{
warnForStyleProps(nativeProps, viewConfig.validAttributes);
@@ -17730,7 +19005,7 @@
// view invalidation for certain components (eg RCTTextInput) on iOS.
if (updatePayload != null) {
UIManager.updateView(
- maybeInstance._nativeTag,
+ nativeTag,
viewConfig.uiViewClassName,
updatePayload
);
@@ -17951,6 +19226,18 @@
ReactNativeComponent.prototype.setNativeProps = function setNativeProps(
nativeProps
) {
+ {
+ if (warnAboutDeprecatedSetNativeProps) {
+ warningWithoutStack$1(
+ false,
+ "Warning: Calling ref.setNativeProps(nativeProps) " +
+ "is deprecated and will be removed in a future release. " +
+ "Use the setNativeProps export from the react-native package instead." +
+ "\n\timport {setNativeProps} from 'react-native';\n\tsetNativeProps(ref, nativeProps);\n"
+ );
+ }
+ }
+
// Class components don't have viewConfig -> validateAttributes.
// Nor does it make sense to set native props on a non-native component.
// Instead, find the nearest host component and set props on it.
@@ -17972,6 +19259,8 @@
return;
}
+ var nativeTag =
+ maybeInstance._nativeTag || maybeInstance.canonical._nativeTag;
var viewConfig =
maybeInstance.viewConfig || maybeInstance.canonical.viewConfig;
@@ -17982,7 +19271,7 @@
// view invalidation for certain components (eg RCTTextInput) on iOS.
if (updatePayload != null) {
UIManager.updateView(
- maybeInstance._nativeTag,
+ nativeTag,
viewConfig.uiViewClassName,
updatePayload
);
@@ -18104,6 +19393,36 @@
};
}
+// Module provided by RN:
+function setNativeProps(handle, nativeProps) {
+ if (handle._nativeTag == null) {
+ !(handle._nativeTag != null)
+ ? warningWithoutStack$1(
+ false,
+ "setNativeProps was called with a ref that isn't a " +
+ "native component. Use React.forwardRef to get access to the underlying native component"
+ )
+ : void 0;
+ return;
+ }
+
+ {
+ warnForStyleProps(nativeProps, handle.viewConfig.validAttributes);
+ }
+
+ var updatePayload = create(nativeProps, handle.viewConfig.validAttributes);
+ // Avoid the overhead of bridge calls if there's no update.
+ // This is an expensive no-op for Android, and causes an unnecessary
+ // view invalidation for certain components (eg RCTTextInput) on iOS.
+ if (updatePayload != null) {
+ UIManager.updateView(
+ handle._nativeTag,
+ handle.viewConfig.uiViewClassName,
+ updatePayload
+ );
+ }
+}
+
// TODO: direct imports like some-package/src/* are bad. Fix me.
// Module provided by RN:
var ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
@@ -18179,6 +19498,8 @@
findNodeHandle: findNodeHandle,
+ setNativeProps: setNativeProps,
+
render: function(element, containerTag, callback) {
var root = roots.get(containerTag);

Libraries/Renderer/oss/ReactNativeRenderer-prod.js

@@ -1129,8 +1129,10 @@
}
});
var ReactSharedInternals =
- React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
- hasSymbol = "function" === typeof Symbol && Symbol.for,
+ React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
+ReactSharedInternals.hasOwnProperty("ReactCurrentDispatcher") ||
+ (ReactSharedInternals.ReactCurrentDispatcher = { current: null });
+var hasSymbol = "function" === typeof Symbol && Symbol.for,
REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for("react.element") : 60103,
REACT_PORTAL_TYPE = hasSymbol ? Symbol.for("react.portal") : 60106,
REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for("react.fragment") : 60107,
@@ -1598,6 +1600,10 @@
scheduledCallback = null;
null !== callback && callback();
}
+function scheduleDeferredCallback$1(callback) {
+ scheduledCallback = callback;
+ return setTimeout(setTimeoutCallback, 1);
+}
function shim$1() {
invariant(
!1,
@@ -1631,8 +1637,24 @@
return !1;
}
var scheduleTimeout = setTimeout,
- cancelTimeout = clearTimeout,
- BEFORE_SLASH_RE = /^(.*)[\\\/]/;
+ cancelTimeout = clearTimeout;
+function commitUpdate(instance, updatePayloadTODO, type, oldProps, newProps) {
+ updatePayloadTODO = instance.viewConfig;
+ instanceProps[instance._nativeTag] = newProps;
+ oldProps = diffProperties(
+ null,
+ oldProps,
+ newProps,
+ updatePayloadTODO.validAttributes
+ );
+ null != oldProps &&
+ UIManager.updateView(
+ instance._nativeTag,
+ updatePayloadTODO.uiViewClassName,
+ oldProps
+ );
+}
+var BEFORE_SLASH_RE = /^(.*)[\\\/]/;
function getStackByFiberInDevAndProd(workInProgress) {
var info = "";
do {
@@ -1797,7 +1819,7 @@
this.index = 0;
this.ref = null;
this.pendingProps = pendingProps;
- this.firstContextDependency = this.memoizedState = this.updateQueue = this.memoizedProps = null;
+ this.contextDependencies = this.memoizedState = this.updateQueue = this.memoizedProps = null;
this.mode = mode;
this.effectTag = 0;
this.lastEffect = this.firstEffect = this.nextEffect = null;
@@ -1846,7 +1868,7 @@
workInProgress.memoizedProps = current.memoizedProps;
workInProgress.memoizedState = current.memoizedState;
workInProgress.updateQueue = current.updateQueue;
- workInProgress.firstContextDependency = current.firstContextDependency;
+ workInProgress.contextDependencies = current.contextDependencies;
workInProgress.sibling = current.sibling;
workInProgress.index = current.index;
workInProgress.ref = current.ref;
@@ -1970,26 +1992,53 @@
(root.latestPendingTime = expirationTime);
findNextExpirationTimeToWorkOn(expirationTime, root);
}
-function markSuspendedPriorityLevel(root, suspendedTime) {
+function markCommittedPriorityLevels(root, earliestRemainingTime) {
root.didError = !1;
- var latestPingedTime = root.latestPingedTime;
- 0 !== latestPingedTime &&
- latestPingedTime >= suspendedTime &&
+ if (0 === earliestRemainingTime)
+ (root.earliestPendingTime = 0),
+ (root.latestPendingTime = 0),
+ (root.earliestSuspendedTime = 0),
+ (root.latestSuspendedTime = 0),
+ (root.latestPingedTime = 0);
+ else {
+ earliestRemainingTime < root.latestPingedTime &&
(root.latestPingedTime = 0);
- latestPingedTime = root.earliestPendingTime;
var latestPendingTime = root.latestPendingTime;
- latestPingedTime === suspendedTime
+ 0 !== latestPendingTime &&
+ (latestPendingTime > earliestRemainingTime
+ ? (root.earliestPendingTime = root.latestPendingTime = 0)
+ : root.earliestPendingTime > earliestRemainingTime &&
+ (root.earliestPendingTime = root.latestPendingTime));
+ latestPendingTime = root.earliestSuspendedTime;
+ 0 === latestPendingTime
+ ? markPendingPriorityLevel(root, earliestRemainingTime)
+ : earliestRemainingTime < root.latestSuspendedTime
+ ? ((root.earliestSuspendedTime = 0),
+ (root.latestSuspendedTime = 0),
+ (root.latestPingedTime = 0),
+ markPendingPriorityLevel(root, earliestRemainingTime))
+ : earliestRemainingTime > latestPendingTime &&
+ markPendingPriorityLevel(root, earliestRemainingTime);
+ }
+ findNextExpirationTimeToWorkOn(0, root);
+}
+function markSuspendedPriorityLevel(root, suspendedTime) {
+ root.didError = !1;
+ root.latestPingedTime >= suspendedTime && (root.latestPingedTime = 0);
+ var earliestPendingTime = root.earliestPendingTime,
+ latestPendingTime = root.latestPendingTime;
+ earliestPendingTime === suspendedTime
? (root.earliestPendingTime =
latestPendingTime === suspendedTime
? (root.latestPendingTime = 0)
: latestPendingTime)
: latestPendingTime === suspendedTime &&
- (root.latestPendingTime = latestPingedTime);
- latestPingedTime = root.earliestSuspendedTime;
+ (root.latestPendingTime = earliestPendingTime);
+ earliestPendingTime = root.earliestSuspendedTime;
latestPendingTime = root.latestSuspendedTime;
- 0 === latestPingedTime
+ 0 === earliestPendingTime
? (root.earliestSuspendedTime = root.latestSuspendedTime = suspendedTime)
- : latestPingedTime < suspendedTime
+ : earliestPendingTime < suspendedTime
? (root.earliestSuspendedTime = suspendedTime)
: latestPendingTime > suspendedTime &&
(root.latestSuspendedTime = suspendedTime);
@@ -2021,328 +2070,10 @@
root.nextExpirationTimeToWorkOn = earliestPendingTime;
root.expirationTime = completedExpirationTime;
}
-var hasForceUpdate = !1;
-function createUpdateQueue(baseState) {
- return {
- baseState: baseState,
- firstUpdate: null,
- lastUpdate: null,
- firstCapturedUpdate: null,
- lastCapturedUpdate: null,
- firstEffect: null,
- lastEffect: null,
- firstCapturedEffect: null,
- lastCapturedEffect: null
- };
-}
-function cloneUpdateQueue(currentQueue) {
- return {
- baseState: currentQueue.baseState,
- firstUpdate: currentQueue.firstUpdate,
- lastUpdate: currentQueue.lastUpdate,
- firstCapturedUpdate: null,
- lastCapturedUpdate: null,
- firstEffect: null,
- lastEffect: null,
- firstCapturedEffect: null,
- lastCapturedEffect: null
- };
-}
-function createUpdate(expirationTime) {
- return {
- expirationTime: expirationTime,
- tag: 0,
- payload: null,
- callback: null,
- next: null,
- nextEffect: null
- };
-}
-function appendUpdateToQueue(queue, update) {
- null === queue.lastUpdate
- ? (queue.firstUpdate = queue.lastUpdate = update)
- : ((queue.lastUpdate.next = update), (queue.lastUpdate = update));
-}
-function enqueueUpdate(fiber, update) {
- var alternate = fiber.alternate;
- if (null === alternate) {
- var queue1 = fiber.updateQueue;
- var queue2 = null;
- null === queue1 &&
- (queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState));
- } else
- (queue1 = fiber.updateQueue),
- (queue2 = alternate.updateQueue),
- null === queue1
- ? null === queue2
- ? ((queue1 = fiber.updateQueue = createUpdateQueue(
- fiber.memoizedState
- )),
- (queue2 = alternate.updateQueue = createUpdateQueue(
- alternate.memoizedState
- )))
- : (queue1 = fiber.updateQueue = cloneUpdateQueue(queue2))
- : null === queue2 &&
- (queue2 = alternate.updateQueue = cloneUpdateQueue(queue1));
- null === queue2 || queue1 === queue2
- ? appendUpdateToQueue(queue1, update)
- : null === queue1.lastUpdate || null === queue2.lastUpdate
- ? (appendUpdateToQueue(queue1, update),
- appendUpdateToQueue(queue2, update))
- : (appendUpdateToQueue(queue1, update), (queue2.lastUpdate = update));
-}
-function enqueueCapturedUpdate(workInProgress, update) {
- var workInProgressQueue = workInProgress.updateQueue;
- workInProgressQueue =
- null === workInProgressQueue
- ? (workInProgress.updateQueue = createUpdateQueue(
- workInProgress.memoizedState
- ))
- : ensureWorkInProgressQueueIsAClone(workInProgress, workInProgressQueue);
- null === workInProgressQueue.lastCapturedUpdate
- ? (workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update)
- : ((workInProgressQueue.lastCapturedUpdate.next = update),
- (workInProgressQueue.lastCapturedUpdate = update));
-}
-function ensureWorkInProgressQueueIsAClone(workInProgress, queue) {
- var current = workInProgress.alternate;
- null !== current &&
- queue === current.updateQueue &&
- (queue = workInProgress.updateQueue = cloneUpdateQueue(queue));
- return queue;
-}
-function getStateFromUpdate(
- workInProgress,
- queue,
- update,
- prevState,
- nextProps,
- instance
-) {
- switch (update.tag) {
- case 1:
- return (
- (workInProgress = update.payload),
- "function" === typeof workInProgress
- ? workInProgress.call(instance, prevState, nextProps)
- : workInProgress
- );
- case 3:
- workInProgress.effectTag = (workInProgress.effectTag & -2049) | 64;
- case 0:
- workInProgress = update.payload;
- nextProps =
- "function" === typeof workInProgress
- ? workInProgress.call(instance, prevState, nextProps)
- : workInProgress;
- if (null === nextProps || void 0 === nextProps) break;
- return Object.assign({}, prevState, nextProps);
- case 2:
- hasForceUpdate = !0;
- }
- return prevState;
-}
-function processUpdateQueue(
- workInProgress,
- queue,
- props,
- instance,
- renderExpirationTime
-) {
- hasForceUpdate = !1;
- queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue);
- for (
- var newBaseState = queue.baseState,
- newFirstUpdate = null,
- newExpirationTime = 0,
- update = queue.firstUpdate,
- resultState = newBaseState;
- null !== update;
-
- ) {
- var updateExpirationTime = update.expirationTime;
- updateExpirationTime < renderExpirationTime
- ? (null === newFirstUpdate &&
- ((newFirstUpdate = update), (newBaseState = resultState)),
- newExpirationTime < updateExpirationTime &&
- (newExpirationTime = updateExpirationTime))
- : ((resultState = getStateFromUpdate(
- workInProgress,
- queue,
- update,
- resultState,
- props,
- instance
- )),
- null !== update.callback &&
- ((workInProgress.effectTag |= 32),
- (update.nextEffect = null),
- null === queue.lastEffect
- ? (queue.firstEffect = queue.lastEffect = update)
- : ((queue.lastEffect.nextEffect = update),
- (queue.lastEffect = update))));
- update = update.next;
- }
- updateExpirationTime = null;
- for (update = queue.firstCapturedUpdate; null !== update; ) {
- var _updateExpirationTime = update.expirationTime;
- _updateExpirationTime < renderExpirationTime
- ? (null === updateExpirationTime &&
- ((updateExpirationTime = update),
- null === newFirstUpdate && (newBaseState = resultState)),
- newExpirationTime < _updateExpirationTime &&
- (newExpirationTime = _updateExpirationTime))
- : ((resultState = getStateFromUpdate(
- workInProgress,
- queue,
- update,
- resultState,
- props,
- instance
- )),
- null !== update.callback &&
- ((workInProgress.effectTag |= 32),
- (update.nextEffect = null),
- null === queue.lastCapturedEffect
- ? (queue.firstCapturedEffect = queue.lastCapturedEffect = update)
- : ((queue.lastCapturedEffect.nextEffect = update),
- (queue.lastCapturedEffect = update))));
- update = update.next;
- }
- null === newFirstUpdate && (queue.lastUpdate = null);
- null === updateExpirationTime
- ? (queue.lastCapturedUpdate = null)
- : (workInProgress.effectTag |= 32);
- null === newFirstUpdate &&
- null === updateExpirationTime &&
- (newBaseState = resultState);
- queue.baseState = newBaseState;
- queue.firstUpdate = newFirstUpdate;
- queue.firstCapturedUpdate = updateExpirationTime;
- workInProgress.expirationTime = newExpirationTime;
- workInProgress.memoizedState = resultState;
-}
-function commitUpdateQueue(finishedWork, finishedQueue, instance) {
- null !== finishedQueue.firstCapturedUpdate &&
- (null !== finishedQueue.lastUpdate &&
- ((finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate),
- (finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate)),
- (finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null));
- commitUpdateEffects(finishedQueue.firstEffect, instance);
- finishedQueue.firstEffect = finishedQueue.lastEffect = null;
- commitUpdateEffects(finishedQueue.firstCapturedEffect, instance);
- finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null;
-}
-function commitUpdateEffects(effect, instance) {
- for (; null !== effect; ) {
- var _callback3 = effect.callback;
- if (null !== _callback3) {
- effect.callback = null;
- var context = instance;
- invariant(
- "function" === typeof _callback3,
- "Invalid argument passed as callback. Expected a function. Instead received: %s",
- _callback3
- );
- _callback3.call(context);
- }
- effect = effect.nextEffect;
- }
-}
-function createCapturedValue(value, source) {
- return {
- value: value,
- source: source,
- stack: getStackByFiberInDevAndProd(source)
- };
-}
-var valueCursor = { current: null },
- currentlyRenderingFiber = null,
- lastContextDependency = null,
- lastContextWithAllBitsObserved = null;
-function pushProvider(providerFiber, nextValue) {
- var context = providerFiber.type._context;
- push(valueCursor, context._currentValue, providerFiber);
- context._currentValue = nextValue;
-}
-function popProvider(providerFiber) {
- var currentValue = valueCursor.current;
- pop(valueCursor, providerFiber);
- providerFiber.type._context._currentValue = currentValue;
-}
-function prepareToReadContext(workInProgress) {
- currentlyRenderingFiber = workInProgress;
- lastContextWithAllBitsObserved = lastContextDependency = null;
- workInProgress.firstContextDependency = null;
-}
-function readContext(context, observedBits) {
- if (
- lastContextWithAllBitsObserved !== context &&
- !1 !== observedBits &&
- 0 !== observedBits
- ) {
- if ("number" !== typeof observedBits || 1073741823 === observedBits)
- (lastContextWithAllBitsObserved = context), (observedBits = 1073741823);
- observedBits = { context: context, observedBits: observedBits, next: null };
- null === lastContextDependency
- ? (invariant(
- null !== currentlyRenderingFiber,
- "Context can only be read while React is rendering, e.g. inside the render method or getDerivedStateFromProps."
- ),
- (currentlyRenderingFiber.firstContextDependency = lastContextDependency = observedBits))
- : (lastContextDependency = lastContextDependency.next = observedBits);
- }
- return context._currentValue;
-}
-var NO_CONTEXT = {},
- contextStackCursor$1 = { current: NO_CONTEXT },
- contextFiberStackCursor = { current: NO_CONTEXT },
- rootInstanceStackCursor = { current: NO_CONTEXT };
-function requiredContext(c) {
- invariant(
- c !== NO_CONTEXT,
- "Expected host context to exist. This error is likely caused by a bug in React. Please file an issue."
- );
- return c;
-}
-function pushHostContainer(fiber, nextRootInstance) {
- push(rootInstanceStackCursor, nextRootInstance, fiber);
- push(contextFiberStackCursor, fiber, fiber);
- push(contextStackCursor$1, NO_CONTEXT, fiber);
- pop(contextStackCursor$1, fiber);
- push(contextStackCursor$1, { isInAParentText: !1 }, fiber);
-}
-function popHostContainer(fiber) {
- pop(contextStackCursor$1, fiber);
- pop(contextFiberStackCursor, fiber);
- pop(rootInstanceStackCursor, fiber);
-}
-function pushHostContext(fiber) {
- requiredContext(rootInstanceStackCursor.current);
- var context = requiredContext(contextStackCursor$1.current);
- var nextContext = fiber.type;
- nextContext =
- "AndroidTextInput" === nextContext ||
- "RCTMultilineTextInputView" === nextContext ||
- "RCTSinglelineTextInputView" === nextContext ||
- "RCTText" === nextContext ||
- "RCTVirtualText" === nextContext;
- nextContext =
- context.isInAParentText !== nextContext
- ? { isInAParentText: nextContext }
- : context;
- context !== nextContext &&
- (push(contextFiberStackCursor, fiber, fiber),
- push(contextStackCursor$1, nextContext, fiber));
-}
-function popHostContext(fiber) {
- contextFiberStackCursor.current === fiber &&
- (pop(contextStackCursor$1, fiber), pop(contextFiberStackCursor, fiber));
-}
-var hasOwnProperty = Object.prototype.hasOwnProperty;
function is(x, y) {
- return x === y ? 0 !== x || 0 !== y || 1 / x === 1 / y : x !== x && y !== y;
+ return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y);
}
+var hasOwnProperty = Object.prototype.hasOwnProperty;
function shallowEqual(objA, objB) {
if (is(objA, objB)) return !0;
if (
@@ -2383,9 +2114,9 @@
case 0:
throw result;
default:
- throw ((lazyComponent._status = 0),
- (result = lazyComponent._ctor),
- (result = result()),
+ lazyComponent._status = 0;
+ result = lazyComponent._ctor;
+ result = result();
result.then(
function(moduleObject) {
0 === lazyComponent._status &&
@@ -2397,13 +2128,18 @@
0 === lazyComponent._status &&
((lazyComponent._status = 2), (lazyComponent._result = error));
}
- ),
- (lazyComponent._result = result),
- result);
+ );
+ switch (lazyComponent._status) {
+ case 1:
+ return lazyComponent._result;
+ case 2:
+ throw lazyComponent._result;
+ }
+ lazyComponent._result = result;
+ throw result;
}
}
-var ReactCurrentOwner$4 = ReactSharedInternals.ReactCurrentOwner,
- emptyRefsObject = new React.Component().refs;
+var emptyRefsObject = new React.Component().refs;
function applyDerivedStateFromProps(
workInProgress,
ctor,
@@ -2444,7 +2180,7 @@
var currentTime = requestCurrentTime();
currentTime = computeExpirationForFiber(currentTime, inst);
var update = createUpdate(currentTime);
- update.tag = 1;
+ update.tag = ReplaceState;
update.payload = payload;
void 0 !== callback && null !== callback && (update.callback = callback);
flushPassiveEffects();
@@ -2456,7 +2192,7 @@
var currentTime = requestCurrentTime();
currentTime = computeExpirationForFiber(currentTime, inst);
var update = createUpdate(currentTime);
- update.tag = 2;
+ update.tag = ForceUpdate;
void 0 !== callback && null !== callback && (update.callback = callback);
flushPassiveEffects();
enqueueUpdate(inst, update);
@@ -2484,7 +2220,7 @@
unmaskedContext = emptyContextObject;
var context = ctor.contextType;
"object" === typeof context && null !== context
- ? (context = ReactCurrentOwner$4.currentDispatcher.readContext(context))
+ ? (context = readContext(context))
: ((unmaskedContext = isContextProvider(ctor)
? previousContext
: contextStackCursor.current),
@@ -2531,9 +2267,7 @@
instance.refs = emptyRefsObject;
var contextType = ctor.contextType;
"object" === typeof contextType && null !== contextType
- ? (instance.context = ReactCurrentOwner$4.currentDispatcher.readContext(
- contextType
- ))
+ ? (instance.context = readContext(contextType))
: ((contextType = isContextProvider(ctor)
? previousContext
: contextStackCursor.current),
@@ -2588,7 +2322,10 @@
element = element._owner;
var inst = void 0;
element &&
- (invariant(1 === element.tag, "Function components cannot have refs."),
+ (invariant(
+ 1 === element.tag,
+ "Function components cannot have refs. Did you mean to use React.forwardRef()?"
+ ),
(inst = element.stateNode));
invariant(
inst,
@@ -3288,6 +3025,512 @@
}
var reconcileChildFibers = ChildReconciler(!0),
mountChildFibers = ChildReconciler(!1),
+ NO_CONTEXT = {},
+ contextStackCursor$1 = { current: NO_CONTEXT },
+ contextFiberStackCursor = { current: NO_CONTEXT },
+ rootInstanceStackCursor = { current: NO_CONTEXT };
+function requiredContext(c) {
+ invariant(
+ c !== NO_CONTEXT,
+ "Expected host context to exist. This error is likely caused by a bug in React. Please file an issue."
+ );
+ return c;
+}
+function pushHostContainer(fiber, nextRootInstance) {
+ push(rootInstanceStackCursor, nextRootInstance, fiber);
+ push(contextFiberStackCursor, fiber, fiber);
+ push(contextStackCursor$1, NO_CONTEXT, fiber);
+ pop(contextStackCursor$1, fiber);
+ push(contextStackCursor$1, { isInAParentText: !1 }, fiber);
+}
+function popHostContainer(fiber) {
+ pop(contextStackCursor$1, fiber);
+ pop(contextFiberStackCursor, fiber);
+ pop(rootInstanceStackCursor, fiber);
+}
+function pushHostContext(fiber) {
+ requiredContext(rootInstanceStackCursor.current);
+ var context = requiredContext(contextStackCursor$1.current);
+ var nextContext = fiber.type;
+ nextContext =
+ "AndroidTextInput" === nextContext ||
+ "RCTMultilineTextInputView" === nextContext ||
+ "RCTSinglelineTextInputView" === nextContext ||
+ "RCTText" === nextContext ||
+ "RCTVirtualText" === nextContext;
+ nextContext =
+ context.isInAParentText !== nextContext
+ ? { isInAParentText: nextContext }
+ : context;
+ context !== nextContext &&
+ (push(contextFiberStackCursor, fiber, fiber),
+ push(contextStackCursor$1, nextContext, fiber));
+}
+function popHostContext(fiber) {
+ contextFiberStackCursor.current === fiber &&
+ (pop(contextStackCursor$1, fiber), pop(contextFiberStackCursor, fiber));
+}
+var NoEffect$1 = 0,
+ UnmountSnapshot = 2,
+ UnmountMutation = 4,
+ MountMutation = 8,
+ UnmountLayout = 16,
+ MountLayout = 32,
+ MountPassive = 64,
+ UnmountPassive = 128,
+ ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher,
+ renderExpirationTime = 0,
+ currentlyRenderingFiber$1 = null,
+ currentHook = null,
+ nextCurrentHook = null,
+ firstWorkInProgressHook = null,
+ workInProgressHook = null,
+ nextWorkInProgressHook = null,
+ remainingExpirationTime = 0,
+ componentUpdateQueue = null,
+ sideEffectTag = 0,
+ didScheduleRenderPhaseUpdate = !1,
+ renderPhaseUpdates = null,
+ numberOfReRenders = 0;
+function throwInvalidHookError() {
+ invariant(
+ !1,
+ "Hooks can only be called inside the body of a function component. (https://fb.me/react-invalid-hook-call)"
+ );
+}
+function areHookInputsEqual(nextDeps, prevDeps) {
+ if (null === prevDeps) return !1;
+ for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++)
+ if (!is(nextDeps[i], prevDeps[i])) return !1;
+ return !0;
+}
+function renderWithHooks(
+ current,
+ workInProgress,
+ Component,
+ props,
+ refOrContext,
+ nextRenderExpirationTime
+) {
+ renderExpirationTime = nextRenderExpirationTime;
+ currentlyRenderingFiber$1 = workInProgress;
+ nextCurrentHook = null !== current ? current.memoizedState : null;
+ ReactCurrentDispatcher$1.current =
+ null === nextCurrentHook ? HooksDispatcherOnMount : HooksDispatcherOnUpdate;
+ workInProgress = Component(props, refOrContext);
+ if (didScheduleRenderPhaseUpdate) {
+ do
+ (didScheduleRenderPhaseUpdate = !1),
+ (numberOfReRenders += 1),
+ (nextCurrentHook = null !== current ? current.memoizedState : null),
+ (nextWorkInProgressHook = firstWorkInProgressHook),
+ (componentUpdateQueue = workInProgressHook = currentHook = null),
+ (ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdate),
+ (workInProgress = Component(props, refOrContext));
+ while (didScheduleRenderPhaseUpdate);
+ renderPhaseUpdates = null;
+ numberOfReRenders = 0;
+ }
+ ReactCurrentDispatcher$1.current = ContextOnlyDispatcher;
+ current = currentlyRenderingFiber$1;
+ current.memoizedState = firstWorkInProgressHook;
+ current.expirationTime = remainingExpirationTime;
+ current.updateQueue = componentUpdateQueue;
+ current.effectTag |= sideEffectTag;
+ current = null !== currentHook && null !== currentHook.next;
+ renderExpirationTime = 0;
+ nextWorkInProgressHook = workInProgressHook = firstWorkInProgressHook = nextCurrentHook = currentHook = currentlyRenderingFiber$1 = null;
+ remainingExpirationTime = 0;
+ componentUpdateQueue = null;
+ sideEffectTag = 0;
+ invariant(
+ !current,
+ "Rendered fewer hooks than expected. This may be caused by an accidental early return statement."
+ );
+ return workInProgress;
+}
+function resetHooks() {
+ ReactCurrentDispatcher$1.current = ContextOnlyDispatcher;
+ renderExpirationTime = 0;
+ nextWorkInProgressHook = workInProgressHook = firstWorkInProgressHook = nextCurrentHook = currentHook = currentlyRenderingFiber$1 = null;
+ remainingExpirationTime = 0;
+ componentUpdateQueue = null;
+ sideEffectTag = 0;
+ didScheduleRenderPhaseUpdate = !1;
+ renderPhaseUpdates = null;
+ numberOfReRenders = 0;
+}
+function mountWorkInProgressHook() {
+ var hook = {
+ memoizedState: null,
+ baseState: null,
+ queue: null,
+ baseUpdate: null,
+ next: null
+ };
+ null === workInProgressHook
+ ? (firstWorkInProgressHook = workInProgressHook = hook)
+ : (workInProgressHook = workInProgressHook.next = hook);
+ return workInProgressHook;
+}
+function updateWorkInProgressHook() {
+ if (null !== nextWorkInProgressHook)
+ (workInProgressHook = nextWorkInProgressHook),
+ (nextWorkInProgressHook = workInProgressHook.next),
+ (currentHook = nextCurrentHook),
+ (nextCurrentHook = null !== currentHook ? currentHook.next : null);
+ else {
+ invariant(
+ null !== nextCurrentHook,
+ "Rendered more hooks than during the previous render."
+ );
+ currentHook = nextCurrentHook;
+ var newHook = {
+ memoizedState: currentHook.memoizedState,
+ baseState: currentHook.baseState,
+ queue: currentHook.queue,
+ baseUpdate: currentHook.baseUpdate,
+ next: null
+ };
+ workInProgressHook =
+ null === workInProgressHook
+ ? (firstWorkInProgressHook = newHook)
+ : (workInProgressHook.next = newHook);
+ nextCurrentHook = currentHook.next;
+ }
+ return workInProgressHook;
+}
+function basicStateReducer(state, action) {
+ return "function" === typeof action ? action(state) : action;
+}
+function updateReducer(reducer) {
+ var hook = updateWorkInProgressHook(),
+ queue = hook.queue;
+ invariant(
+ null !== queue,
+ "Should have a queue. This is likely a bug in React. Please file an issue."
+ );
+ if (0 < numberOfReRenders) {
+ var _dispatch = queue.dispatch;
+ if (null !== renderPhaseUpdates) {
+ var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+ if (void 0 !== firstRenderPhaseUpdate) {
+ renderPhaseUpdates.delete(queue);
+ var newState = hook.memoizedState;
+ do
+ (newState = reducer(newState, firstRenderPhaseUpdate.action)),
+ (firstRenderPhaseUpdate = firstRenderPhaseUpdate.next);
+ while (null !== firstRenderPhaseUpdate);
+ 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];
+ }
+ }
+ return [hook.memoizedState, _dispatch];
+ }
+ _dispatch = queue.last;
+ var baseUpdate = hook.baseUpdate;
+ newState = hook.baseState;
+ null !== baseUpdate
+ ? (null !== _dispatch && (_dispatch.next = null),
+ (_dispatch = baseUpdate.next))
+ : (_dispatch = null !== _dispatch ? _dispatch.next : null);
+ if (null !== _dispatch) {
+ var newBaseUpdate = (firstRenderPhaseUpdate = null),
+ _update = _dispatch,
+ didSkip = !1;
+ do {
+ var updateExpirationTime = _update.expirationTime;
+ updateExpirationTime < renderExpirationTime
+ ? (didSkip ||
+ ((didSkip = !0),
+ (newBaseUpdate = baseUpdate),
+ (firstRenderPhaseUpdate = newState)),
+ updateExpirationTime > remainingExpirationTime &&
+ (remainingExpirationTime = updateExpirationTime))
+ : (newState =
+ _update.eagerReducer === reducer
+ ? _update.eagerState
+ : reducer(newState, _update.action));
+ baseUpdate = _update;
+ _update = _update.next;
+ } while (null !== _update && _update !== _dispatch);
+ didSkip ||
+ ((newBaseUpdate = baseUpdate), (firstRenderPhaseUpdate = newState));
+ is(newState, hook.memoizedState) || (didReceiveUpdate = !0);
+ hook.memoizedState = newState;
+ hook.baseUpdate = newBaseUpdate;
+ hook.baseState = firstRenderPhaseUpdate;
+ queue.eagerReducer = reducer;
+ queue.eagerState = newState;
+ }
+ return [hook.memoizedState, queue.dispatch];
+}
+function pushEffect(tag, create, destroy, deps) {
+ tag = { tag: tag, create: create, destroy: destroy, deps: deps, next: null };
+ null === componentUpdateQueue
+ ? ((componentUpdateQueue = { lastEffect: null }),
+ (componentUpdateQueue.lastEffect = tag.next = tag))
+ : ((create = componentUpdateQueue.lastEffect),
+ null === create
+ ? (componentUpdateQueue.lastEffect = tag.next = tag)
+ : ((destroy = create.next),
+ (create.next = tag),
+ (tag.next = destroy),
+ (componentUpdateQueue.lastEffect = tag)));
+ return tag;
+}
+function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) {
+ var hook = mountWorkInProgressHook();
+ sideEffectTag |= fiberEffectTag;
+ hook.memoizedState = pushEffect(
+ hookEffectTag,
+ create,
+ void 0,
+ void 0 === deps ? null : deps
+ );
+}
+function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) {
+ var hook = updateWorkInProgressHook();
+ deps = void 0 === deps ? null : deps;
+ var destroy = void 0;
+ if (null !== currentHook) {
+ var prevEffect = currentHook.memoizedState;
+ destroy = prevEffect.destroy;
+ if (null !== deps && areHookInputsEqual(deps, prevEffect.deps)) {
+ pushEffect(NoEffect$1, create, destroy, deps);
+ return;
+ }
+ }
+ sideEffectTag |= fiberEffectTag;
+ hook.memoizedState = pushEffect(hookEffectTag, create, destroy, deps);
+}
+function imperativeHandleEffect(create, ref) {
+ if ("function" === typeof ref)
+ return (
+ (create = create()),
+ ref(create),
+ function() {
+ ref(null);
+ }
+ );
+ if (null !== ref && void 0 !== ref)
+ return (
+ (create = create()),
+ (ref.current = create),
+ function() {
+ ref.current = null;
+ }
+ );
+}
+function mountDebugValue() {}
+function dispatchAction(fiber, queue, action) {
+ invariant(
+ 25 > numberOfReRenders,
+ "Too many re-renders. React limits the number of renders to prevent an infinite loop."
+ );
+ var alternate = fiber.alternate;
+ if (
+ fiber === currentlyRenderingFiber$1 ||
+ (null !== alternate && alternate === currentlyRenderingFiber$1)
+ )
+ if (
+ ((didScheduleRenderPhaseUpdate = !0),
+ (fiber = {
+ expirationTime: renderExpirationTime,
+ action: action,
+ eagerReducer: null,
+ eagerState: null,
+ next: null
+ }),
+ null === renderPhaseUpdates && (renderPhaseUpdates = new Map()),
+ (action = renderPhaseUpdates.get(queue)),
+ void 0 === action)
+ )
+ renderPhaseUpdates.set(queue, fiber);
+ else {
+ for (queue = action; null !== queue.next; ) queue = queue.next;
+ queue.next = fiber;
+ }
+ else {
+ flushPassiveEffects();
+ var currentTime = requestCurrentTime();
+ currentTime = computeExpirationForFiber(currentTime, fiber);
+ var _update2 = {
+ expirationTime: currentTime,
+ action: action,
+ eagerReducer: null,
+ eagerState: null,
+ next: null
+ },
+ _last = queue.last;
+ if (null === _last) _update2.next = _update2;
+ else {
+ var first = _last.next;
+ null !== first && (_update2.next = first);
+ _last.next = _update2;
+ }
+ queue.last = _update2;
+ if (
+ 0 === fiber.expirationTime &&
+ (null === alternate || 0 === alternate.expirationTime) &&
+ ((alternate = queue.eagerReducer), null !== alternate)
+ )
+ try {
+ var currentState = queue.eagerState,
+ _eagerState = alternate(currentState, action);
+ _update2.eagerReducer = alternate;
+ _update2.eagerState = _eagerState;
+ if (is(_eagerState, currentState)) return;
+ } catch (error) {
+ } finally {
+ }
+ scheduleWork(fiber, currentTime);
+ }
+}
+var ContextOnlyDispatcher = {
+ readContext: readContext,
+ useCallback: throwInvalidHookError,
+ useContext: throwInvalidHookError,
+ useEffect: throwInvalidHookError,
+ useImperativeHandle: throwInvalidHookError,
+ useLayoutEffect: throwInvalidHookError,
+ useMemo: throwInvalidHookError,
+ useReducer: throwInvalidHookError,
+ useRef: throwInvalidHookError,
+ useState: throwInvalidHookError,
+ useDebugValue: throwInvalidHookError
+ },
+ HooksDispatcherOnMount = {
+ readContext: readContext,
+ useCallback: function(callback, deps) {
+ mountWorkInProgressHook().memoizedState = [
+ callback,
+ void 0 === deps ? null : deps
+ ];
+ return callback;
+ },
+ useContext: readContext,
+ useEffect: function(create, deps) {
+ return mountEffectImpl(516, UnmountPassive | MountPassive, create, deps);
+ },
+ useImperativeHandle: function(ref, create, deps) {
+ deps = null !== deps && void 0 !== deps ? deps.concat([ref]) : null;
+ return mountEffectImpl(
+ 4,
+ UnmountMutation | MountLayout,
+ imperativeHandleEffect.bind(null, create, ref),
+ deps
+ );
+ },
+ useLayoutEffect: function(create, deps) {
+ return mountEffectImpl(4, UnmountMutation | MountLayout, create, deps);
+ },
+ useMemo: function(nextCreate, deps) {
+ var hook = mountWorkInProgressHook();
+ deps = void 0 === deps ? null : deps;
+ nextCreate = nextCreate();
+ hook.memoizedState = [nextCreate, deps];
+ return nextCreate;
+ },
+ useReducer: function(reducer, initialArg, init) {
+ var hook = mountWorkInProgressHook();
+ initialArg = void 0 !== init ? init(initialArg) : initialArg;
+ hook.memoizedState = hook.baseState = initialArg;
+ reducer = hook.queue = {
+ last: null,
+ dispatch: null,
+ eagerReducer: reducer,
+ eagerState: initialArg
+ };
+ reducer = reducer.dispatch = dispatchAction.bind(
+ null,
+ currentlyRenderingFiber$1,
+ reducer
+ );
+ return [hook.memoizedState, reducer];
+ },
+ useRef: function(initialValue) {
+ var hook = mountWorkInProgressHook();
+ initialValue = { current: initialValue };
+ return (hook.memoizedState = initialValue);
+ },
+ useState: function(initialState) {
+ var hook = mountWorkInProgressHook();
+ "function" === typeof initialState && (initialState = initialState());
+ hook.memoizedState = hook.baseState = initialState;
+ initialState = hook.queue = {
+ last: null,
+ dispatch: null,
+ eagerReducer: basicStateReducer,
+ eagerState: initialState
+ };
+ initialState = initialState.dispatch = dispatchAction.bind(
+ null,
+ currentlyRenderingFiber$1,
+ initialState
+ );
+ return [hook.memoizedState, initialState];
+ },
+ useDebugValue: mountDebugValue
+ },
+ HooksDispatcherOnUpdate = {
+ readContext: readContext,
+ useCallback: function(callback, deps) {
+ var hook = updateWorkInProgressHook();
+ deps = void 0 === deps ? null : deps;
+ var prevState = hook.memoizedState;
+ if (
+ null !== prevState &&
+ null !== deps &&
+ areHookInputsEqual(deps, prevState[1])
+ )
+ return prevState[0];
+ hook.memoizedState = [callback, deps];
+ return callback;
+ },
+ useContext: readContext,
+ useEffect: function(create, deps) {
+ return updateEffectImpl(516, UnmountPassive | MountPassive, create, deps);
+ },
+ useImperativeHandle: function(ref, create, deps) {
+ deps = null !== deps && void 0 !== deps ? deps.concat([ref]) : null;
+ return updateEffectImpl(
+ 4,
+ UnmountMutation | MountLayout,
+ imperativeHandleEffect.bind(null, create, ref),
+ deps
+ );
+ },
+ useLayoutEffect: function(create, deps) {
+ return updateEffectImpl(4, UnmountMutation | MountLayout, create, deps);
+ },
+ useMemo: function(nextCreate, deps) {
+ var hook = updateWorkInProgressHook();
+ deps = void 0 === deps ? null : deps;
+ var prevState = hook.memoizedState;
+ if (
+ null !== prevState &&
+ null !== deps &&
+ areHookInputsEqual(deps, prevState[1])
+ )
+ return prevState[0];
+ nextCreate = nextCreate();
+ hook.memoizedState = [nextCreate, deps];
+ return nextCreate;
+ },
+ useReducer: updateReducer,
+ useRef: function() {
+ return updateWorkInProgressHook().memoizedState;
+ },
+ useState: function(initialState) {
+ return updateReducer(basicStateReducer, initialState);
+ },
+ useDebugValue: mountDebugValue
+ },
hydrationParentFiber = null,
nextHydratableInstance = null,
isHydrating = !1;
@@ -3303,6 +3546,8 @@
(nextInstance = shim$1(nextInstance, fiber.pendingProps)),
null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1
);
+ case 13:
+ return !1;
default:
return !1;
}
@@ -3340,7 +3585,8 @@
(hydrationParentFiber = fiber$jscomp$0);
}
}
-var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner;
+var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner,
+ didReceiveUpdate = !1;
function reconcileChildren(
current$$1,
workInProgress,
@@ -3372,7 +3618,26 @@
Component = Component.render;
var ref = workInProgress.ref;
prepareToReadContext(workInProgress, renderExpirationTime);
- nextProps = Component(nextProps, ref);
+ nextProps = renderWithHooks(
+ current$$1,
+ workInProgress,
+ Component,
+ nextProps,
+ ref,
+ renderExpirationTime
+ );
+ if (null !== current$$1 && !didReceiveUpdate)
+ return (
+ (workInProgress.updateQueue = current$$1.updateQueue),
+ (workInProgress.effectTag &= -517),
+ current$$1.expirationTime <= renderExpirationTime &&
+ (current$$1.expirationTime = 0),
+ bailoutOnAlreadyFinishedWork(
+ current$$1,
+ workInProgress,
+ renderExpirationTime
+ )
+ );
workInProgress.effectTag |= 1;
reconcileChildren(
current$$1,
@@ -3452,9 +3717,9 @@
renderExpirationTime
) {
return null !== current$$1 &&
- updateExpirationTime < renderExpirationTime &&
shallowEqual(current$$1.memoizedProps, nextProps) &&
- current$$1.ref === workInProgress.ref
+ current$$1.ref === workInProgress.ref &&
+ ((didReceiveUpdate = !1), updateExpirationTime < renderExpirationTime)
? bailoutOnAlreadyFinishedWork(
current$$1,
workInProgress,
@@ -3488,7 +3753,26 @@
: contextStackCursor.current;
unmaskedContext = getMaskedContext(workInProgress, unmaskedContext);
prepareToReadContext(workInProgress, renderExpirationTime);
- Component = Component(nextProps, unmaskedContext);
+ Component = renderWithHooks(
+ current$$1,
+ workInProgress,
+ Component,
+ nextProps,
+ unmaskedContext,
+ renderExpirationTime
+ );
+ if (null !== current$$1 && !didReceiveUpdate)
+ return (
+ (workInProgress.updateQueue = current$$1.updateQueue),
+ (workInProgress.effectTag &= -517),
+ current$$1.expirationTime <= renderExpirationTime &&
+ (current$$1.expirationTime = 0),
+ bailoutOnAlreadyFinishedWork(
+ current$$1,
+ workInProgress,
+ renderExpirationTime
+ )
+ );
workInProgress.effectTag |= 1;
reconcileChildren(
current$$1,
@@ -3535,9 +3819,7 @@
var oldContext = instance.context,
contextType = Component.contextType;
"object" === typeof contextType && null !== contextType
- ? (contextType = ReactCurrentOwner$4.currentDispatcher.readContext(
- contextType
- ))
+ ? (contextType = readContext(contextType))
: ((contextType = isContextProvider(Component)
? previousContext
: contextStackCursor.current),
@@ -3622,9 +3904,7 @@
(oldContext = instance.context),
(contextType = Component.contextType),
"object" === typeof contextType && null !== contextType
- ? (contextType = ReactCurrentOwner$4.currentDispatcher.readContext(
- contextType
- ))
+ ? (contextType = readContext(contextType))
: ((contextType = isContextProvider(Component)
? previousContext
: contextStackCursor.current),
@@ -3805,33 +4085,35 @@
(nextState = { timedOutAt: null !== nextState ? nextState.timedOutAt : 0 }),
(nextDidTimeout = !0),
(workInProgress.effectTag &= -65);
- null === current$$1
- ? nextDidTimeout
- ? ((nextDidTimeout = nextProps.fallback),
- (nextProps = createFiberFromFragment(null, mode, 0, null)),
+ if (null === current$$1)
+ if (nextDidTimeout) {
+ var nextFallbackChildren = nextProps.fallback;
+ current$$1 = createFiberFromFragment(null, mode, 0, null);
0 === (workInProgress.mode & 1) &&
- (nextProps.child =
+ (current$$1.child =
null !== workInProgress.memoizedState
? workInProgress.child.child
- : workInProgress.child),
- (mode = createFiberFromFragment(
- nextDidTimeout,
+ : workInProgress.child);
+ mode = createFiberFromFragment(
+ nextFallbackChildren,
mode,
renderExpirationTime,
null
- )),
- (nextProps.sibling = mode),
- (renderExpirationTime = nextProps),
- (renderExpirationTime.return = mode.return = workInProgress))
- : (renderExpirationTime = mode = mountChildFibers(
+ );
+ current$$1.sibling = mode;
+ renderExpirationTime = current$$1;
+ renderExpirationTime.return = mode.return = workInProgress;
+ } else
+ renderExpirationTime = mode = mountChildFibers(
workInProgress,
null,
nextProps.children,
renderExpirationTime
- ))
- : null !== current$$1.memoizedState
+ );
+ else
+ null !== current$$1.memoizedState
? ((mode = current$$1.child),
- (current$$1 = mode.sibling),
+ (nextFallbackChildren = mode.sibling),
nextDidTimeout
? ((renderExpirationTime = nextProps.fallback),
(nextProps = createWorkInProgress(mode, mode.pendingProps, 0)),
@@ -3843,9 +4125,9 @@
nextDidTimeout !== mode.child &&
(nextProps.child = nextDidTimeout)),
(mode = nextProps.sibling = createWorkInProgress(
- current$$1,
+ nextFallbackChildren,
renderExpirationTime,
- current$$1.expirationTime
+ nextFallbackChildren.expirationTime
)),
(renderExpirationTime = nextProps),
(nextProps.childExpirationTime = 0),
@@ -3856,11 +4138,11 @@
nextProps.children,
renderExpirationTime
)))
- : ((current$$1 = current$$1.child),
+ : ((nextFallbackChildren = current$$1.child),
nextDidTimeout
? ((nextDidTimeout = nextProps.fallback),
(nextProps = createFiberFromFragment(null, mode, 0, null)),
- (nextProps.child = current$$1),
+ (nextProps.child = nextFallbackChildren),
0 === (workInProgress.mode & 1) &&
(nextProps.child =
null !== workInProgress.memoizedState
@@ -3878,10 +4160,11 @@
(renderExpirationTime.return = mode.return = workInProgress))
: (mode = renderExpirationTime = reconcileChildFibers(
workInProgress,
- current$$1,
+ nextFallbackChildren,
nextProps.children,
renderExpirationTime
- )));
+ ))),
+ (workInProgress.stateNode = current$$1.stateNode);
workInProgress.memoizedState = nextState;
workInProgress.child = renderExpirationTime;
return mode;
@@ -3892,7 +4175,7 @@
renderExpirationTime
) {
null !== current$$1 &&
- (workInProgress.firstContextDependency = current$$1.firstContextDependency);
+ (workInProgress.contextDependencies = current$$1.contextDependencies);
if (workInProgress.childExpirationTime < renderExpirationTime) return null;
invariant(
null === current$$1 || workInProgress.child === current$$1.child,
@@ -3924,12 +4207,15 @@
}
function beginWork(current$$1, workInProgress, renderExpirationTime) {
var updateExpirationTime = workInProgress.expirationTime;
+ if (null !== current$$1)
if (
- null !== current$$1 &&
- current$$1.memoizedProps === workInProgress.pendingProps &&
- !didPerformWorkStackCursor.current &&
- updateExpirationTime < renderExpirationTime
- ) {
+ current$$1.memoizedProps !== workInProgress.pendingProps ||
+ didPerformWorkStackCursor.current
+ )
+ didReceiveUpdate = !0;
+ else {
+ if (updateExpirationTime < renderExpirationTime) {
+ didReceiveUpdate = !1;
switch (workInProgress.tag) {
case 3:
pushHostRootContext(workInProgress);
@@ -3976,6 +4262,8 @@
renderExpirationTime
);
}
+ }
+ else didReceiveUpdate = !1;
workInProgress.expirationTime = 0;
switch (workInProgress.tag) {
case 2:
@@ -3990,7 +4278,14 @@
contextStackCursor.current
);
prepareToReadContext(workInProgress, renderExpirationTime);
- context = updateExpirationTime(current$$1, context);
+ context = renderWithHooks(
+ null,
+ workInProgress,
+ updateExpirationTime,
+ current$$1,
+ context,
+ renderExpirationTime
+ );
workInProgress.effectTag |= 1;
if (
"object" === typeof context &&
@@ -3999,6 +4294,7 @@
void 0 === context.$$typeof
) {
workInProgress.tag = 1;
+ resetHooks();
if (isContextProvider(updateExpirationTime)) {
var hasContext = !0;
pushContextProvider(workInProgress);
@@ -4270,13 +4566,9 @@
pushProvider(workInProgress, hasContext);
if (null !== getDerivedStateFromProps) {
var oldValue = getDerivedStateFromProps.value;
- hasContext =
- (oldValue === hasContext &&
- (0 !== oldValue || 1 / oldValue === 1 / hasContext)) ||
- (oldValue !== oldValue && hasContext !== hasContext)
+ hasContext = is(oldValue, hasContext)
? 0
- : ("function" ===
- typeof updateExpirationTime._calculateChangedBits
+ : ("function" === typeof updateExpirationTime._calculateChangedBits
? updateExpirationTime._calculateChangedBits(
oldValue,
hasContext
@@ -4296,83 +4588,79 @@
}
} else
for (
- getDerivedStateFromProps = workInProgress.child,
- null !== getDerivedStateFromProps &&
- (getDerivedStateFromProps.return = workInProgress);
- null !== getDerivedStateFromProps;
+ oldValue = workInProgress.child,
+ null !== oldValue && (oldValue.return = workInProgress);
+ null !== oldValue;
) {
- oldValue = getDerivedStateFromProps.firstContextDependency;
- if (null !== oldValue) {
- do {
+ var list = oldValue.contextDependencies;
+ if (null !== list) {
+ getDerivedStateFromProps = oldValue.child;
+ for (var dependency = list.first; null !== dependency; ) {
if (
- oldValue.context === updateExpirationTime &&
- 0 !== (oldValue.observedBits & hasContext)
- ) {
- if (1 === getDerivedStateFromProps.tag) {
- var nextFiber = createUpdate(renderExpirationTime);
- nextFiber.tag = 2;
- enqueueUpdate(getDerivedStateFromProps, nextFiber);
- }
- getDerivedStateFromProps.expirationTime <
- renderExpirationTime &&
- (getDerivedStateFromProps.expirationTime = renderExpirationTime);
- nextFiber = getDerivedStateFromProps.alternate;
- null !== nextFiber &&
- nextFiber.expirationTime < renderExpirationTime &&
- (nextFiber.expirationTime = renderExpirationTime);
- for (
- var node = getDerivedStateFromProps.return;
- null !== node;
-
+ dependency.context === updateExpirationTime &&
+ 0 !== (dependency.observedBits & hasContext)
) {
- nextFiber = node.alternate;
- if (node.childExpirationTime < renderExpirationTime)
- (node.childExpirationTime = renderExpirationTime),
- null !== nextFiber &&
- nextFiber.childExpirationTime <
- renderExpirationTime &&
- (nextFiber.childExpirationTime = renderExpirationTime);
+ 1 === oldValue.tag &&
+ ((dependency = createUpdate(renderExpirationTime)),
+ (dependency.tag = ForceUpdate),
+ enqueueUpdate(oldValue, dependency));
+ oldValue.expirationTime < renderExpirationTime &&
+ (oldValue.expirationTime = renderExpirationTime);
+ dependency = oldValue.alternate;
+ null !== dependency &&
+ dependency.expirationTime < renderExpirationTime &&
+ (dependency.expirationTime = renderExpirationTime);
+ dependency = renderExpirationTime;
+ for (var node = oldValue.return; null !== node; ) {
+ var alternate = node.alternate;
+ if (node.childExpirationTime < dependency)
+ (node.childExpirationTime = dependency),
+ null !== alternate &&
+ alternate.childExpirationTime < dependency &&
+ (alternate.childExpirationTime = dependency);
else if (
- null !== nextFiber &&
- nextFiber.childExpirationTime < renderExpirationTime
+ null !== alternate &&
+ alternate.childExpirationTime < dependency
)
- nextFiber.childExpirationTime = renderExpirationTime;
+ alternate.childExpirationTime = dependency;
else break;
node = node.return;
}
+ list.expirationTime < renderExpirationTime &&
+ (list.expirationTime = renderExpirationTime);
+ break;
+ }
+ dependency = dependency.next;
}
- nextFiber = getDerivedStateFromProps.child;
- oldValue = oldValue.next;
- } while (null !== oldValue);
} else
- nextFiber =
- 10 === getDerivedStateFromProps.tag
- ? getDerivedStateFromProps.type === workInProgress.type
+ getDerivedStateFromProps =
+ 10 === oldValue.tag
+ ? oldValue.type === workInProgress.type
? null
- : getDerivedStateFromProps.child
- : getDerivedStateFromProps.child;
- if (null !== nextFiber)
- nextFiber.return = getDerivedStateFromProps;
+ : oldValue.child
+ : oldValue.child;
+ if (null !== getDerivedStateFromProps)
+ getDerivedStateFromProps.return = oldValue;
else
for (
- nextFiber = getDerivedStateFromProps;
- null !== nextFiber;
+ getDerivedStateFromProps = oldValue;
+ null !== getDerivedStateFromProps;
) {
- if (nextFiber === workInProgress) {
- nextFiber = null;
+ if (getDerivedStateFromProps === workInProgress) {
+ getDerivedStateFromProps = null;
break;
}
- getDerivedStateFromProps = nextFiber.sibling;
- if (null !== getDerivedStateFromProps) {
- getDerivedStateFromProps.return = nextFiber.return;
- nextFiber = getDerivedStateFromProps;
+ oldValue = getDerivedStateFromProps.sibling;
+ if (null !== oldValue) {
+ oldValue.return = getDerivedStateFromProps.return;
+ getDerivedStateFromProps = oldValue;
break;
}
- nextFiber = nextFiber.return;
+ getDerivedStateFromProps = getDerivedStateFromProps.return;
}
- getDerivedStateFromProps = nextFiber;
+ oldValue = getDerivedStateFromProps;
}
}
reconcileChildren(
@@ -4465,12 +4753,296 @@
renderExpirationTime
)
);
- default:
+ }
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,
+ lastContextDependency = null,
+ lastContextWithAllBitsObserved = null;
+function pushProvider(providerFiber, nextValue) {
+ var context = providerFiber.type._context;
+ push(valueCursor, context._currentValue, providerFiber);
+ context._currentValue = nextValue;
+}
+function popProvider(providerFiber) {
+ var currentValue = valueCursor.current;
+ pop(valueCursor, providerFiber);
+ providerFiber.type._context._currentValue = currentValue;
+}
+function prepareToReadContext(workInProgress, renderExpirationTime) {
+ currentlyRenderingFiber = workInProgress;
+ lastContextWithAllBitsObserved = lastContextDependency = null;
+ var currentDependencies = workInProgress.contextDependencies;
+ null !== currentDependencies &&
+ currentDependencies.expirationTime >= renderExpirationTime &&
+ (didReceiveUpdate = !0);
+ workInProgress.contextDependencies = null;
+}
+function readContext(context, observedBits) {
+ if (
+ lastContextWithAllBitsObserved !== context &&
+ !1 !== observedBits &&
+ 0 !== observedBits
+ ) {
+ if ("number" !== typeof observedBits || 1073741823 === observedBits)
+ (lastContextWithAllBitsObserved = context), (observedBits = 1073741823);
+ observedBits = { context: context, observedBits: observedBits, next: null };
+ null === lastContextDependency
+ ? (invariant(
+ null !== currentlyRenderingFiber,
+ "Context can only be read while React is rendering. In classes, you can read it in the render method or getDerivedStateFromProps. In function components, you can read it directly in the function body, but not inside Hooks like useReducer() or useMemo()."
+ ),
+ (lastContextDependency = observedBits),
+ (currentlyRenderingFiber.contextDependencies = {
+ first: observedBits,
+ expirationTime: 0
+ }))
+ : (lastContextDependency = lastContextDependency.next = observedBits);
+ }
+ return context._currentValue;
+}
+var UpdateState = 0,
+ ReplaceState = 1,
+ ForceUpdate = 2,
+ CaptureUpdate = 3,
+ hasForceUpdate = !1;
+function createUpdateQueue(baseState) {
+ return {
+ baseState: baseState,
+ firstUpdate: null,
+ lastUpdate: null,
+ firstCapturedUpdate: null,
+ lastCapturedUpdate: null,
+ firstEffect: null,
+ lastEffect: null,
+ firstCapturedEffect: null,
+ lastCapturedEffect: null
+ };
+}
+function cloneUpdateQueue(currentQueue) {
+ return {
+ baseState: currentQueue.baseState,
+ firstUpdate: currentQueue.firstUpdate,
+ lastUpdate: currentQueue.lastUpdate,
+ firstCapturedUpdate: null,
+ lastCapturedUpdate: null,
+ firstEffect: null,
+ lastEffect: null,
+ firstCapturedEffect: null,
+ lastCapturedEffect: null
+ };
+}
+function createUpdate(expirationTime) {
+ return {
+ expirationTime: expirationTime,
+ tag: UpdateState,
+ payload: null,
+ callback: null,
+ next: null,
+ nextEffect: null
+ };
+}
+function appendUpdateToQueue(queue, update) {
+ null === queue.lastUpdate
+ ? (queue.firstUpdate = queue.lastUpdate = update)
+ : ((queue.lastUpdate.next = update), (queue.lastUpdate = update));
+}
+function enqueueUpdate(fiber, update) {
+ var alternate = fiber.alternate;
+ if (null === alternate) {
+ var queue1 = fiber.updateQueue;
+ var queue2 = null;
+ null === queue1 &&
+ (queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState));
+ } else
+ (queue1 = fiber.updateQueue),
+ (queue2 = alternate.updateQueue),
+ null === queue1
+ ? null === queue2
+ ? ((queue1 = fiber.updateQueue = createUpdateQueue(
+ fiber.memoizedState
+ )),
+ (queue2 = alternate.updateQueue = createUpdateQueue(
+ alternate.memoizedState
+ )))
+ : (queue1 = fiber.updateQueue = cloneUpdateQueue(queue2))
+ : null === queue2 &&
+ (queue2 = alternate.updateQueue = cloneUpdateQueue(queue1));
+ null === queue2 || queue1 === queue2
+ ? appendUpdateToQueue(queue1, update)
+ : null === queue1.lastUpdate || null === queue2.lastUpdate
+ ? (appendUpdateToQueue(queue1, update),
+ appendUpdateToQueue(queue2, update))
+ : (appendUpdateToQueue(queue1, update), (queue2.lastUpdate = update));
+}
+function enqueueCapturedUpdate(workInProgress, update) {
+ var workInProgressQueue = workInProgress.updateQueue;
+ workInProgressQueue =
+ null === workInProgressQueue
+ ? (workInProgress.updateQueue = createUpdateQueue(
+ workInProgress.memoizedState
+ ))
+ : ensureWorkInProgressQueueIsAClone(workInProgress, workInProgressQueue);
+ null === workInProgressQueue.lastCapturedUpdate
+ ? (workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update)
+ : ((workInProgressQueue.lastCapturedUpdate.next = update),
+ (workInProgressQueue.lastCapturedUpdate = update));
+}
+function ensureWorkInProgressQueueIsAClone(workInProgress, queue) {
+ var current = workInProgress.alternate;
+ null !== current &&
+ queue === current.updateQueue &&
+ (queue = workInProgress.updateQueue = cloneUpdateQueue(queue));
+ return queue;
+}
+function getStateFromUpdate(
+ workInProgress,
+ queue,
+ update,
+ prevState,
+ nextProps,
+ instance
+) {
+ switch (update.tag) {
+ case ReplaceState:
+ return (
+ (workInProgress = update.payload),
+ "function" === typeof workInProgress
+ ? workInProgress.call(instance, prevState, nextProps)
+ : workInProgress
+ );
+ case CaptureUpdate:
+ workInProgress.effectTag = (workInProgress.effectTag & -2049) | 64;
+ case UpdateState:
+ workInProgress = update.payload;
+ nextProps =
+ "function" === typeof workInProgress
+ ? workInProgress.call(instance, prevState, nextProps)
+ : workInProgress;
+ if (null === nextProps || void 0 === nextProps) break;
+ return Object.assign({}, prevState, nextProps);
+ case ForceUpdate:
+ hasForceUpdate = !0;
}
+ return prevState;
+}
+function processUpdateQueue(
+ workInProgress,
+ queue,
+ props,
+ instance,
+ renderExpirationTime
+) {
+ hasForceUpdate = !1;
+ queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue);
+ for (
+ var newBaseState = queue.baseState,
+ newFirstUpdate = null,
+ newExpirationTime = 0,
+ update = queue.firstUpdate,
+ resultState = newBaseState;
+ null !== update;
+
+ ) {
+ var updateExpirationTime = update.expirationTime;
+ updateExpirationTime < renderExpirationTime
+ ? (null === newFirstUpdate &&
+ ((newFirstUpdate = update), (newBaseState = resultState)),
+ newExpirationTime < updateExpirationTime &&
+ (newExpirationTime = updateExpirationTime))
+ : ((resultState = getStateFromUpdate(
+ workInProgress,
+ queue,
+ update,
+ resultState,
+ props,
+ instance
+ )),
+ null !== update.callback &&
+ ((workInProgress.effectTag |= 32),
+ (update.nextEffect = null),
+ null === queue.lastEffect
+ ? (queue.firstEffect = queue.lastEffect = update)
+ : ((queue.lastEffect.nextEffect = update),
+ (queue.lastEffect = update))));
+ update = update.next;
+ }
+ updateExpirationTime = null;
+ for (update = queue.firstCapturedUpdate; null !== update; ) {
+ var _updateExpirationTime = update.expirationTime;
+ _updateExpirationTime < renderExpirationTime
+ ? (null === updateExpirationTime &&
+ ((updateExpirationTime = update),
+ null === newFirstUpdate && (newBaseState = resultState)),
+ newExpirationTime < _updateExpirationTime &&
+ (newExpirationTime = _updateExpirationTime))
+ : ((resultState = getStateFromUpdate(
+ workInProgress,
+ queue,
+ update,
+ resultState,
+ props,
+ instance
+ )),
+ null !== update.callback &&
+ ((workInProgress.effectTag |= 32),
+ (update.nextEffect = null),
+ null === queue.lastCapturedEffect
+ ? (queue.firstCapturedEffect = queue.lastCapturedEffect = update)
+ : ((queue.lastCapturedEffect.nextEffect = update),
+ (queue.lastCapturedEffect = update))));
+ update = update.next;
+ }
+ null === newFirstUpdate && (queue.lastUpdate = null);
+ null === updateExpirationTime
+ ? (queue.lastCapturedUpdate = null)
+ : (workInProgress.effectTag |= 32);
+ null === newFirstUpdate &&
+ null === updateExpirationTime &&
+ (newBaseState = resultState);
+ queue.baseState = newBaseState;
+ queue.firstUpdate = newFirstUpdate;
+ queue.firstCapturedUpdate = updateExpirationTime;
+ workInProgress.expirationTime = newExpirationTime;
+ workInProgress.memoizedState = resultState;
+}
+function commitUpdateQueue(finishedWork, finishedQueue, instance) {
+ null !== finishedQueue.firstCapturedUpdate &&
+ (null !== finishedQueue.lastUpdate &&
+ ((finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate),
+ (finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate)),
+ (finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null));
+ commitUpdateEffects(finishedQueue.firstEffect, instance);
+ finishedQueue.firstEffect = finishedQueue.lastEffect = null;
+ commitUpdateEffects(finishedQueue.firstCapturedEffect, instance);
+ finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null;
+}
+function commitUpdateEffects(effect, instance) {
+ for (; null !== effect; ) {
+ var _callback3 = effect.callback;
+ if (null !== _callback3) {
+ effect.callback = null;
+ var context = instance;
+ invariant(
+ "function" === typeof _callback3,
+ "Invalid argument passed as callback. Expected a function. Instead received: %s",
+ _callback3
+ );
+ _callback3.call(context);
+ }
+ effect = effect.nextEffect;
+ }
+}
+function createCapturedValue(value, source) {
+ return {
+ value: value,
+ source: source,
+ stack: getStackByFiberInDevAndProd(source)
+ };
}
var appendAllChildren = void 0,
updateHostContainer = void 0,
@@ -4522,6 +5094,7 @@
: Error("Unspecified error at:" + componentStack);
ExceptionsManager.handleException(error, !1);
}
+var PossiblyWeakSet$1 = "function" === typeof WeakSet ? WeakSet : Set;
function logError(boundary, errorInfo) {
var source = errorInfo.source,
stack = errorInfo.stack;
@@ -4562,6 +5135,81 @@
}
else ref.current = null;
}
+function commitHookEffectList(unmountTag, mountTag, finishedWork) {
+ finishedWork = finishedWork.updateQueue;
+ finishedWork = null !== finishedWork ? finishedWork.lastEffect : null;
+ if (null !== finishedWork) {
+ var effect = (finishedWork = finishedWork.next);
+ do {
+ if ((effect.tag & unmountTag) !== NoEffect$1) {
+ var destroy = effect.destroy;
+ effect.destroy = void 0;
+ void 0 !== destroy && destroy();
+ }
+ (effect.tag & mountTag) !== NoEffect$1 &&
+ ((destroy = effect.create), (effect.destroy = destroy()));
+ effect = effect.next;
+ } while (effect !== finishedWork);
+ }
+}
+function hideOrUnhideAllChildren(finishedWork, isHidden) {
+ for (var node = finishedWork; ; ) {
+ if (5 === node.tag) {
+ var instance = node.stateNode;
+ if (isHidden) {
+ var viewConfig = instance.viewConfig;
+ var updatePayload = diffProperties(
+ null,
+ emptyObject,
+ { style: { display: "none" } },
+ viewConfig.validAttributes
+ );
+ UIManager.updateView(
+ instance._nativeTag,
+ viewConfig.uiViewClassName,
+ updatePayload
+ );
+ } else {
+ instance = node.stateNode;
+ updatePayload = node.memoizedProps;
+ viewConfig = instance.viewConfig;
+ var prevProps = Object.assign({}, updatePayload, {
+ style: [updatePayload.style, { display: "none" }]
+ });
+ updatePayload = diffProperties(
+ null,
+ prevProps,
+ updatePayload,
+ viewConfig.validAttributes
+ );
+ UIManager.updateView(
+ instance._nativeTag,
+ viewConfig.uiViewClassName,
+ updatePayload
+ );
+ }
+ } else {
+ if (6 === node.tag) throw Error("Not yet implemented.");
+ if (13 === node.tag && null !== node.memoizedState) {
+ instance = node.child.sibling;
+ instance.return = node;
+ node = instance;
+ continue;
+ } else if (null !== node.child) {
+ node.child.return = node;
+ node = node.child;
+ continue;
+ }
+ }
+ if (node === finishedWork) break;
+ for (; null === node.sibling; ) {
+ if (null === node.return || node.return === finishedWork) return;
+ node = node.return;
+ }
+ node.sibling.return = node.return;
+ node = node.sibling;
+ }
+}
function commitUnmount(current$$1$jscomp$0) {
"function" === typeof onCommitFiberUnmount &&
onCommitFiberUnmount(current$$1$jscomp$0);
@@ -4578,7 +5226,7 @@
var effect = (updateQueue = updateQueue.next);
do {
var destroy = effect.destroy;
- if (null !== destroy) {
+ if (void 0 !== destroy) {
var current$$1 = current$$1$jscomp$0;
try {
destroy();
@@ -4659,7 +5307,7 @@
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;
@@ -4822,13 +5470,15 @@
node$jscomp$0.splice(child, 1);
UIManager.manageChildren(root._nativeTag, [], [], [], [], [child]);
}
- } else if (
- (4 === node.tag
- ? ((currentParent = node.stateNode.containerInfo),
- (currentParentIsContainer = !0))
- : commitUnmount(node),
- null !== node.child)
- ) {
+ } else if (4 === node.tag) {
+ if (null !== node.child) {
+ currentParent = node.stateNode.containerInfo;
+ currentParentIsContainer = !0;
+ node.child.return = node;
+ node = node.child;
+ continue;
+ }
+ } else if ((commitUnmount(node), null !== node.child)) {
node.child.return = node;
node = node.child;
continue;
@@ -4849,6 +5499,7 @@
case 11:
case 14:
case 15:
+ commitHookEffectList(UnmountMutation, MountMutation, finishedWork);
break;
case 1:
break;
@@ -4857,23 +5508,18 @@
if (null != instance) {
var newProps = finishedWork.memoizedProps;
current$$1 = null !== current$$1 ? current$$1.memoizedProps : newProps;
- var updatePayload = finishedWork.updateQueue;
+ var type = finishedWork.type,
+ updatePayload = finishedWork.updateQueue;
finishedWork.updateQueue = null;
null !== updatePayload &&
- ((finishedWork = instance.viewConfig),
- (instanceProps[instance._nativeTag] = newProps),
- (newProps = diffProperties(
- null,
+ commitUpdate(
+ instance,
+ updatePayload,
+ type,
current$$1,
newProps,
- finishedWork.validAttributes
- )),
- null != newProps &&
- UIManager.updateView(
- instance._nativeTag,
- finishedWork.uiViewClassName,
- newProps
- ));
+ finishedWork
+ );
}
break;
case 6:
@@ -4890,70 +5536,27 @@
case 12:
break;
case 13:
- newProps = finishedWork.memoizedState;
+ instance = finishedWork.memoizedState;
+ newProps = void 0;
current$$1 = finishedWork;
- null === newProps
- ? (instance = !1)
- : ((instance = !0),
+ null === instance
+ ? (newProps = !1)
+ : ((newProps = !0),
(current$$1 = finishedWork.child),
- 0 === newProps.timedOutAt &&
- (newProps.timedOutAt = requestCurrentTime()));
- if (null !== current$$1)
- a: for (newProps = finishedWork = current$$1; ; ) {
- if (5 === newProps.tag)
- if (((current$$1 = newProps.stateNode), instance)) {
- updatePayload = current$$1.viewConfig;
- var updatePayload$jscomp$0 = diffProperties(
- null,
- emptyObject,
- { style: { display: "none" } },
- updatePayload.validAttributes
- );
- UIManager.updateView(
- current$$1._nativeTag,
- updatePayload.uiViewClassName,
- updatePayload$jscomp$0
- );
- } else {
- current$$1 = newProps.stateNode;
- updatePayload$jscomp$0 = newProps.memoizedProps;
- updatePayload = current$$1.viewConfig;
- var prevProps = Object.assign({}, updatePayload$jscomp$0, {
- style: [updatePayload$jscomp$0.style, { display: "none" }]
+ 0 === instance.timedOutAt &&
+ (instance.timedOutAt = requestCurrentTime()));
+ null !== current$$1 && hideOrUnhideAllChildren(current$$1, newProps);
+ instance = finishedWork.updateQueue;
+ if (null !== instance) {
+ finishedWork.updateQueue = null;
+ var retryCache = finishedWork.stateNode;
+ null === retryCache &&
+ (retryCache = finishedWork.stateNode = new PossiblyWeakSet$1());
+ instance.forEach(function(thenable) {
+ var retry = resolveRetryThenable.bind(null, finishedWork, thenable);
+ retryCache.has(thenable) ||
+ (retryCache.add(thenable), thenable.then(retry, retry));
});
- updatePayload$jscomp$0 = diffProperties(
- null,
- prevProps,
- updatePayload$jscomp$0,
- updatePayload.validAttributes
- );
- UIManager.updateView(
- current$$1._nativeTag,
- updatePayload.uiViewClassName,
- updatePayload$jscomp$0
- );
- }
- else {
- if (6 === newProps.tag) throw Error("Not yet implemented.");
- if (13 === newProps.tag && null !== newProps.memoizedState) {
- current$$1 = newProps.child.sibling;
- current$$1.return = newProps;
- newProps = current$$1;
- continue;
- } else if (null !== newProps.child) {
- newProps.child.return = newProps;
- newProps = newProps.child;
- continue;
- }
- }
- if (newProps === finishedWork) break a;
- for (; null === newProps.sibling; ) {
- if (null === newProps.return || newProps.return === finishedWork)
- break a;
- newProps = newProps.return;
- }
- newProps.sibling.return = newProps.return;
- newProps = newProps.sibling;
}
break;
case 17:
@@ -4965,9 +5568,10 @@
);
}
}
+var PossiblyWeakMap = "function" === typeof WeakMap ? WeakMap : Map;
function createRootErrorUpdate(fiber, errorInfo, expirationTime) {
expirationTime = createUpdate(expirationTime);
- expirationTime.tag = 3;
+ expirationTime.tag = CaptureUpdate;
expirationTime.payload = { element: null };
var error = errorInfo.value;
expirationTime.callback = function() {
@@ -4978,7 +5582,7 @@
}
function createClassErrorUpdate(fiber, errorInfo, expirationTime) {
expirationTime = createUpdate(expirationTime);
- expirationTime.tag = 3;
+ expirationTime.tag = CaptureUpdate;
var getDerivedStateFromError = fiber.type.getDerivedStateFromError;
if ("function" === typeof getDerivedStateFromError) {
var error$jscomp$0 = errorInfo.value;
@@ -5034,6 +5638,8 @@
workInProgress)
: null
);
+ case 18:
+ return null;
case 4:
return popHostContainer(workInProgress), null;
case 10:
@@ -5042,7 +5648,7 @@
return null;
}
}
-var DispatcherWithoutHooks = { readContext: readContext },
+var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher,
ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner,
isWorking = !1,
nextUnitOfWork = null,
@@ -5052,6 +5658,7 @@
nextRenderDidError = !1,
nextEffect = null,
isCommitting$1 = !1,
+ rootWithPendingPassiveEffects = null,
passiveEffectCallbackHandle = null,
passiveEffectCallback = null,
legacyErrorBoundariesThatAlreadyFailed = null;
@@ -5092,10 +5699,317 @@
nextRenderDidError = !1;
nextUnitOfWork = null;
}
+function commitAllHostEffects() {
+ for (; null !== nextEffect; ) {
+ var effectTag = nextEffect.effectTag;
+ if (effectTag & 128) {
+ var current$$1 = nextEffect.alternate;
+ null !== current$$1 &&
+ ((current$$1 = current$$1.ref),
+ null !== current$$1 &&
+ ("function" === typeof current$$1
+ ? current$$1(null)
+ : (current$$1.current = null)));
+ }
+ switch (effectTag & 14) {
+ case 2:
+ commitPlacement(nextEffect);
+ nextEffect.effectTag &= -3;
+ break;
+ case 6:
+ commitPlacement(nextEffect);
+ nextEffect.effectTag &= -3;
+ commitWork(nextEffect.alternate, nextEffect);
+ break;
+ case 4:
+ commitWork(nextEffect.alternate, nextEffect);
+ break;
+ case 8:
+ (effectTag = nextEffect),
+ unmountHostComponents(effectTag),
+ (effectTag.return = null),
+ (effectTag.child = null),
+ (effectTag.memoizedState = null),
+ (effectTag.updateQueue = null),
+ (effectTag = effectTag.alternate),
+ null !== effectTag &&
+ ((effectTag.return = null),
+ (effectTag.child = null),
+ (effectTag.memoizedState = null),
+ (effectTag.updateQueue = null));
+ }
+ nextEffect = nextEffect.nextEffect;
+ }
+}
+function commitBeforeMutationLifecycles() {
+ for (; null !== nextEffect; ) {
+ if (nextEffect.effectTag & 256)
+ a: {
+ var current$$1 = nextEffect.alternate,
+ finishedWork = nextEffect;
+ switch (finishedWork.tag) {
+ case 0:
+ case 11:
+ case 15:
+ commitHookEffectList(UnmountSnapshot, NoEffect$1, finishedWork);
+ break a;
+ case 1:
+ if (finishedWork.effectTag & 256 && null !== current$$1) {
+ var prevProps = current$$1.memoizedProps,
+ prevState = current$$1.memoizedState;
+ current$$1 = finishedWork.stateNode;
+ finishedWork = current$$1.getSnapshotBeforeUpdate(
+ finishedWork.elementType === finishedWork.type
+ ? prevProps
+ : resolveDefaultProps(finishedWork.type, prevProps),
+ prevState
+ );
+ current$$1.__reactInternalSnapshotBeforeUpdate = finishedWork;
+ }
+ break a;
+ case 3:
+ case 5:
+ case 6:
+ case 4:
+ case 17:
+ break a;
+ default:
+ invariant(
+ !1,
+ "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue."
+ );
+ }
+ }
+ nextEffect = nextEffect.nextEffect;
+ }
+}
+function commitAllLifeCycles(finishedRoot, committedExpirationTime$jscomp$0) {
+ for (; null !== nextEffect; ) {
+ var effectTag = nextEffect.effectTag;
+ if (effectTag & 36) {
+ var current$$1 = nextEffect.alternate,
+ finishedWork = nextEffect,
+ committedExpirationTime = committedExpirationTime$jscomp$0;
+ switch (finishedWork.tag) {
+ case 0:
+ case 11:
+ case 15:
+ commitHookEffectList(UnmountLayout, MountLayout, finishedWork);
+ break;
+ case 1:
+ var instance = finishedWork.stateNode;
+ if (finishedWork.effectTag & 4)
+ if (null === current$$1) instance.componentDidMount();
+ else {
+ var prevProps =
+ finishedWork.elementType === finishedWork.type
+ ? current$$1.memoizedProps
+ : resolveDefaultProps(
+ finishedWork.type,
+ current$$1.memoizedProps
+ );
+ instance.componentDidUpdate(
+ prevProps,
+ current$$1.memoizedState,
+ instance.__reactInternalSnapshotBeforeUpdate
+ );
+ }
+ current$$1 = finishedWork.updateQueue;
+ null !== current$$1 &&
+ commitUpdateQueue(
+ finishedWork,
+ current$$1,
+ instance,
+ committedExpirationTime
+ );
+ break;
+ case 3:
+ instance = finishedWork.updateQueue;
+ if (null !== instance) {
+ current$$1 = null;
+ if (null !== finishedWork.child)
+ switch (finishedWork.child.tag) {
+ case 5:
+ current$$1 = finishedWork.child.stateNode;
+ break;
+ case 1:
+ current$$1 = finishedWork.child.stateNode;
+ }
+ commitUpdateQueue(
+ finishedWork,
+ instance,
+ current$$1,
+ committedExpirationTime
+ );
+ }
+ break;
+ case 5:
+ break;
+ case 6:
+ break;
+ case 4:
+ break;
+ case 12:
+ break;
+ case 13:
+ break;
+ case 17:
+ break;
+ default:
+ invariant(
+ !1,
+ "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue."
+ );
+ }
+ }
+ effectTag & 128 &&
+ ((finishedWork = nextEffect.ref),
+ null !== finishedWork &&
+ ((committedExpirationTime = nextEffect.stateNode),
+ "function" === typeof finishedWork
+ ? finishedWork(committedExpirationTime)
+ : (finishedWork.current = committedExpirationTime)));
+ effectTag & 512 && (rootWithPendingPassiveEffects = finishedRoot);
+ nextEffect = nextEffect.nextEffect;
+ }
+}
+function commitPassiveEffects(root, firstEffect) {
+ passiveEffectCallback = passiveEffectCallbackHandle = rootWithPendingPassiveEffects = null;
+ var previousIsRendering = isRendering;
+ isRendering = !0;
+ do {
+ if (firstEffect.effectTag & 512) {
+ var didError = !1,
+ error = void 0;
+ try {
+ var finishedWork = firstEffect;
+ commitHookEffectList(UnmountPassive, NoEffect$1, finishedWork);
+ commitHookEffectList(NoEffect$1, MountPassive, finishedWork);
+ } catch (e) {
+ (didError = !0), (error = e);
+ }
+ didError && captureCommitPhaseError(firstEffect, error);
+ }
+ firstEffect = firstEffect.nextEffect;
+ } while (null !== firstEffect);
+ isRendering = previousIsRendering;
+ previousIsRendering = root.expirationTime;
+ 0 !== previousIsRendering && requestWork(root, previousIsRendering);
+ isBatchingUpdates || isRendering || performWork(1073741823, !1);
+}
function flushPassiveEffects() {
- null !== passiveEffectCallback &&
- (scheduler.unstable_cancelCallback(passiveEffectCallbackHandle),
- passiveEffectCallback());
+ if (null !== passiveEffectCallbackHandle) {
+ var callbackID = passiveEffectCallbackHandle;
+ scheduledCallback = null;
+ clearTimeout(callbackID);
+ }
+ null !== passiveEffectCallback && passiveEffectCallback();
+}
+function commitRoot(root, finishedWork) {
+ isCommitting$1 = isWorking = !0;
+ invariant(
+ root.current !== finishedWork,
+ "Cannot commit the same tree as before. This is probably a bug related to the return field. This error is likely caused by a bug in React. Please file an issue."
+ );
+ var committedExpirationTime = root.pendingCommitExpirationTime;
+ invariant(
+ 0 !== committedExpirationTime,
+ "Cannot commit an incomplete root. This error is likely caused by a bug in React. Please file an issue."
+ );
+ root.pendingCommitExpirationTime = 0;
+ var updateExpirationTimeBeforeCommit = finishedWork.expirationTime,
+ childExpirationTimeBeforeCommit = finishedWork.childExpirationTime;
+ markCommittedPriorityLevels(
+ root,
+ childExpirationTimeBeforeCommit > updateExpirationTimeBeforeCommit
+ ? childExpirationTimeBeforeCommit
+ : updateExpirationTimeBeforeCommit
+ );
+ ReactCurrentOwner$2.current = null;
+ updateExpirationTimeBeforeCommit = void 0;
+ 1 < finishedWork.effectTag
+ ? null !== finishedWork.lastEffect
+ ? ((finishedWork.lastEffect.nextEffect = finishedWork),
+ (updateExpirationTimeBeforeCommit = finishedWork.firstEffect))
+ : (updateExpirationTimeBeforeCommit = finishedWork)
+ : (updateExpirationTimeBeforeCommit = finishedWork.firstEffect);
+ for (nextEffect = updateExpirationTimeBeforeCommit; null !== nextEffect; ) {
+ childExpirationTimeBeforeCommit = !1;
+ var error = void 0;
+ try {
+ commitBeforeMutationLifecycles();
+ } catch (e) {
+ (childExpirationTimeBeforeCommit = !0), (error = e);
+ }
+ childExpirationTimeBeforeCommit &&
+ (invariant(
+ null !== nextEffect,
+ "Should have next effect. This error is likely caused by a bug in React. Please file an issue."
+ ),
+ captureCommitPhaseError(nextEffect, error),
+ null !== nextEffect && (nextEffect = nextEffect.nextEffect));
+ }
+ for (nextEffect = updateExpirationTimeBeforeCommit; null !== nextEffect; ) {
+ childExpirationTimeBeforeCommit = !1;
+ error = void 0;
+ try {
+ commitAllHostEffects();
+ } catch (e) {
+ (childExpirationTimeBeforeCommit = !0), (error = e);
+ }
+ childExpirationTimeBeforeCommit &&
+ (invariant(
+ null !== nextEffect,
+ "Should have next effect. This error is likely caused by a bug in React. Please file an issue."
+ ),
+ captureCommitPhaseError(nextEffect, error),
+ null !== nextEffect && (nextEffect = nextEffect.nextEffect));
+ }
+ root.current = finishedWork;
+ for (nextEffect = updateExpirationTimeBeforeCommit; null !== nextEffect; ) {
+ childExpirationTimeBeforeCommit = !1;
+ error = void 0;
+ try {
+ commitAllLifeCycles(root, committedExpirationTime);
+ } catch (e) {
+ (childExpirationTimeBeforeCommit = !0), (error = e);
+ }
+ childExpirationTimeBeforeCommit &&
+ (invariant(
+ null !== nextEffect,
+ "Should have next effect. This error is likely caused by a bug in React. Please file an issue."
+ ),
+ captureCommitPhaseError(nextEffect, error),
+ null !== nextEffect && (nextEffect = nextEffect.nextEffect));
+ }
+ if (
+ null !== updateExpirationTimeBeforeCommit &&
+ null !== rootWithPendingPassiveEffects
+ ) {
+ var callback = commitPassiveEffects.bind(
+ null,
+ root,
+ updateExpirationTimeBeforeCommit
+ );
+ passiveEffectCallbackHandle = scheduler.unstable_runWithPriority(
+ scheduler.unstable_NormalPriority,
+ function() {
+ return scheduleDeferredCallback$1(callback);
+ }
+ );
+ passiveEffectCallback = callback;
+ }
+ isWorking = isCommitting$1 = !1;
+ "function" === typeof onCommitFiberRoot &&
+ onCommitFiberRoot(finishedWork.stateNode);
+ committedExpirationTime = finishedWork.expirationTime;
+ finishedWork = finishedWork.childExpirationTime;
+ finishedWork =
+ finishedWork > committedExpirationTime
+ ? finishedWork
+ : committedExpirationTime;
+ 0 === finishedWork && (legacyErrorBoundariesThatAlreadyFailed = null);
+ onCommit(root, finishedWork);
}
function completeUnitOfWork(workInProgress) {
for (;;) {
@@ -5237,11 +6151,7 @@
: ((current$$1.firstEffect = current$$1.lastEffect = type),
(type.nextEffect = null)),
(type.effectTag = 8)));
- if (
- newProps !== renderExpirationTime ||
- (0 === (current$$1.effectTag & 1) && newProps)
- )
- current$$1.effectTag |= 4;
+ if (newProps || renderExpirationTime) current$$1.effectTag |= 4;
break;
case 7:
break;
@@ -5263,6 +6173,8 @@
case 17:
isContextProvider(current$$1.type) && popContext(current$$1);
break;
+ case 18:
+ break;
default:
invariant(
!1,
@@ -5335,7 +6247,8 @@
);
flushPassiveEffects();
isWorking = !0;
- ReactCurrentOwner$2.currentDispatcher = DispatcherWithoutHooks;
+ var previousDispatcher = ReactCurrentDispatcher.current;
+ ReactCurrentDispatcher.current = ContextOnlyDispatcher;
var expirationTime = root$jscomp$0.nextExpirationTimeToWorkOn;
if (
expirationTime !== nextRenderExpirationTime ||
@@ -5355,7 +6268,7 @@
do {
try {
if (isYieldy)
- for (; null !== nextUnitOfWork && !shouldYieldToRenderer(); )
+ for (; null !== nextUnitOfWork && !(frameDeadline <= now$1()); )
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
else
for (; null !== nextUnitOfWork; )
@@ -5363,6 +6276,7 @@
} catch (thrownValue) {
if (
((lastContextWithAllBitsObserved = lastContextDependency = currentlyRenderingFiber = null),
+ resetHooks(),
null === nextUnitOfWork)
)
(didFatal = !0), onUncaughtError(thrownValue);
@@ -5422,23 +6336,44 @@
? !1
: null === value.memoizedState;
if (current$$1) {
- returnFiber$jscomp$0 = retrySuspendedRoot.bind(
- null,
- root,
- value,
- sourceFiber$jscomp$0,
- 0 === (value.mode & 1) ? 1073741823 : returnFiber
- );
- thenable.then(returnFiber$jscomp$0, returnFiber$jscomp$0);
+ returnFiber$jscomp$0 = value.updateQueue;
+ null === returnFiber$jscomp$0
+ ? ((returnFiber$jscomp$0 = new Set()),
+ returnFiber$jscomp$0.add(thenable),
+ (value.updateQueue = returnFiber$jscomp$0))
+ : returnFiber$jscomp$0.add(thenable);
if (0 === (value.mode & 1)) {
value.effectTag |= 64;
sourceFiber$jscomp$0.effectTag &= -1957;
1 === sourceFiber$jscomp$0.tag &&
- null === sourceFiber$jscomp$0.alternate &&
- (sourceFiber$jscomp$0.tag = 17);
- sourceFiber$jscomp$0.expirationTime = returnFiber;
+ (null === sourceFiber$jscomp$0.alternate
+ ? (sourceFiber$jscomp$0.tag = 17)
+ : ((returnFiber = createUpdate(1073741823)),
+ (returnFiber.tag = ForceUpdate),
+ enqueueUpdate(sourceFiber$jscomp$0, returnFiber)));
+ sourceFiber$jscomp$0.expirationTime = 1073741823;
break a;
}
+ 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,
+ sourceFiber$jscomp$0,
+ thenable,
+ returnFiber$jscomp$0
+ )),
+ thenable.then(sourceFiber$jscomp$0, sourceFiber$jscomp$0));
-1 === earliestTimeoutMs
? (root = 1073741823)
: (-1 === startTimeMs &&
@@ -5473,36 +6408,32 @@
do {
switch (root.tag) {
case 3:
- sourceFiber$jscomp$0 = value;
root.effectTag |= 2048;
root.expirationTime = returnFiber;
- returnFiber = createRootErrorUpdate(
- root,
- sourceFiber$jscomp$0,
- returnFiber
- );
+ returnFiber = createRootErrorUpdate(root, value, returnFiber);
enqueueCapturedUpdate(root, returnFiber);
break a;
case 1:
if (
- ((sourceFiber$jscomp$0 = value),
- (returnFiber$jscomp$0 = root.type),
- (thenable = root.stateNode),
+ ((earliestTimeoutMs = value),
+ (startTimeMs = root.type),
+ (sourceFiber$jscomp$0 = root.stateNode),
0 === (root.effectTag & 64) &&
("function" ===
- typeof returnFiber$jscomp$0.getDerivedStateFromError ||
- (null !== thenable &&
- "function" === typeof thenable.componentDidCatch &&
+ typeof startTimeMs.getDerivedStateFromError ||
+ (null !== sourceFiber$jscomp$0 &&
+ "function" ===
+ typeof sourceFiber$jscomp$0.componentDidCatch &&
(null === legacyErrorBoundariesThatAlreadyFailed ||
!legacyErrorBoundariesThatAlreadyFailed.has(
- thenable
+ sourceFiber$jscomp$0
)))))
) {
root.effectTag |= 2048;
root.expirationTime = returnFiber;
returnFiber = createClassErrorUpdate(
root,
- sourceFiber$jscomp$0,
+ earliestTimeoutMs,
returnFiber
);
enqueueCapturedUpdate(root, returnFiber);
@@ -5520,29 +6451,31 @@
break;
} while (1);
isWorking = !1;
- lastContextWithAllBitsObserved = lastContextDependency = currentlyRenderingFiber = ReactCurrentOwner$2.currentDispatcher = null;
+ ReactCurrentDispatcher.current = previousDispatcher;
+ lastContextWithAllBitsObserved = lastContextDependency = currentlyRenderingFiber = null;
+ resetHooks();
if (didFatal) (nextRoot = null), (root$jscomp$0.finishedWork = null);
else if (null !== nextUnitOfWork) root$jscomp$0.finishedWork = null;
else {
- didFatal = root$jscomp$0.current.alternate;
+ previousDispatcher = root$jscomp$0.current.alternate;
invariant(
- null !== didFatal,
+ null !== previousDispatcher,
"Finished root should have a work-in-progress. This error is likely caused by a bug in React. Please file an issue."
);
nextRoot = null;
if (nextRenderDidError) {
- sourceFiber = root$jscomp$0.latestPendingTime;
- returnFiber = root$jscomp$0.latestSuspendedTime;
- root = root$jscomp$0.latestPingedTime;
+ didFatal = root$jscomp$0.latestPendingTime;
+ sourceFiber = root$jscomp$0.latestSuspendedTime;
+ returnFiber = root$jscomp$0.latestPingedTime;
if (
+ (0 !== didFatal && didFatal < expirationTime) ||
(0 !== sourceFiber && sourceFiber < expirationTime) ||
- (0 !== returnFiber && returnFiber < expirationTime) ||
- (0 !== root && root < expirationTime)
+ (0 !== returnFiber && returnFiber < expirationTime)
) {
markSuspendedPriorityLevel(root$jscomp$0, expirationTime);
onSuspend(
root$jscomp$0,
- didFatal,
+ previousDispatcher,
expirationTime,
root$jscomp$0.expirationTime,
-1
@@ -5553,7 +6486,13 @@
root$jscomp$0.didError = !0;
expirationTime = root$jscomp$0.nextExpirationTimeToWorkOn = expirationTime;
isYieldy = root$jscomp$0.expirationTime = 1073741823;
- onSuspend(root$jscomp$0, didFatal, expirationTime, isYieldy, -1);
+ onSuspend(
+ root$jscomp$0,
+ previousDispatcher,
+ expirationTime,
+ isYieldy,
+ -1
+ );
return;
}
}
@@ -5572,13 +6511,13 @@
(isYieldy = nextLatestAbsoluteTimeoutMs - isYieldy),
onSuspend(
root$jscomp$0,
- didFatal,
+ previousDispatcher,
expirationTime,
root$jscomp$0.expirationTime,
0 > isYieldy ? 0 : isYieldy
))
: ((root$jscomp$0.pendingCommitExpirationTime = expirationTime),
- (root$jscomp$0.finishedWork = didFatal));
+ (root$jscomp$0.finishedWork = previousDispatcher));
}
}
function captureCommitPhaseError(sourceFiber, value) {
@@ -5615,55 +6554,72 @@
scheduleWork(sourceFiber, 1073741823));
}
function computeExpirationForFiber(currentTime, fiber) {
- isWorking
- ? (currentTime = isCommitting$1 ? 1073741823 : nextRenderExpirationTime)
- : fiber.mode & 1
- ? ((currentTime = isBatchingInteractiveUpdates
- ? 1073741822 - 10 * ((((1073741822 - currentTime + 15) / 10) | 0) + 1)
- : 1073741822 -
- 25 * ((((1073741822 - currentTime + 500) / 25) | 0) + 1)),
+ var priorityLevel = scheduler.unstable_getCurrentPriorityLevel(),
+ expirationTime = void 0;
+ if (0 === (fiber.mode & 1)) expirationTime = 1073741823;
+ else if (isWorking && !isCommitting$1)
+ expirationTime = nextRenderExpirationTime;
+ else {
+ switch (priorityLevel) {
+ case scheduler.unstable_ImmediatePriority:
+ expirationTime = 1073741823;
+ break;
+ case scheduler.unstable_UserBlockingPriority:
+ expirationTime =
+ 1073741822 - 10 * ((((1073741822 - currentTime + 15) / 10) | 0) + 1);
+ break;
+ case scheduler.unstable_NormalPriority:
+ expirationTime =
+ 1073741822 - 25 * ((((1073741822 - currentTime + 500) / 25) | 0) + 1);
+ break;
+ case scheduler.unstable_LowPriority:
+ case scheduler.unstable_IdlePriority:
+ expirationTime = 1;
+ break;
+ default:
+ invariant(
+ !1,
+ "Unknown priority level. This error is likely caused by a bug in React. Please file an issue."
+ );
+ }
null !== nextRoot &&
- currentTime === nextRenderExpirationTime &&
- --currentTime)
- : (currentTime = 1073741823);
- isBatchingInteractiveUpdates &&
+ expirationTime === nextRenderExpirationTime &&
+ --expirationTime;
+ }
+ priorityLevel === scheduler.unstable_UserBlockingPriority &&
(0 === lowestPriorityPendingInteractiveExpirationTime ||
- currentTime < lowestPriorityPendingInteractiveExpirationTime) &&
- (lowestPriorityPendingInteractiveExpirationTime = currentTime);
- return currentTime;
-}
-function retrySuspendedRoot(root, boundaryFiber, sourceFiber, suspendedTime) {
- var retryTime = root.earliestSuspendedTime;
- var latestSuspendedTime = root.latestSuspendedTime;
- if (
- 0 !== retryTime &&
- suspendedTime <= retryTime &&
- suspendedTime >= latestSuspendedTime
+ expirationTime < lowestPriorityPendingInteractiveExpirationTime) &&
+ (lowestPriorityPendingInteractiveExpirationTime = expirationTime);
+ return expirationTime;
+}
+function pingSuspendedRoot(root, thenable, pingTime) {
+ var pingCache = root.pingCache;
+ null !== pingCache && pingCache.delete(thenable);
+ if (null !== nextRoot && nextRenderExpirationTime === pingTime)
+ nextRoot = null;
+ else if (
+ ((thenable = root.earliestSuspendedTime),
+ (pingCache = root.latestSuspendedTime),
+ 0 !== thenable && pingTime <= thenable && pingTime >= pingCache)
) {
- latestSuspendedTime = retryTime = suspendedTime;
root.didError = !1;
- var latestPingedTime = root.latestPingedTime;
- if (0 === latestPingedTime || latestPingedTime > latestSuspendedTime)
- root.latestPingedTime = latestSuspendedTime;
- findNextExpirationTimeToWorkOn(latestSuspendedTime, root);
- } else
- (retryTime = requestCurrentTime()),
- (retryTime = computeExpirationForFiber(retryTime, boundaryFiber)),
- markPendingPriorityLevel(root, retryTime);
- 0 !== (boundaryFiber.mode & 1) &&
- root === nextRoot &&
- nextRenderExpirationTime === suspendedTime &&
- (nextRoot = null);
- scheduleWorkToRoot(boundaryFiber, retryTime);
- 0 === (boundaryFiber.mode & 1) &&
- (scheduleWorkToRoot(sourceFiber, retryTime),
- 1 === sourceFiber.tag &&
- null !== sourceFiber.stateNode &&
- ((boundaryFiber = createUpdate(retryTime)),
- (boundaryFiber.tag = 2),
- enqueueUpdate(sourceFiber, boundaryFiber)));
- sourceFiber = root.expirationTime;
- 0 !== sourceFiber && requestWork(root, sourceFiber);
+ thenable = root.latestPingedTime;
+ if (0 === thenable || thenable > pingTime) root.latestPingedTime = pingTime;
+ findNextExpirationTimeToWorkOn(pingTime, root);
+ pingTime = root.expirationTime;
+ 0 !== pingTime && requestWork(root, pingTime);
+ }
+}
+function resolveRetryThenable(boundaryFiber, thenable) {
+ var retryCache = boundaryFiber.stateNode;
+ null !== retryCache && retryCache.delete(thenable);
+ thenable = requestCurrentTime();
+ thenable = computeExpirationForFiber(thenable, boundaryFiber);
+ boundaryFiber = scheduleWorkToRoot(boundaryFiber, thenable);
+ null !== boundaryFiber &&
+ (markPendingPriorityLevel(boundaryFiber, thenable),
+ (thenable = boundaryFiber.expirationTime),
+ 0 !== thenable && requestWork(boundaryFiber, thenable));
}
function scheduleWorkToRoot(fiber, expirationTime) {
fiber.expirationTime < expirationTime &&
@@ -5720,7 +6676,6 @@
unhandledError = null,
isBatchingUpdates = !1,
isUnbatchingUpdates = !1,
- isBatchingInteractiveUpdates = !1,
completedBatches = null,
originalStartTimeMs = now$1(),
currentRendererTime = 1073741822 - ((originalStartTimeMs / 10) | 0),
@@ -5739,9 +6694,10 @@
((root = callbackID), (scheduledCallback = null), clearTimeout(root));
}
callbackExpirationTime = expirationTime;
- now$1();
- scheduledCallback = performAsyncWork;
- callbackID = setTimeout(setTimeoutCallback, 1);
+ root = now$1() - originalStartTimeMs;
+ callbackID = scheduleDeferredCallback$1(performAsyncWork, {
+ timeout: 10 * (1073741822 - expirationTime) - root
+ });
}
function onSuspend(
root,
@@ -5751,7 +6707,7 @@
msUntilTimeout
) {
root.expirationTime = rootExpirationTime;
- 0 !== msUntilTimeout || shouldYieldToRenderer()
+ 0 !== msUntilTimeout || frameDeadline <= now$1()
? 0 < msUntilTimeout &&
(root.timeoutHandle = scheduleTimeout(
onTimeout.bind(null, root, finishedWork, suspendedExpirationTime),
@@ -5774,6 +6730,10 @@
performWorkOnRoot(root, suspendedExpirationTime, !1);
performWork(1073741823, !1);
}
+function onCommit(root, expirationTime) {
+ root.expirationTime = expirationTime;
+ root.finishedWork = null;
+}
function requestCurrentTime() {
if (isRendering) return currentSchedulerTime;
findHighestPriorityRoot();
@@ -5847,27 +6807,19 @@
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) {
+function performAsyncWork(didTimeout) {
+ if (didTimeout && null !== firstScheduledRoot) {
recomputeCurrentRendererTime();
- var root = firstScheduledRoot;
+ didTimeout = firstScheduledRoot;
do {
- var expirationTime = root.expirationTime;
+ var expirationTime = didTimeout.expirationTime;
0 !== expirationTime &&
currentRendererTime <= expirationTime &&
- (root.nextExpirationTimeToWorkOn = currentRendererTime);
- root = root.nextScheduledRoot;
- } while (root !== firstScheduledRoot);
+ (didTimeout.nextExpirationTimeToWorkOn = currentRendererTime);
+ didTimeout = didTimeout.nextScheduledRoot;
+ } while (didTimeout !== firstScheduledRoot);
}
performWork(0, !0);
- } finally {
- didYield = !1;
- }
}
function performWork(minExpirationTime, isYieldy) {
findHighestPriorityRoot();
@@ -5878,7 +6830,10 @@
null !== nextFlushedRoot &&
0 !== nextFlushedExpirationTime &&
minExpirationTime <= nextFlushedExpirationTime &&
- !(didYield && currentRendererTime > nextFlushedExpirationTime);
+ !(
+ frameDeadline <= now$1() &&
+ currentRendererTime > nextFlushedExpirationTime
+ );
)
performWorkOnRoot(
@@ -5946,7 +6901,7 @@
renderRoot(root, isYieldy),
(_finishedWork = root.finishedWork),
null !== _finishedWork &&
- (shouldYieldToRenderer()
+ (frameDeadline <= now$1()
? (root.finishedWork = _finishedWork)
: completeRoot(root, _finishedWork, expirationTime)));
} else
@@ -5963,7 +6918,7 @@
completeRoot(root, _finishedWork, expirationTime));
isRendering = !1;
}
-function completeRoot(root, finishedWork$jscomp$0, expirationTime) {
+function completeRoot(root, finishedWork, expirationTime) {
var firstBatch = root.firstBatch;
if (
null !== firstBatch &&
@@ -5973,7 +6928,7 @@
: completedBatches.push(firstBatch),
firstBatch._defer)
) {
- root.finishedWork = finishedWork$jscomp$0;
+ root.finishedWork = finishedWork;
root.expirationTime = 0;
return;
}
@@ -5981,290 +6936,12 @@
root === lastCommittedRootDuringThisBatch
? nestedUpdateCount++
: ((lastCommittedRootDuringThisBatch = root), (nestedUpdateCount = 0));
- isCommitting$1 = isWorking = !0;
- invariant(
- root.current !== finishedWork$jscomp$0,
- "Cannot commit the same tree as before. This is probably a bug related to the return field. This error is likely caused by a bug in React. Please file an issue."
- );
- expirationTime = root.pendingCommitExpirationTime;
- invariant(
- 0 !== expirationTime,
- "Cannot commit an incomplete root. This error is likely caused by a bug in React. Please file an issue."
- );
- root.pendingCommitExpirationTime = 0;
- firstBatch = finishedWork$jscomp$0.expirationTime;
- var childExpirationTimeBeforeCommit =
- finishedWork$jscomp$0.childExpirationTime;
- firstBatch =
- childExpirationTimeBeforeCommit > firstBatch
- ? childExpirationTimeBeforeCommit
- : firstBatch;
- root.didError = !1;
- 0 === firstBatch
- ? ((root.earliestPendingTime = 0),
- (root.latestPendingTime = 0),
- (root.earliestSuspendedTime = 0),
- (root.latestSuspendedTime = 0),
- (root.latestPingedTime = 0))
- : ((childExpirationTimeBeforeCommit = root.latestPendingTime),
- 0 !== childExpirationTimeBeforeCommit &&
- (childExpirationTimeBeforeCommit > firstBatch
- ? (root.earliestPendingTime = root.latestPendingTime = 0)
- : root.earliestPendingTime > firstBatch &&
- (root.earliestPendingTime = root.latestPendingTime)),
- (childExpirationTimeBeforeCommit = root.earliestSuspendedTime),
- 0 === childExpirationTimeBeforeCommit
- ? markPendingPriorityLevel(root, firstBatch)
- : firstBatch < root.latestSuspendedTime
- ? ((root.earliestSuspendedTime = 0),
- (root.latestSuspendedTime = 0),
- (root.latestPingedTime = 0),
- markPendingPriorityLevel(root, firstBatch))
- : firstBatch > childExpirationTimeBeforeCommit &&
- markPendingPriorityLevel(root, firstBatch));
- findNextExpirationTimeToWorkOn(0, root);
- ReactCurrentOwner$2.current = null;
- 1 < finishedWork$jscomp$0.effectTag
- ? null !== finishedWork$jscomp$0.lastEffect
- ? ((finishedWork$jscomp$0.lastEffect.nextEffect = finishedWork$jscomp$0),
- (firstBatch = finishedWork$jscomp$0.firstEffect))
- : (firstBatch = finishedWork$jscomp$0)
- : (firstBatch = finishedWork$jscomp$0.firstEffect);
- for (nextEffect = firstBatch; null !== nextEffect; ) {
- childExpirationTimeBeforeCommit = !1;
- var error = void 0;
- try {
- for (; null !== nextEffect; ) {
- if (nextEffect.effectTag & 256)
- a: {
- var current$$1 = nextEffect.alternate,
- finishedWork = nextEffect;
- switch (finishedWork.tag) {
- case 0:
- case 11:
- case 15:
- break a;
- case 1:
- if (finishedWork.effectTag & 256 && null !== current$$1) {
- var prevProps = current$$1.memoizedProps,
- prevState = current$$1.memoizedState,
- instance = finishedWork.stateNode,
- snapshot = instance.getSnapshotBeforeUpdate(
- finishedWork.elementType === finishedWork.type
- ? prevProps
- : resolveDefaultProps(finishedWork.type, prevProps),
- prevState
- );
- instance.__reactInternalSnapshotBeforeUpdate = snapshot;
- }
- break a;
- case 3:
- case 5:
- case 6:
- case 4:
- case 17:
- break a;
- default:
- invariant(
- !1,
- "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue."
- );
- }
- }
- nextEffect = nextEffect.nextEffect;
- }
- } catch (e) {
- (childExpirationTimeBeforeCommit = !0), (error = e);
- }
- childExpirationTimeBeforeCommit &&
- (invariant(
- null !== nextEffect,
- "Should have next effect. This error is likely caused by a bug in React. Please file an issue."
- ),
- captureCommitPhaseError(nextEffect, error),
- null !== nextEffect && (nextEffect = nextEffect.nextEffect));
- }
- for (nextEffect = firstBatch; null !== nextEffect; ) {
- current$$1 = !1;
- prevProps = void 0;
- try {
- for (; null !== nextEffect; ) {
- var effectTag = nextEffect.effectTag;
- if (effectTag & 128) {
- var current$$1$jscomp$0 = nextEffect.alternate;
- if (null !== current$$1$jscomp$0) {
- var currentRef = current$$1$jscomp$0.ref;
- null !== currentRef &&
- ("function" === typeof currentRef
- ? currentRef(null)
- : (currentRef.current = null));
- }
- }
- switch (effectTag & 14) {
- case 2:
- commitPlacement(nextEffect);
- nextEffect.effectTag &= -3;
- break;
- case 6:
- commitPlacement(nextEffect);
- nextEffect.effectTag &= -3;
- commitWork(nextEffect.alternate, nextEffect);
- break;
- case 4:
- commitWork(nextEffect.alternate, nextEffect);
- break;
- case 8:
- prevState = nextEffect;
- unmountHostComponents(prevState);
- prevState.return = null;
- prevState.child = null;
- prevState.memoizedState = null;
- prevState.updateQueue = null;
- var alternate = prevState.alternate;
- null !== alternate &&
- ((alternate.return = null),
- (alternate.child = null),
- (alternate.memoizedState = null),
- (alternate.updateQueue = null));
- }
- nextEffect = nextEffect.nextEffect;
- }
- } catch (e) {
- (current$$1 = !0), (prevProps = e);
- }
- current$$1 &&
- (invariant(
- null !== nextEffect,
- "Should have next effect. This error is likely caused by a bug in React. Please file an issue."
- ),
- captureCommitPhaseError(nextEffect, prevProps),
- null !== nextEffect && (nextEffect = nextEffect.nextEffect));
- }
- root.current = finishedWork$jscomp$0;
- for (nextEffect = firstBatch; null !== nextEffect; ) {
- effectTag = !1;
- current$$1$jscomp$0 = void 0;
- try {
- for (currentRef = expirationTime; null !== nextEffect; ) {
- var effectTag$jscomp$0 = nextEffect.effectTag;
- if (effectTag$jscomp$0 & 36) {
- var current$$1$jscomp$1 = nextEffect.alternate;
- alternate = nextEffect;
- current$$1 = currentRef;
- switch (alternate.tag) {
- case 0:
- case 11:
- case 15:
- break;
- case 1:
- var instance$jscomp$0 = alternate.stateNode;
- if (alternate.effectTag & 4)
- if (null === current$$1$jscomp$1)
- instance$jscomp$0.componentDidMount();
- else {
- var prevProps$jscomp$0 =
- alternate.elementType === alternate.type
- ? current$$1$jscomp$1.memoizedProps
- : resolveDefaultProps(
- alternate.type,
- current$$1$jscomp$1.memoizedProps
- );
- instance$jscomp$0.componentDidUpdate(
- prevProps$jscomp$0,
- current$$1$jscomp$1.memoizedState,
- instance$jscomp$0.__reactInternalSnapshotBeforeUpdate
- );
- }
- var updateQueue = alternate.updateQueue;
- null !== updateQueue &&
- commitUpdateQueue(
- alternate,
- updateQueue,
- instance$jscomp$0,
- current$$1
- );
- break;
- case 3:
- var _updateQueue = alternate.updateQueue;
- if (null !== _updateQueue) {
- prevProps = null;
- if (null !== alternate.child)
- switch (alternate.child.tag) {
- case 5:
- prevProps = alternate.child.stateNode;
- break;
- case 1:
- prevProps = alternate.child.stateNode;
+ scheduler.unstable_runWithPriority(
+ scheduler.unstable_ImmediatePriority,
+ function() {
+ commitRoot(root, finishedWork);
}
- commitUpdateQueue(
- alternate,
- _updateQueue,
- prevProps,
- current$$1
);
- }
- break;
- case 5:
- break;
- case 6:
- break;
- case 4:
- break;
- case 12:
- break;
- case 13:
- break;
- case 17:
- break;
- default:
- invariant(
- !1,
- "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue."
- );
- }
- }
- if (effectTag$jscomp$0 & 128) {
- var ref = nextEffect.ref;
- if (null !== ref) {
- var instance$jscomp$1 = nextEffect.stateNode;
- switch (nextEffect.tag) {
- case 5:
- var instanceToUse = instance$jscomp$1;
- break;
- default:
- instanceToUse = instance$jscomp$1;
- }
- "function" === typeof ref
- ? ref(instanceToUse)
- : (ref.current = instanceToUse);
- }
- }
- nextEffect = nextEffect.nextEffect;
- }
- } catch (e) {
- (effectTag = !0), (current$$1$jscomp$0 = e);
- }
- effectTag &&
- (invariant(
- null !== nextEffect,
- "Should have next effect. This error is likely caused by a bug in React. Please file an issue."
- ),
- captureCommitPhaseError(nextEffect, current$$1$jscomp$0),
- null !== nextEffect && (nextEffect = nextEffect.nextEffect));
- }
- isWorking = isCommitting$1 = !1;
- "function" === typeof onCommitFiberRoot &&
- onCommitFiberRoot(finishedWork$jscomp$0.stateNode);
- effectTag$jscomp$0 = finishedWork$jscomp$0.expirationTime;
- finishedWork$jscomp$0 = finishedWork$jscomp$0.childExpirationTime;
- finishedWork$jscomp$0 =
- finishedWork$jscomp$0 > effectTag$jscomp$0
- ? finishedWork$jscomp$0
- : effectTag$jscomp$0;
- 0 === finishedWork$jscomp$0 &&
- (legacyErrorBoundariesThatAlreadyFailed = null);
- root.expirationTime = finishedWork$jscomp$0;
- root.finishedWork = null;
}
function onUncaughtError(error) {
invariant(
@@ -6465,18 +7142,20 @@
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
);
}
@@ -6485,6 +7164,21 @@
})(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) {
@@ -6493,6 +7187,7 @@
current: root,
containerInfo: containerTag,
pendingChildren: null,
+ pingCache: null,
earliestPendingTime: 0,
latestPendingTime: 0,
earliestSuspendedTime: 0,
@@ -6574,17 +7269,20 @@
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
);
}
@@ -6608,6 +7306,8 @@
var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance;
return injectInternals(
Object.assign({}, devToolsConfig, {
+ overrideProps: null,
+ currentDispatcherRef: ReactSharedInternals.ReactCurrentDispatcher,
findHostInstanceByFiber: function(fiber) {
fiber = findCurrentHostFiber(fiber);
return null === fiber ? null : fiber.stateNode;
@@ -6623,7 +7323,7 @@
findFiberByHostInstance: getInstanceFromTag,
getInspectorDataForViewTag: getInspectorDataForViewTag,
bundleType: 0,
- version: "16.6.1",
+ version: "16.8.3",
rendererPackageName: "react-native-renderer"
});
var ReactNativeRenderer$2 = { default: ReactNativeRenderer },

Libraries/Renderer/oss/ReactNativeRenderer-profiling.js

@@ -1130,8 +1130,10 @@
}
});
var ReactSharedInternals =
- React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
- hasSymbol = "function" === typeof Symbol && Symbol.for,
+ React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
+ReactSharedInternals.hasOwnProperty("ReactCurrentDispatcher") ||
+ (ReactSharedInternals.ReactCurrentDispatcher = { current: null });
+var hasSymbol = "function" === typeof Symbol && Symbol.for,
REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for("react.element") : 60103,
REACT_PORTAL_TYPE = hasSymbol ? Symbol.for("react.portal") : 60106,
REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for("react.fragment") : 60107,
@@ -1599,6 +1601,10 @@
scheduledCallback = null;
null !== callback && callback();
}
+function scheduleDeferredCallback$1(callback) {
+ scheduledCallback = callback;
+ return setTimeout(setTimeoutCallback, 1);
+}
function shim$1() {
invariant(
!1,
@@ -1632,8 +1638,24 @@
return !1;
}
var scheduleTimeout = setTimeout,
- cancelTimeout = clearTimeout,
- BEFORE_SLASH_RE = /^(.*)[\\\/]/;
+ cancelTimeout = clearTimeout;
+function commitUpdate(instance, updatePayloadTODO, type, oldProps, newProps) {
+ updatePayloadTODO = instance.viewConfig;
+ instanceProps[instance._nativeTag] = newProps;
+ oldProps = diffProperties(
+ null,
+ oldProps,
+ newProps,
+ updatePayloadTODO.validAttributes
+ );
+ null != oldProps &&
+ UIManager.updateView(
+ instance._nativeTag,
+ updatePayloadTODO.uiViewClassName,
+ oldProps
+ );
+}
+var BEFORE_SLASH_RE = /^(.*)[\\\/]/;
function getStackByFiberInDevAndProd(workInProgress) {
var info = "";
do {
@@ -1799,7 +1821,7 @@
this.index = 0;
this.ref = null;
this.pendingProps = pendingProps;
- this.firstContextDependency = this.memoizedState = this.updateQueue = this.memoizedProps = null;
+ this.contextDependencies = this.memoizedState = this.updateQueue = this.memoizedProps = null;
this.mode = mode;
this.effectTag = 0;
this.lastEffect = this.firstEffect = this.nextEffect = null;
@@ -1853,7 +1875,7 @@
workInProgress.memoizedProps = current.memoizedProps;
workInProgress.memoizedState = current.memoizedState;
workInProgress.updateQueue = current.updateQueue;
- workInProgress.firstContextDependency = current.firstContextDependency;
+ workInProgress.contextDependencies = current.contextDependencies;
workInProgress.sibling = current.sibling;
workInProgress.index = current.index;
workInProgress.ref = current.ref;
@@ -1988,6 +2010,8 @@
(root.latestSuspendedTime = 0),
(root.latestPingedTime = 0);
else {
+ earliestRemainingTime < root.latestPingedTime &&
+ (root.latestPingedTime = 0);
var latestPendingTime = root.latestPendingTime;
0 !== latestPendingTime &&
(latestPendingTime > earliestRemainingTime
@@ -2020,24 +2044,21 @@
}
function markSuspendedPriorityLevel(root, suspendedTime) {
root.didError = !1;
- var latestPingedTime = root.latestPingedTime;
- 0 !== latestPingedTime &&
- latestPingedTime >= suspendedTime &&
- (root.latestPingedTime = 0);
- latestPingedTime = root.earliestPendingTime;
- var latestPendingTime = root.latestPendingTime;
- latestPingedTime === suspendedTime
+ root.latestPingedTime >= suspendedTime && (root.latestPingedTime = 0);
+ var earliestPendingTime = root.earliestPendingTime,
+ latestPendingTime = root.latestPendingTime;
+ earliestPendingTime === suspendedTime
? (root.earliestPendingTime =
latestPendingTime === suspendedTime
? (root.latestPendingTime = 0)
: latestPendingTime)
: latestPendingTime === suspendedTime &&
- (root.latestPendingTime = latestPingedTime);
- latestPingedTime = root.earliestSuspendedTime;
+ (root.latestPendingTime = earliestPendingTime);
+ earliestPendingTime = root.earliestSuspendedTime;
latestPendingTime = root.latestSuspendedTime;
- 0 === latestPingedTime
+ 0 === earliestPendingTime
? (root.earliestSuspendedTime = root.latestSuspendedTime = suspendedTime)
- : latestPingedTime < suspendedTime
+ : earliestPendingTime < suspendedTime
? (root.earliestSuspendedTime = suspendedTime)
: latestPendingTime > suspendedTime &&
(root.latestSuspendedTime = suspendedTime);
@@ -2069,338 +2090,10 @@
root.nextExpirationTimeToWorkOn = earliestPendingTime;
root.expirationTime = completedExpirationTime;
}
-var hasForceUpdate = !1;
-function createUpdateQueue(baseState) {
- return {
- baseState: baseState,
- firstUpdate: null,
- lastUpdate: null,
- firstCapturedUpdate: null,
- lastCapturedUpdate: null,
- firstEffect: null,
- lastEffect: null,
- firstCapturedEffect: null,
- lastCapturedEffect: null
- };
-}
-function cloneUpdateQueue(currentQueue) {
- return {
- baseState: currentQueue.baseState,
- firstUpdate: currentQueue.firstUpdate,
- lastUpdate: currentQueue.lastUpdate,
- firstCapturedUpdate: null,
- lastCapturedUpdate: null,
- firstEffect: null,
- lastEffect: null,
- firstCapturedEffect: null,
- lastCapturedEffect: null
- };
-}
-function createUpdate(expirationTime) {
- return {
- expirationTime: expirationTime,
- tag: 0,
- payload: null,
- callback: null,
- next: null,
- nextEffect: null
- };
-}
-function appendUpdateToQueue(queue, update) {
- null === queue.lastUpdate
- ? (queue.firstUpdate = queue.lastUpdate = update)
- : ((queue.lastUpdate.next = update), (queue.lastUpdate = update));
-}
-function enqueueUpdate(fiber, update) {
- var alternate = fiber.alternate;
- if (null === alternate) {
- var queue1 = fiber.updateQueue;
- var queue2 = null;
- null === queue1 &&
- (queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState));
- } else
- (queue1 = fiber.updateQueue),
- (queue2 = alternate.updateQueue),
- null === queue1
- ? null === queue2
- ? ((queue1 = fiber.updateQueue = createUpdateQueue(
- fiber.memoizedState
- )),
- (queue2 = alternate.updateQueue = createUpdateQueue(
- alternate.memoizedState
- )))
- : (queue1 = fiber.updateQueue = cloneUpdateQueue(queue2))
- : null === queue2 &&
- (queue2 = alternate.updateQueue = cloneUpdateQueue(queue1));
- null === queue2 || queue1 === queue2
- ? appendUpdateToQueue(queue1, update)
- : null === queue1.lastUpdate || null === queue2.lastUpdate
- ? (appendUpdateToQueue(queue1, update),
- appendUpdateToQueue(queue2, update))
- : (appendUpdateToQueue(queue1, update), (queue2.lastUpdate = update));
-}
-function enqueueCapturedUpdate(workInProgress, update) {
- var workInProgressQueue = workInProgress.updateQueue;
- workInProgressQueue =
- null === workInProgressQueue
- ? (workInProgress.updateQueue = createUpdateQueue(
- workInProgress.memoizedState
- ))
- : ensureWorkInProgressQueueIsAClone(workInProgress, workInProgressQueue);
- null === workInProgressQueue.lastCapturedUpdate
- ? (workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update)
- : ((workInProgressQueue.lastCapturedUpdate.next = update),
- (workInProgressQueue.lastCapturedUpdate = update));
-}
-function ensureWorkInProgressQueueIsAClone(workInProgress, queue) {
- var current = workInProgress.alternate;
- null !== current &&
- queue === current.updateQueue &&
- (queue = workInProgress.updateQueue = cloneUpdateQueue(queue));
- return queue;
-}
-function getStateFromUpdate(
- workInProgress,
- queue,
- update,
- prevState,
- nextProps,
- instance
-) {
- switch (update.tag) {
- case 1:
- return (
- (workInProgress = update.payload),
- "function" === typeof workInProgress
- ? workInProgress.call(instance, prevState, nextProps)
- : workInProgress
- );
- case 3:
- workInProgress.effectTag = (workInProgress.effectTag & -2049) | 64;
- case 0:
- workInProgress = update.payload;
- nextProps =
- "function" === typeof workInProgress
- ? workInProgress.call(instance, prevState, nextProps)
- : workInProgress;
- if (null === nextProps || void 0 === nextProps) break;
- return Object.assign({}, prevState, nextProps);
- case 2:
- hasForceUpdate = !0;
- }
- return prevState;
-}
-function processUpdateQueue(
- workInProgress,
- queue,
- props,
- instance,
- renderExpirationTime
-) {
- hasForceUpdate = !1;
- queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue);
- for (
- var newBaseState = queue.baseState,
- newFirstUpdate = null,
- newExpirationTime = 0,
- update = queue.firstUpdate,
- resultState = newBaseState;
- null !== update;
-
- ) {
- var updateExpirationTime = update.expirationTime;
- updateExpirationTime < renderExpirationTime
- ? (null === newFirstUpdate &&
- ((newFirstUpdate = update), (newBaseState = resultState)),
- newExpirationTime < updateExpirationTime &&
- (newExpirationTime = updateExpirationTime))
- : ((resultState = getStateFromUpdate(
- workInProgress,
- queue,
- update,
- resultState,
- props,
- instance
- )),
- null !== update.callback &&
- ((workInProgress.effectTag |= 32),
- (update.nextEffect = null),
- null === queue.lastEffect
- ? (queue.firstEffect = queue.lastEffect = update)
- : ((queue.lastEffect.nextEffect = update),
- (queue.lastEffect = update))));
- update = update.next;
- }
- updateExpirationTime = null;
- for (update = queue.firstCapturedUpdate; null !== update; ) {
- var _updateExpirationTime = update.expirationTime;
- _updateExpirationTime < renderExpirationTime
- ? (null === updateExpirationTime &&
- ((updateExpirationTime = update),
- null === newFirstUpdate && (newBaseState = resultState)),
- newExpirationTime < _updateExpirationTime &&
- (newExpirationTime = _updateExpirationTime))
- : ((resultState = getStateFromUpdate(
- workInProgress,
- queue,
- update,
- resultState,
- props,
- instance
- )),
- null !== update.callback &&
- ((workInProgress.effectTag |= 32),
- (update.nextEffect = null),
- null === queue.lastCapturedEffect
- ? (queue.firstCapturedEffect = queue.lastCapturedEffect = update)
- : ((queue.lastCapturedEffect.nextEffect = update),
- (queue.lastCapturedEffect = update))));
- update = update.next;
- }
- null === newFirstUpdate && (queue.lastUpdate = null);
- null === updateExpirationTime
- ? (queue.lastCapturedUpdate = null)
- : (workInProgress.effectTag |= 32);
- null === newFirstUpdate &&
- null === updateExpirationTime &&
- (newBaseState = resultState);
- queue.baseState = newBaseState;
- queue.firstUpdate = newFirstUpdate;
- queue.firstCapturedUpdate = updateExpirationTime;
- workInProgress.expirationTime = newExpirationTime;
- workInProgress.memoizedState = resultState;
-}
-function commitUpdateQueue(finishedWork, finishedQueue, instance) {
- null !== finishedQueue.firstCapturedUpdate &&
- (null !== finishedQueue.lastUpdate &&
- ((finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate),
- (finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate)),
- (finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null));
- commitUpdateEffects(finishedQueue.firstEffect, instance);
- finishedQueue.firstEffect = finishedQueue.lastEffect = null;
- commitUpdateEffects(finishedQueue.firstCapturedEffect, instance);
- finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null;
-}
-function commitUpdateEffects(effect, instance) {
- for (; null !== effect; ) {
- var _callback3 = effect.callback;
- if (null !== _callback3) {
- effect.callback = null;
- var context = instance;
- invariant(
- "function" === typeof _callback3,
- "Invalid argument passed as callback. Expected a function. Instead received: %s",
- _callback3
- );
- _callback3.call(context);
- }
- effect = effect.nextEffect;
- }
-}
-function createCapturedValue(value, source) {
- return {
- value: value,
- source: source,
- stack: getStackByFiberInDevAndProd(source)
- };
-}
-var valueCursor = { current: null },
- currentlyRenderingFiber = null,
- lastContextDependency = null,
- lastContextWithAllBitsObserved = null;
-function pushProvider(providerFiber, nextValue) {
- var context = providerFiber.type._context;
- push(valueCursor, context._currentValue, providerFiber);
- context._currentValue = nextValue;
-}
-function popProvider(providerFiber) {
- var currentValue = valueCursor.current;
- pop(valueCursor, providerFiber);
- providerFiber.type._context._currentValue = currentValue;
-}
-function prepareToReadContext(workInProgress) {
- currentlyRenderingFiber = workInProgress;
- lastContextWithAllBitsObserved = lastContextDependency = null;
- workInProgress.firstContextDependency = null;
-}
-function readContext(context, observedBits) {
- if (
- lastContextWithAllBitsObserved !== context &&
- !1 !== observedBits &&
- 0 !== observedBits
- ) {
- if ("number" !== typeof observedBits || 1073741823 === observedBits)
- (lastContextWithAllBitsObserved = context), (observedBits = 1073741823);
- observedBits = { context: context, observedBits: observedBits, next: null };
- null === lastContextDependency
- ? (invariant(
- null !== currentlyRenderingFiber,
- "Context can only be read while React is rendering, e.g. inside the render method or getDerivedStateFromProps."
- ),
- (currentlyRenderingFiber.firstContextDependency = lastContextDependency = observedBits))
- : (lastContextDependency = lastContextDependency.next = observedBits);
- }
- return context._currentValue;
-}
-var NO_CONTEXT = {},
- contextStackCursor$1 = { current: NO_CONTEXT },
- contextFiberStackCursor = { current: NO_CONTEXT },
- rootInstanceStackCursor = { current: NO_CONTEXT };
-function requiredContext(c) {
- invariant(
- c !== NO_CONTEXT,
- "Expected host context to exist. This error is likely caused by a bug in React. Please file an issue."
- );
- return c;
-}
-function pushHostContainer(fiber, nextRootInstance) {
- push(rootInstanceStackCursor, nextRootInstance, fiber);
- push(contextFiberStackCursor, fiber, fiber);
- push(contextStackCursor$1, NO_CONTEXT, fiber);
- pop(contextStackCursor$1, fiber);
- push(contextStackCursor$1, { isInAParentText: !1 }, fiber);
-}
-function popHostContainer(fiber) {
- pop(contextStackCursor$1, fiber);
- pop(contextFiberStackCursor, fiber);
- pop(rootInstanceStackCursor, fiber);
-}
-function pushHostContext(fiber) {
- requiredContext(rootInstanceStackCursor.current);
- var context = requiredContext(contextStackCursor$1.current);
- var nextContext = fiber.type;
- nextContext =
- "AndroidTextInput" === nextContext ||
- "RCTMultilineTextInputView" === nextContext ||
- "RCTSinglelineTextInputView" === nextContext ||
- "RCTText" === nextContext ||
- "RCTVirtualText" === nextContext;
- nextContext =
- context.isInAParentText !== nextContext
- ? { isInAParentText: nextContext }
- : context;
- context !== nextContext &&
- (push(contextFiberStackCursor, fiber, fiber),
- push(contextStackCursor$1, nextContext, fiber));
-}
-function popHostContext(fiber) {
- contextFiberStackCursor.current === fiber &&
- (pop(contextStackCursor$1, fiber), pop(contextFiberStackCursor, fiber));
-}
-var commitTime = 0,
- profilerStartTime = -1;
-function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) {
- if (0 <= profilerStartTime) {
- var elapsedTime = now$1() - profilerStartTime;
- fiber.actualDuration += elapsedTime;
- overrideBaseTime && (fiber.selfBaseDuration = elapsedTime);
- profilerStartTime = -1;
- }
-}
-var hasOwnProperty = Object.prototype.hasOwnProperty;
function is(x, y) {
- return x === y ? 0 !== x || 0 !== y || 1 / x === 1 / y : x !== x && y !== y;
+ return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y);
}
+var hasOwnProperty = Object.prototype.hasOwnProperty;
function shallowEqual(objA, objB) {
if (is(objA, objB)) return !0;
if (
@@ -2441,9 +2134,9 @@
case 0:
throw result;
default:
- throw ((lazyComponent._status = 0),
- (result = lazyComponent._ctor),
- (result = result()),
+ lazyComponent._status = 0;
+ result = lazyComponent._ctor;
+ result = result();
result.then(
function(moduleObject) {
0 === lazyComponent._status &&
@@ -2455,13 +2148,18 @@
0 === lazyComponent._status &&
((lazyComponent._status = 2), (lazyComponent._result = error));
}
- ),
- (lazyComponent._result = result),
- result);
+ );
+ switch (lazyComponent._status) {
+ case 1:
+ return lazyComponent._result;
+ case 2:
+ throw lazyComponent._result;
+ }
+ lazyComponent._result = result;
+ throw result;
}
}
-var ReactCurrentOwner$4 = ReactSharedInternals.ReactCurrentOwner,
- emptyRefsObject = new React.Component().refs;
+var emptyRefsObject = new React.Component().refs;
function applyDerivedStateFromProps(
workInProgress,
ctor,
@@ -2502,7 +2200,7 @@
var currentTime = requestCurrentTime();
currentTime = computeExpirationForFiber(currentTime, inst);
var update = createUpdate(currentTime);
- update.tag = 1;
+ update.tag = ReplaceState;
update.payload = payload;
void 0 !== callback && null !== callback && (update.callback = callback);
flushPassiveEffects();
@@ -2514,7 +2212,7 @@
var currentTime = requestCurrentTime();
currentTime = computeExpirationForFiber(currentTime, inst);
var update = createUpdate(currentTime);
- update.tag = 2;
+ update.tag = ForceUpdate;
void 0 !== callback && null !== callback && (update.callback = callback);
flushPassiveEffects();
enqueueUpdate(inst, update);
@@ -2542,7 +2240,7 @@
unmaskedContext = emptyContextObject;
var context = ctor.contextType;
"object" === typeof context && null !== context
- ? (context = ReactCurrentOwner$4.currentDispatcher.readContext(context))
+ ? (context = readContext(context))
: ((unmaskedContext = isContextProvider(ctor)
? previousContext
: contextStackCursor.current),
@@ -2589,9 +2287,7 @@
instance.refs = emptyRefsObject;
var contextType = ctor.contextType;
"object" === typeof contextType && null !== contextType
- ? (instance.context = ReactCurrentOwner$4.currentDispatcher.readContext(
- contextType
- ))
+ ? (instance.context = readContext(contextType))
: ((contextType = isContextProvider(ctor)
? previousContext
: contextStackCursor.current),
@@ -2646,7 +2342,10 @@
element = element._owner;
var inst = void 0;
element &&
- (invariant(1 === element.tag, "Function components cannot have refs."),
+ (invariant(
+ 1 === element.tag,
+ "Function components cannot have refs. Did you mean to use React.forwardRef()?"
+ ),
(inst = element.stateNode));
invariant(
inst,
@@ -3346,7 +3045,523 @@
}
var reconcileChildFibers = ChildReconciler(!0),
mountChildFibers = ChildReconciler(!1),
- hydrationParentFiber = null,
+ NO_CONTEXT = {},
+ contextStackCursor$1 = { current: NO_CONTEXT },
+ contextFiberStackCursor = { current: NO_CONTEXT },
+ rootInstanceStackCursor = { current: NO_CONTEXT };
+function requiredContext(c) {
+ invariant(
+ c !== NO_CONTEXT,
+ "Expected host context to exist. This error is likely caused by a bug in React. Please file an issue."
+ );
+ return c;
+}
+function pushHostContainer(fiber, nextRootInstance) {
+ push(rootInstanceStackCursor, nextRootInstance, fiber);
+ push(contextFiberStackCursor, fiber, fiber);
+ push(contextStackCursor$1, NO_CONTEXT, fiber);
+ pop(contextStackCursor$1, fiber);
+ push(contextStackCursor$1, { isInAParentText: !1 }, fiber);
+}
+function popHostContainer(fiber) {
+ pop(contextStackCursor$1, fiber);
+ pop(contextFiberStackCursor, fiber);
+ pop(rootInstanceStackCursor, fiber);
+}
+function pushHostContext(fiber) {
+ requiredContext(rootInstanceStackCursor.current);
+ var context = requiredContext(contextStackCursor$1.current);
+ var nextContext = fiber.type;
+ nextContext =
+ "AndroidTextInput" === nextContext ||
+ "RCTMultilineTextInputView" === nextContext ||
+ "RCTSinglelineTextInputView" === nextContext ||
+ "RCTText" === nextContext ||
+ "RCTVirtualText" === nextContext;
+ nextContext =
+ context.isInAParentText !== nextContext
+ ? { isInAParentText: nextContext }
+ : context;
+ context !== nextContext &&
+ (push(contextFiberStackCursor, fiber, fiber),
+ push(contextStackCursor$1, nextContext, fiber));
+}
+function popHostContext(fiber) {
+ contextFiberStackCursor.current === fiber &&
+ (pop(contextStackCursor$1, fiber), pop(contextFiberStackCursor, fiber));
+}
+var NoEffect$1 = 0,
+ UnmountSnapshot = 2,
+ UnmountMutation = 4,
+ MountMutation = 8,
+ UnmountLayout = 16,
+ MountLayout = 32,
+ MountPassive = 64,
+ UnmountPassive = 128,
+ ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher,
+ renderExpirationTime = 0,
+ currentlyRenderingFiber$1 = null,
+ currentHook = null,
+ nextCurrentHook = null,
+ firstWorkInProgressHook = null,
+ workInProgressHook = null,
+ nextWorkInProgressHook = null,
+ remainingExpirationTime = 0,
+ componentUpdateQueue = null,
+ sideEffectTag = 0,
+ didScheduleRenderPhaseUpdate = !1,
+ renderPhaseUpdates = null,
+ numberOfReRenders = 0;
+function throwInvalidHookError() {
+ invariant(
+ !1,
+ "Hooks can only be called inside the body of a function component. (https://fb.me/react-invalid-hook-call)"
+ );
+}
+function areHookInputsEqual(nextDeps, prevDeps) {
+ if (null === prevDeps) return !1;
+ for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++)
+ if (!is(nextDeps[i], prevDeps[i])) return !1;
+ return !0;
+}
+function renderWithHooks(
+ current,
+ workInProgress,
+ Component,
+ props,
+ refOrContext,
+ nextRenderExpirationTime
+) {
+ renderExpirationTime = nextRenderExpirationTime;
+ currentlyRenderingFiber$1 = workInProgress;
+ nextCurrentHook = null !== current ? current.memoizedState : null;
+ ReactCurrentDispatcher$1.current =
+ null === nextCurrentHook ? HooksDispatcherOnMount : HooksDispatcherOnUpdate;
+ workInProgress = Component(props, refOrContext);
+ if (didScheduleRenderPhaseUpdate) {
+ do
+ (didScheduleRenderPhaseUpdate = !1),
+ (numberOfReRenders += 1),
+ (nextCurrentHook = null !== current ? current.memoizedState : null),
+ (nextWorkInProgressHook = firstWorkInProgressHook),
+ (componentUpdateQueue = workInProgressHook = currentHook = null),
+ (ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdate),
+ (workInProgress = Component(props, refOrContext));
+ while (didScheduleRenderPhaseUpdate);
+ renderPhaseUpdates = null;
+ numberOfReRenders = 0;
+ }
+ ReactCurrentDispatcher$1.current = ContextOnlyDispatcher;
+ current = currentlyRenderingFiber$1;
+ current.memoizedState = firstWorkInProgressHook;
+ current.expirationTime = remainingExpirationTime;
+ current.updateQueue = componentUpdateQueue;
+ current.effectTag |= sideEffectTag;
+ current = null !== currentHook && null !== currentHook.next;
+ renderExpirationTime = 0;
+ nextWorkInProgressHook = workInProgressHook = firstWorkInProgressHook = nextCurrentHook = currentHook = currentlyRenderingFiber$1 = null;
+ remainingExpirationTime = 0;
+ componentUpdateQueue = null;
+ sideEffectTag = 0;
+ invariant(
+ !current,
+ "Rendered fewer hooks than expected. This may be caused by an accidental early return statement."
+ );
+ return workInProgress;
+}
+function resetHooks() {
+ ReactCurrentDispatcher$1.current = ContextOnlyDispatcher;
+ renderExpirationTime = 0;
+ nextWorkInProgressHook = workInProgressHook = firstWorkInProgressHook = nextCurrentHook = currentHook = currentlyRenderingFiber$1 = null;
+ remainingExpirationTime = 0;
+ componentUpdateQueue = null;
+ sideEffectTag = 0;
+ didScheduleRenderPhaseUpdate = !1;
+ renderPhaseUpdates = null;
+ numberOfReRenders = 0;
+}
+function mountWorkInProgressHook() {
+ var hook = {
+ memoizedState: null,
+ baseState: null,
+ queue: null,
+ baseUpdate: null,
+ next: null
+ };
+ null === workInProgressHook
+ ? (firstWorkInProgressHook = workInProgressHook = hook)
+ : (workInProgressHook = workInProgressHook.next = hook);
+ return workInProgressHook;
+}
+function updateWorkInProgressHook() {
+ if (null !== nextWorkInProgressHook)
+ (workInProgressHook = nextWorkInProgressHook),
+ (nextWorkInProgressHook = workInProgressHook.next),
+ (currentHook = nextCurrentHook),
+ (nextCurrentHook = null !== currentHook ? currentHook.next : null);
+ else {
+ invariant(
+ null !== nextCurrentHook,
+ "Rendered more hooks than during the previous render."
+ );
+ currentHook = nextCurrentHook;
+ var newHook = {
+ memoizedState: currentHook.memoizedState,
+ baseState: currentHook.baseState,
+ queue: currentHook.queue,
+ baseUpdate: currentHook.baseUpdate,
+ next: null
+ };
+ workInProgressHook =
+ null === workInProgressHook
+ ? (firstWorkInProgressHook = newHook)
+ : (workInProgressHook.next = newHook);
+ nextCurrentHook = currentHook.next;
+ }
+ return workInProgressHook;
+}
+function basicStateReducer(state, action) {
+ return "function" === typeof action ? action(state) : action;
+}
+function updateReducer(reducer) {
+ var hook = updateWorkInProgressHook(),
+ queue = hook.queue;
+ invariant(
+ null !== queue,
+ "Should have a queue. This is likely a bug in React. Please file an issue."
+ );
+ if (0 < numberOfReRenders) {
+ var _dispatch = queue.dispatch;
+ if (null !== renderPhaseUpdates) {
+ var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+ if (void 0 !== firstRenderPhaseUpdate) {
+ renderPhaseUpdates.delete(queue);
+ var newState = hook.memoizedState;
+ do
+ (newState = reducer(newState, firstRenderPhaseUpdate.action)),
+ (firstRenderPhaseUpdate = firstRenderPhaseUpdate.next);
+ while (null !== firstRenderPhaseUpdate);
+ 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];
+ }
+ }
+ return [hook.memoizedState, _dispatch];
+ }
+ _dispatch = queue.last;
+ var baseUpdate = hook.baseUpdate;
+ newState = hook.baseState;
+ null !== baseUpdate
+ ? (null !== _dispatch && (_dispatch.next = null),
+ (_dispatch = baseUpdate.next))
+ : (_dispatch = null !== _dispatch ? _dispatch.next : null);
+ if (null !== _dispatch) {
+ var newBaseUpdate = (firstRenderPhaseUpdate = null),
+ _update = _dispatch,
+ didSkip = !1;
+ do {
+ var updateExpirationTime = _update.expirationTime;
+ updateExpirationTime < renderExpirationTime
+ ? (didSkip ||
+ ((didSkip = !0),
+ (newBaseUpdate = baseUpdate),
+ (firstRenderPhaseUpdate = newState)),
+ updateExpirationTime > remainingExpirationTime &&
+ (remainingExpirationTime = updateExpirationTime))
+ : (newState =
+ _update.eagerReducer === reducer
+ ? _update.eagerState
+ : reducer(newState, _update.action));
+ baseUpdate = _update;
+ _update = _update.next;
+ } while (null !== _update && _update !== _dispatch);
+ didSkip ||
+ ((newBaseUpdate = baseUpdate), (firstRenderPhaseUpdate = newState));
+ is(newState, hook.memoizedState) || (didReceiveUpdate = !0);
+ hook.memoizedState = newState;
+ hook.baseUpdate = newBaseUpdate;
+ hook.baseState = firstRenderPhaseUpdate;
+ queue.eagerReducer = reducer;
+ queue.eagerState = newState;
+ }
+ return [hook.memoizedState, queue.dispatch];
+}
+function pushEffect(tag, create, destroy, deps) {
+ tag = { tag: tag, create: create, destroy: destroy, deps: deps, next: null };
+ null === componentUpdateQueue
+ ? ((componentUpdateQueue = { lastEffect: null }),
+ (componentUpdateQueue.lastEffect = tag.next = tag))
+ : ((create = componentUpdateQueue.lastEffect),
+ null === create
+ ? (componentUpdateQueue.lastEffect = tag.next = tag)
+ : ((destroy = create.next),
+ (create.next = tag),
+ (tag.next = destroy),
+ (componentUpdateQueue.lastEffect = tag)));
+ return tag;
+}
+function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) {
+ var hook = mountWorkInProgressHook();
+ sideEffectTag |= fiberEffectTag;
+ hook.memoizedState = pushEffect(
+ hookEffectTag,
+ create,
+ void 0,
+ void 0 === deps ? null : deps
+ );
+}
+function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) {
+ var hook = updateWorkInProgressHook();
+ deps = void 0 === deps ? null : deps;
+ var destroy = void 0;
+ if (null !== currentHook) {
+ var prevEffect = currentHook.memoizedState;
+ destroy = prevEffect.destroy;
+ if (null !== deps && areHookInputsEqual(deps, prevEffect.deps)) {
+ pushEffect(NoEffect$1, create, destroy, deps);
+ return;
+ }
+ }
+ sideEffectTag |= fiberEffectTag;
+ hook.memoizedState = pushEffect(hookEffectTag, create, destroy, deps);
+}
+function imperativeHandleEffect(create, ref) {
+ if ("function" === typeof ref)
+ return (
+ (create = create()),
+ ref(create),
+ function() {
+ ref(null);
+ }
+ );
+ if (null !== ref && void 0 !== ref)
+ return (
+ (create = create()),
+ (ref.current = create),
+ function() {
+ ref.current = null;
+ }
+ );
+}
+function mountDebugValue() {}
+function dispatchAction(fiber, queue, action) {
+ invariant(
+ 25 > numberOfReRenders,
+ "Too many re-renders. React limits the number of renders to prevent an infinite loop."
+ );
+ var alternate = fiber.alternate;
+ if (
+ fiber === currentlyRenderingFiber$1 ||
+ (null !== alternate && alternate === currentlyRenderingFiber$1)
+ )
+ if (
+ ((didScheduleRenderPhaseUpdate = !0),
+ (fiber = {
+ expirationTime: renderExpirationTime,
+ action: action,
+ eagerReducer: null,
+ eagerState: null,
+ next: null
+ }),
+ null === renderPhaseUpdates && (renderPhaseUpdates = new Map()),
+ (action = renderPhaseUpdates.get(queue)),
+ void 0 === action)
+ )
+ renderPhaseUpdates.set(queue, fiber);
+ else {
+ for (queue = action; null !== queue.next; ) queue = queue.next;
+ queue.next = fiber;
+ }
+ else {
+ flushPassiveEffects();
+ var currentTime = requestCurrentTime();
+ currentTime = computeExpirationForFiber(currentTime, fiber);
+ var _update2 = {
+ expirationTime: currentTime,
+ action: action,
+ eagerReducer: null,
+ eagerState: null,
+ next: null
+ },
+ _last = queue.last;
+ if (null === _last) _update2.next = _update2;
+ else {
+ var first = _last.next;
+ null !== first && (_update2.next = first);
+ _last.next = _update2;
+ }
+ queue.last = _update2;
+ if (
+ 0 === fiber.expirationTime &&
+ (null === alternate || 0 === alternate.expirationTime) &&
+ ((alternate = queue.eagerReducer), null !== alternate)
+ )
+ try {
+ var currentState = queue.eagerState,
+ _eagerState = alternate(currentState, action);
+ _update2.eagerReducer = alternate;
+ _update2.eagerState = _eagerState;
+ if (is(_eagerState, currentState)) return;
+ } catch (error) {
+ } finally {
+ }
+ scheduleWork(fiber, currentTime);
+ }
+}
+var ContextOnlyDispatcher = {
+ readContext: readContext,
+ useCallback: throwInvalidHookError,
+ useContext: throwInvalidHookError,
+ useEffect: throwInvalidHookError,
+ useImperativeHandle: throwInvalidHookError,
+ useLayoutEffect: throwInvalidHookError,
+ useMemo: throwInvalidHookError,
+ useReducer: throwInvalidHookError,
+ useRef: throwInvalidHookError,
+ useState: throwInvalidHookError,
+ useDebugValue: throwInvalidHookError
+ },
+ HooksDispatcherOnMount = {
+ readContext: readContext,
+ useCallback: function(callback, deps) {
+ mountWorkInProgressHook().memoizedState = [
+ callback,
+ void 0 === deps ? null : deps
+ ];
+ return callback;
+ },
+ useContext: readContext,
+ useEffect: function(create, deps) {
+ return mountEffectImpl(516, UnmountPassive | MountPassive, create, deps);
+ },
+ useImperativeHandle: function(ref, create, deps) {
+ deps = null !== deps && void 0 !== deps ? deps.concat([ref]) : null;
+ return mountEffectImpl(
+ 4,
+ UnmountMutation | MountLayout,
+ imperativeHandleEffect.bind(null, create, ref),
+ deps
+ );
+ },
+ useLayoutEffect: function(create, deps) {
+ return mountEffectImpl(4, UnmountMutation | MountLayout, create, deps);
+ },
+ useMemo: function(nextCreate, deps) {
+ var hook = mountWorkInProgressHook();
+ deps = void 0 === deps ? null : deps;
+ nextCreate = nextCreate();
+ hook.memoizedState = [nextCreate, deps];
+ return nextCreate;
+ },
+ useReducer: function(reducer, initialArg, init) {
+ var hook = mountWorkInProgressHook();
+ initialArg = void 0 !== init ? init(initialArg) : initialArg;
+ hook.memoizedState = hook.baseState = initialArg;
+ reducer = hook.queue = {
+ last: null,
+ dispatch: null,
+ eagerReducer: reducer,
+ eagerState: initialArg
+ };
+ reducer = reducer.dispatch = dispatchAction.bind(
+ null,
+ currentlyRenderingFiber$1,
+ reducer
+ );
+ return [hook.memoizedState, reducer];
+ },
+ useRef: function(initialValue) {
+ var hook = mountWorkInProgressHook();
+ initialValue = { current: initialValue };
+ return (hook.memoizedState = initialValue);
+ },
+ useState: function(initialState) {
+ var hook = mountWorkInProgressHook();
+ "function" === typeof initialState && (initialState = initialState());
+ hook.memoizedState = hook.baseState = initialState;
+ initialState = hook.queue = {
+ last: null,
+ dispatch: null,
+ eagerReducer: basicStateReducer,
+ eagerState: initialState
+ };
+ initialState = initialState.dispatch = dispatchAction.bind(
+ null,
+ currentlyRenderingFiber$1,
+ initialState
+ );
+ return [hook.memoizedState, initialState];
+ },
+ useDebugValue: mountDebugValue
+ },
+ HooksDispatcherOnUpdate = {
+ readContext: readContext,
+ useCallback: function(callback, deps) {
+ var hook = updateWorkInProgressHook();
+ deps = void 0 === deps ? null : deps;
+ var prevState = hook.memoizedState;
+ if (
+ null !== prevState &&
+ null !== deps &&
+ areHookInputsEqual(deps, prevState[1])
+ )
+ return prevState[0];
+ hook.memoizedState = [callback, deps];
+ return callback;
+ },
+ useContext: readContext,
+ useEffect: function(create, deps) {
+ return updateEffectImpl(516, UnmountPassive | MountPassive, create, deps);
+ },
+ useImperativeHandle: function(ref, create, deps) {
+ deps = null !== deps && void 0 !== deps ? deps.concat([ref]) : null;
+ return updateEffectImpl(
+ 4,
+ UnmountMutation | MountLayout,
+ imperativeHandleEffect.bind(null, create, ref),
+ deps
+ );
+ },
+ useLayoutEffect: function(create, deps) {
+ return updateEffectImpl(4, UnmountMutation | MountLayout, create, deps);
+ },
+ useMemo: function(nextCreate, deps) {
+ var hook = updateWorkInProgressHook();
+ deps = void 0 === deps ? null : deps;
+ var prevState = hook.memoizedState;
+ if (
+ null !== prevState &&
+ null !== deps &&
+ areHookInputsEqual(deps, prevState[1])
+ )
+ return prevState[0];
+ nextCreate = nextCreate();
+ hook.memoizedState = [nextCreate, deps];
+ return nextCreate;
+ },
+ useReducer: updateReducer,
+ useRef: function() {
+ return updateWorkInProgressHook().memoizedState;
+ },
+ useState: function(initialState) {
+ return updateReducer(basicStateReducer, initialState);
+ },
+ useDebugValue: mountDebugValue
+ },
+ commitTime = 0,
+ profilerStartTime = -1;
+function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) {
+ if (0 <= profilerStartTime) {
+ var elapsedTime = now$1() - profilerStartTime;
+ fiber.actualDuration += elapsedTime;
+ overrideBaseTime && (fiber.selfBaseDuration = elapsedTime);
+ profilerStartTime = -1;
+ }
+}
+var hydrationParentFiber = null,
nextHydratableInstance = null,
isHydrating = !1;
function tryHydrate(fiber, nextInstance) {
@@ -3361,6 +3576,8 @@
(nextInstance = shim$1(nextInstance, fiber.pendingProps)),
null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1
);
+ case 13:
+ return !1;
default:
return !1;
}
@@ -3398,7 +3615,8 @@
(hydrationParentFiber = fiber$jscomp$0);
}
}
-var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner;
+var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner,
+ didReceiveUpdate = !1;
function reconcileChildren(
current$$1,
workInProgress,
@@ -3430,7 +3648,26 @@
Component = Component.render;
var ref = workInProgress.ref;
prepareToReadContext(workInProgress, renderExpirationTime);
- nextProps = Component(nextProps, ref);
+ nextProps = renderWithHooks(
+ current$$1,
+ workInProgress,
+ Component,
+ nextProps,
+ ref,
+ renderExpirationTime
+ );
+ if (null !== current$$1 && !didReceiveUpdate)
+ return (
+ (workInProgress.updateQueue = current$$1.updateQueue),
+ (workInProgress.effectTag &= -517),
+ current$$1.expirationTime <= renderExpirationTime &&
+ (current$$1.expirationTime = 0),
+ bailoutOnAlreadyFinishedWork(
+ current$$1,
+ workInProgress,
+ renderExpirationTime
+ )
+ );
workInProgress.effectTag |= 1;
reconcileChildren(
current$$1,
@@ -3510,9 +3747,9 @@
renderExpirationTime
) {
return null !== current$$1 &&
- updateExpirationTime < renderExpirationTime &&
shallowEqual(current$$1.memoizedProps, nextProps) &&
- current$$1.ref === workInProgress.ref
+ current$$1.ref === workInProgress.ref &&
+ ((didReceiveUpdate = !1), updateExpirationTime < renderExpirationTime)
? bailoutOnAlreadyFinishedWork(
current$$1,
workInProgress,
@@ -3546,7 +3783,26 @@
: contextStackCursor.current;
unmaskedContext = getMaskedContext(workInProgress, unmaskedContext);
prepareToReadContext(workInProgress, renderExpirationTime);
- Component = Component(nextProps, unmaskedContext);
+ Component = renderWithHooks(
+ current$$1,
+ workInProgress,
+ Component,
+ nextProps,
+ unmaskedContext,
+ renderExpirationTime
+ );
+ if (null !== current$$1 && !didReceiveUpdate)
+ return (
+ (workInProgress.updateQueue = current$$1.updateQueue),
+ (workInProgress.effectTag &= -517),
+ current$$1.expirationTime <= renderExpirationTime &&
+ (current$$1.expirationTime = 0),
+ bailoutOnAlreadyFinishedWork(
+ current$$1,
+ workInProgress,
+ renderExpirationTime
+ )
+ );
workInProgress.effectTag |= 1;
reconcileChildren(
current$$1,
@@ -3593,9 +3849,7 @@
var oldContext = instance.context,
contextType = Component.contextType;
"object" === typeof contextType && null !== contextType
- ? (contextType = ReactCurrentOwner$4.currentDispatcher.readContext(
- contextType
- ))
+ ? (contextType = readContext(contextType))
: ((contextType = isContextProvider(Component)
? previousContext
: contextStackCursor.current),
@@ -3680,9 +3934,7 @@
(oldContext = instance.context),
(contextType = Component.contextType),
"object" === typeof contextType && null !== contextType
- ? (contextType = ReactCurrentOwner$4.currentDispatcher.readContext(
- contextType
- ))
+ ? (contextType = readContext(contextType))
: ((contextType = isContextProvider(Component)
? previousContext
: contextStackCursor.current),
@@ -3868,39 +4120,41 @@
(nextDidTimeout = !0),
(workInProgress.effectTag &= -65);
if (null === current$$1)
- nextDidTimeout
- ? ((nextDidTimeout = nextProps.fallback),
- (nextProps = createFiberFromFragment(null, mode, 0, null)),
+ if (nextDidTimeout) {
+ var nextFallbackChildren = nextProps.fallback;
+ current$$1 = createFiberFromFragment(null, mode, 0, null);
0 === (workInProgress.mode & 1) &&
- (nextProps.child =
+ (current$$1.child =
null !== workInProgress.memoizedState
? workInProgress.child.child
- : workInProgress.child),
- (renderExpirationTime = createFiberFromFragment(
- nextDidTimeout,
+ : workInProgress.child);
+ renderExpirationTime = createFiberFromFragment(
+ nextFallbackChildren,
mode,
renderExpirationTime,
null
- )),
- (nextProps.sibling = renderExpirationTime),
- (mode = nextProps),
- (mode.return = renderExpirationTime.return = workInProgress))
- : (mode = renderExpirationTime = mountChildFibers(
+ );
+ current$$1.sibling = renderExpirationTime;
+ mode = current$$1;
+ mode.return = renderExpirationTime.return = workInProgress;
+ } else
+ mode = renderExpirationTime = mountChildFibers(
workInProgress,
null,
nextProps.children,
renderExpirationTime
- ));
- else if (null !== current$$1.memoizedState)
+ );
+ else {
+ if (null !== current$$1.memoizedState)
if (
- ((current$$1 = current$$1.child),
- (mode = current$$1.sibling),
+ ((nextFallbackChildren = current$$1.child),
+ (mode = nextFallbackChildren.sibling),
nextDidTimeout)
) {
nextProps = nextProps.fallback;
renderExpirationTime = createWorkInProgress(
- current$$1,
- current$$1.pendingProps,
+ nextFallbackChildren,
+ nextFallbackChildren.pendingProps,
0
);
0 === (workInProgress.mode & 1) &&
@@ -3908,64 +4162,77 @@
null !== workInProgress.memoizedState
? workInProgress.child.child
: workInProgress.child),
- nextDidTimeout !== current$$1.child &&
+ nextDidTimeout !== nextFallbackChildren.child &&
(renderExpirationTime.child = nextDidTimeout));
if (workInProgress.mode & 4) {
- nextDidTimeout = 0;
- for (current$$1 = renderExpirationTime.child; null !== current$$1; )
- (nextDidTimeout += current$$1.treeBaseDuration),
- (current$$1 = current$$1.sibling);
- renderExpirationTime.treeBaseDuration = nextDidTimeout;
+ nextFallbackChildren = 0;
+ for (
+ nextDidTimeout = renderExpirationTime.child;
+ null !== nextDidTimeout;
+
+ )
+ (nextFallbackChildren += nextDidTimeout.treeBaseDuration),
+ (nextDidTimeout = nextDidTimeout.sibling);
+ renderExpirationTime.treeBaseDuration = nextFallbackChildren;
}
- nextProps = renderExpirationTime.sibling = createWorkInProgress(
+ nextFallbackChildren = renderExpirationTime.sibling = createWorkInProgress(
mode,
nextProps,
mode.expirationTime
);
mode = renderExpirationTime;
renderExpirationTime.childExpirationTime = 0;
- renderExpirationTime = nextProps;
+ renderExpirationTime = nextFallbackChildren;
mode.return = renderExpirationTime.return = workInProgress;
} else
mode = renderExpirationTime = reconcileChildFibers(
workInProgress,
- current$$1.child,
+ nextFallbackChildren.child,
nextProps.children,
renderExpirationTime
);
- else if (((current$$1 = current$$1.child), nextDidTimeout)) {
- nextDidTimeout = nextProps.fallback;
- nextProps = createFiberFromFragment(null, mode, 0, null);
- nextProps.child = current$$1;
+ else {
+ var _currentPrimaryChild = current$$1.child;
+ if (nextDidTimeout) {
+ nextProps = nextProps.fallback;
+ nextFallbackChildren = createFiberFromFragment(null, mode, 0, null);
+ nextFallbackChildren.child = _currentPrimaryChild;
0 === (workInProgress.mode & 1) &&
- (nextProps.child =
+ (nextFallbackChildren.child =
null !== workInProgress.memoizedState
? workInProgress.child.child
: workInProgress.child);
if (workInProgress.mode & 4) {
- current$$1 = 0;
- for (var _hiddenChild = nextProps.child; null !== _hiddenChild; )
- (current$$1 += _hiddenChild.treeBaseDuration),
- (_hiddenChild = _hiddenChild.sibling);
- nextProps.treeBaseDuration = current$$1;
+ nextDidTimeout = 0;
+ for (
+ _currentPrimaryChild = nextFallbackChildren.child;
+ null !== _currentPrimaryChild;
+
+ )
+ (nextDidTimeout += _currentPrimaryChild.treeBaseDuration),
+ (_currentPrimaryChild = _currentPrimaryChild.sibling);
+ nextFallbackChildren.treeBaseDuration = nextDidTimeout;
}
- renderExpirationTime = nextProps.sibling = createFiberFromFragment(
- nextDidTimeout,
+ renderExpirationTime = nextFallbackChildren.sibling = createFiberFromFragment(
+ nextProps,
mode,
renderExpirationTime,
null
);
renderExpirationTime.effectTag |= 2;
- mode = nextProps;
- nextProps.childExpirationTime = 0;
+ mode = nextFallbackChildren;
+ nextFallbackChildren.childExpirationTime = 0;
mode.return = renderExpirationTime.return = workInProgress;
} else
renderExpirationTime = mode = reconcileChildFibers(
workInProgress,
- current$$1,
+ _currentPrimaryChild,
nextProps.children,
renderExpirationTime
);
+ }
+ workInProgress.stateNode = current$$1.stateNode;
+ }
workInProgress.memoizedState = nextState;
workInProgress.child = mode;
return renderExpirationTime;
@@ -3976,7 +4243,7 @@
renderExpirationTime
) {
null !== current$$1 &&
- (workInProgress.firstContextDependency = current$$1.firstContextDependency);
+ (workInProgress.contextDependencies = current$$1.contextDependencies);
profilerStartTime = -1;
if (workInProgress.childExpirationTime < renderExpirationTime) return null;
invariant(
@@ -4009,12 +4276,15 @@
}
function beginWork(current$$1, workInProgress, renderExpirationTime) {
var updateExpirationTime = workInProgress.expirationTime;
+ if (null !== current$$1)
if (
- null !== current$$1 &&
- current$$1.memoizedProps === workInProgress.pendingProps &&
- !didPerformWorkStackCursor.current &&
- updateExpirationTime < renderExpirationTime
- ) {
+ current$$1.memoizedProps !== workInProgress.pendingProps ||
+ didPerformWorkStackCursor.current
+ )
+ didReceiveUpdate = !0;
+ else {
+ if (updateExpirationTime < renderExpirationTime) {
+ didReceiveUpdate = !1;
switch (workInProgress.tag) {
case 3:
pushHostRootContext(workInProgress);
@@ -4064,6 +4334,8 @@
renderExpirationTime
);
}
+ }
+ else didReceiveUpdate = !1;
workInProgress.expirationTime = 0;
switch (workInProgress.tag) {
case 2:
@@ -4078,7 +4350,14 @@
contextStackCursor.current
);
prepareToReadContext(workInProgress, renderExpirationTime);
- context = updateExpirationTime(current$$1, context);
+ context = renderWithHooks(
+ null,
+ workInProgress,
+ updateExpirationTime,
+ current$$1,
+ context,
+ renderExpirationTime
+ );
workInProgress.effectTag |= 1;
if (
"object" === typeof context &&
@@ -4087,6 +4366,7 @@
void 0 === context.$$typeof
) {
workInProgress.tag = 1;
+ resetHooks();
if (isContextProvider(updateExpirationTime)) {
var hasContext = !0;
pushContextProvider(workInProgress);
@@ -4359,13 +4639,9 @@
pushProvider(workInProgress, hasContext);
if (null !== getDerivedStateFromProps) {
var oldValue = getDerivedStateFromProps.value;
- hasContext =
- (oldValue === hasContext &&
- (0 !== oldValue || 1 / oldValue === 1 / hasContext)) ||
- (oldValue !== oldValue && hasContext !== hasContext)
+ hasContext = is(oldValue, hasContext)
? 0
- : ("function" ===
- typeof updateExpirationTime._calculateChangedBits
+ : ("function" === typeof updateExpirationTime._calculateChangedBits
? updateExpirationTime._calculateChangedBits(
oldValue,
hasContext
@@ -4385,83 +4661,79 @@
}
} else
for (
- getDerivedStateFromProps = workInProgress.child,
- null !== getDerivedStateFromProps &&
- (getDerivedStateFromProps.return = workInProgress);
- null !== getDerivedStateFromProps;
+ oldValue = workInProgress.child,
+ null !== oldValue && (oldValue.return = workInProgress);
+ null !== oldValue;
) {
- oldValue = getDerivedStateFromProps.firstContextDependency;
- if (null !== oldValue) {
- do {
+ var list = oldValue.contextDependencies;
+ if (null !== list) {
+ getDerivedStateFromProps = oldValue.child;
+ for (var dependency = list.first; null !== dependency; ) {
if (
- oldValue.context === updateExpirationTime &&
- 0 !== (oldValue.observedBits & hasContext)
+ dependency.context === updateExpirationTime &&
+ 0 !== (dependency.observedBits & hasContext)
) {
- if (1 === getDerivedStateFromProps.tag) {
- var nextFiber = createUpdate(renderExpirationTime);
- nextFiber.tag = 2;
- enqueueUpdate(getDerivedStateFromProps, nextFiber);
- }
- getDerivedStateFromProps.expirationTime <
- renderExpirationTime &&
- (getDerivedStateFromProps.expirationTime = renderExpirationTime);
- nextFiber = getDerivedStateFromProps.alternate;
- null !== nextFiber &&
- nextFiber.expirationTime < renderExpirationTime &&
- (nextFiber.expirationTime = renderExpirationTime);
- for (
- var node = getDerivedStateFromProps.return;
- null !== node;
-
- ) {
- nextFiber = node.alternate;
- if (node.childExpirationTime < renderExpirationTime)
- (node.childExpirationTime = renderExpirationTime),
- null !== nextFiber &&
- nextFiber.childExpirationTime <
- renderExpirationTime &&
- (nextFiber.childExpirationTime = renderExpirationTime);
+ 1 === oldValue.tag &&
+ ((dependency = createUpdate(renderExpirationTime)),
+ (dependency.tag = ForceUpdate),
+ enqueueUpdate(oldValue, dependency));
+ oldValue.expirationTime < renderExpirationTime &&
+ (oldValue.expirationTime = renderExpirationTime);
+ dependency = oldValue.alternate;
+ null !== dependency &&
+ dependency.expirationTime < renderExpirationTime &&
+ (dependency.expirationTime = renderExpirationTime);
+ dependency = renderExpirationTime;
+ for (var node = oldValue.return; null !== node; ) {
+ var alternate = node.alternate;
+ if (node.childExpirationTime < dependency)
+ (node.childExpirationTime = dependency),
+ null !== alternate &&
+ alternate.childExpirationTime < dependency &&
+ (alternate.childExpirationTime = dependency);
else if (
- null !== nextFiber &&
- nextFiber.childExpirationTime < renderExpirationTime
+ null !== alternate &&
+ alternate.childExpirationTime < dependency
)
- nextFiber.childExpirationTime = renderExpirationTime;
+ alternate.childExpirationTime = dependency;
else break;
node = node.return;
}
+ list.expirationTime < renderExpirationTime &&
+ (list.expirationTime = renderExpirationTime);
+ break;
+ }
+ dependency = dependency.next;
}
- nextFiber = getDerivedStateFromProps.child;
- oldValue = oldValue.next;
- } while (null !== oldValue);
} else
- nextFiber =
- 10 === getDerivedStateFromProps.tag
- ? getDerivedStateFromProps.type === workInProgress.type
+ getDerivedStateFromProps =
+ 10 === oldValue.tag
+ ? oldValue.type === workInProgress.type
? null
- : getDerivedStateFromProps.child
- : getDerivedStateFromProps.child;
- if (null !== nextFiber)
- nextFiber.return = getDerivedStateFromProps;
+ : oldValue.child
+ : oldValue.child;
+ if (null !== getDerivedStateFromProps)
+ getDerivedStateFromProps.return = oldValue;
else
for (
- nextFiber = getDerivedStateFromProps;
- null !== nextFiber;
+ getDerivedStateFromProps = oldValue;
+ null !== getDerivedStateFromProps;
) {
- if (nextFiber === workInProgress) {
- nextFiber = null;
+ if (getDerivedStateFromProps === workInProgress) {
+ getDerivedStateFromProps = null;
break;
}
- getDerivedStateFromProps = nextFiber.sibling;
- if (null !== getDerivedStateFromProps) {
- getDerivedStateFromProps.return = nextFiber.return;
- nextFiber = getDerivedStateFromProps;
+ oldValue = getDerivedStateFromProps.sibling;
+ if (null !== oldValue) {
+ oldValue.return = getDerivedStateFromProps.return;
+ getDerivedStateFromProps = oldValue;
break;
}
- nextFiber = nextFiber.return;
+ getDerivedStateFromProps = getDerivedStateFromProps.return;
}
- getDerivedStateFromProps = nextFiber;
+ oldValue = getDerivedStateFromProps;
}
}
reconcileChildren(
@@ -4554,13 +4826,297 @@
renderExpirationTime
)
);
- default:
+ }
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,
+ lastContextDependency = null,
+ lastContextWithAllBitsObserved = null;
+function pushProvider(providerFiber, nextValue) {
+ var context = providerFiber.type._context;
+ push(valueCursor, context._currentValue, providerFiber);
+ context._currentValue = nextValue;
+}
+function popProvider(providerFiber) {
+ var currentValue = valueCursor.current;
+ pop(valueCursor, providerFiber);
+ providerFiber.type._context._currentValue = currentValue;
+}
+function prepareToReadContext(workInProgress, renderExpirationTime) {
+ currentlyRenderingFiber = workInProgress;
+ lastContextWithAllBitsObserved = lastContextDependency = null;
+ var currentDependencies = workInProgress.contextDependencies;
+ null !== currentDependencies &&
+ currentDependencies.expirationTime >= renderExpirationTime &&
+ (didReceiveUpdate = !0);
+ workInProgress.contextDependencies = null;
+}
+function readContext(context, observedBits) {
+ if (
+ lastContextWithAllBitsObserved !== context &&
+ !1 !== observedBits &&
+ 0 !== observedBits
+ ) {
+ if ("number" !== typeof observedBits || 1073741823 === observedBits)
+ (lastContextWithAllBitsObserved = context), (observedBits = 1073741823);
+ observedBits = { context: context, observedBits: observedBits, next: null };
+ null === lastContextDependency
+ ? (invariant(
+ null !== currentlyRenderingFiber,
+ "Context can only be read while React is rendering. In classes, you can read it in the render method or getDerivedStateFromProps. In function components, you can read it directly in the function body, but not inside Hooks like useReducer() or useMemo()."
+ ),
+ (lastContextDependency = observedBits),
+ (currentlyRenderingFiber.contextDependencies = {
+ first: observedBits,
+ expirationTime: 0
+ }))
+ : (lastContextDependency = lastContextDependency.next = observedBits);
+ }
+ return context._currentValue;
+}
+var UpdateState = 0,
+ ReplaceState = 1,
+ ForceUpdate = 2,
+ CaptureUpdate = 3,
+ hasForceUpdate = !1;
+function createUpdateQueue(baseState) {
+ return {
+ baseState: baseState,
+ firstUpdate: null,
+ lastUpdate: null,
+ firstCapturedUpdate: null,
+ lastCapturedUpdate: null,
+ firstEffect: null,
+ lastEffect: null,
+ firstCapturedEffect: null,
+ lastCapturedEffect: null
+ };
+}
+function cloneUpdateQueue(currentQueue) {
+ return {
+ baseState: currentQueue.baseState,
+ firstUpdate: currentQueue.firstUpdate,
+ lastUpdate: currentQueue.lastUpdate,
+ firstCapturedUpdate: null,
+ lastCapturedUpdate: null,
+ firstEffect: null,
+ lastEffect: null,
+ firstCapturedEffect: null,
+ lastCapturedEffect: null
+ };
+}
+function createUpdate(expirationTime) {
+ return {
+ expirationTime: expirationTime,
+ tag: UpdateState,
+ payload: null,
+ callback: null,
+ next: null,
+ nextEffect: null
+ };
+}
+function appendUpdateToQueue(queue, update) {
+ null === queue.lastUpdate
+ ? (queue.firstUpdate = queue.lastUpdate = update)
+ : ((queue.lastUpdate.next = update), (queue.lastUpdate = update));
+}
+function enqueueUpdate(fiber, update) {
+ var alternate = fiber.alternate;
+ if (null === alternate) {
+ var queue1 = fiber.updateQueue;
+ var queue2 = null;
+ null === queue1 &&
+ (queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState));
+ } else
+ (queue1 = fiber.updateQueue),
+ (queue2 = alternate.updateQueue),
+ null === queue1
+ ? null === queue2
+ ? ((queue1 = fiber.updateQueue = createUpdateQueue(
+ fiber.memoizedState
+ )),
+ (queue2 = alternate.updateQueue = createUpdateQueue(
+ alternate.memoizedState
+ )))
+ : (queue1 = fiber.updateQueue = cloneUpdateQueue(queue2))
+ : null === queue2 &&
+ (queue2 = alternate.updateQueue = cloneUpdateQueue(queue1));
+ null === queue2 || queue1 === queue2
+ ? appendUpdateToQueue(queue1, update)
+ : null === queue1.lastUpdate || null === queue2.lastUpdate
+ ? (appendUpdateToQueue(queue1, update),
+ appendUpdateToQueue(queue2, update))
+ : (appendUpdateToQueue(queue1, update), (queue2.lastUpdate = update));
+}
+function enqueueCapturedUpdate(workInProgress, update) {
+ var workInProgressQueue = workInProgress.updateQueue;
+ workInProgressQueue =
+ null === workInProgressQueue
+ ? (workInProgress.updateQueue = createUpdateQueue(
+ workInProgress.memoizedState
+ ))
+ : ensureWorkInProgressQueueIsAClone(workInProgress, workInProgressQueue);
+ null === workInProgressQueue.lastCapturedUpdate
+ ? (workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update)
+ : ((workInProgressQueue.lastCapturedUpdate.next = update),
+ (workInProgressQueue.lastCapturedUpdate = update));
+}
+function ensureWorkInProgressQueueIsAClone(workInProgress, queue) {
+ var current = workInProgress.alternate;
+ null !== current &&
+ queue === current.updateQueue &&
+ (queue = workInProgress.updateQueue = cloneUpdateQueue(queue));
+ return queue;
+}
+function getStateFromUpdate(
+ workInProgress,
+ queue,
+ update,
+ prevState,
+ nextProps,
+ instance
+) {
+ switch (update.tag) {
+ case ReplaceState:
+ return (
+ (workInProgress = update.payload),
+ "function" === typeof workInProgress
+ ? workInProgress.call(instance, prevState, nextProps)
+ : workInProgress
+ );
+ case CaptureUpdate:
+ workInProgress.effectTag = (workInProgress.effectTag & -2049) | 64;
+ case UpdateState:
+ workInProgress = update.payload;
+ nextProps =
+ "function" === typeof workInProgress
+ ? workInProgress.call(instance, prevState, nextProps)
+ : workInProgress;
+ if (null === nextProps || void 0 === nextProps) break;
+ return Object.assign({}, prevState, nextProps);
+ case ForceUpdate:
+ hasForceUpdate = !0;
+ }
+ return prevState;
+}
+function processUpdateQueue(
+ workInProgress,
+ queue,
+ props,
+ instance,
+ renderExpirationTime
+) {
+ hasForceUpdate = !1;
+ queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue);
+ for (
+ var newBaseState = queue.baseState,
+ newFirstUpdate = null,
+ newExpirationTime = 0,
+ update = queue.firstUpdate,
+ resultState = newBaseState;
+ null !== update;
+
+ ) {
+ var updateExpirationTime = update.expirationTime;
+ updateExpirationTime < renderExpirationTime
+ ? (null === newFirstUpdate &&
+ ((newFirstUpdate = update), (newBaseState = resultState)),
+ newExpirationTime < updateExpirationTime &&
+ (newExpirationTime = updateExpirationTime))
+ : ((resultState = getStateFromUpdate(
+ workInProgress,
+ queue,
+ update,
+ resultState,
+ props,
+ instance
+ )),
+ null !== update.callback &&
+ ((workInProgress.effectTag |= 32),
+ (update.nextEffect = null),
+ null === queue.lastEffect
+ ? (queue.firstEffect = queue.lastEffect = update)
+ : ((queue.lastEffect.nextEffect = update),
+ (queue.lastEffect = update))));
+ update = update.next;
+ }
+ updateExpirationTime = null;
+ for (update = queue.firstCapturedUpdate; null !== update; ) {
+ var _updateExpirationTime = update.expirationTime;
+ _updateExpirationTime < renderExpirationTime
+ ? (null === updateExpirationTime &&
+ ((updateExpirationTime = update),
+ null === newFirstUpdate && (newBaseState = resultState)),
+ newExpirationTime < _updateExpirationTime &&
+ (newExpirationTime = _updateExpirationTime))
+ : ((resultState = getStateFromUpdate(
+ workInProgress,
+ queue,
+ update,
+ resultState,
+ props,
+ instance
+ )),
+ null !== update.callback &&
+ ((workInProgress.effectTag |= 32),
+ (update.nextEffect = null),
+ null === queue.lastCapturedEffect
+ ? (queue.firstCapturedEffect = queue.lastCapturedEffect = update)
+ : ((queue.lastCapturedEffect.nextEffect = update),
+ (queue.lastCapturedEffect = update))));
+ update = update.next;
+ }
+ null === newFirstUpdate && (queue.lastUpdate = null);
+ null === updateExpirationTime
+ ? (queue.lastCapturedUpdate = null)
+ : (workInProgress.effectTag |= 32);
+ null === newFirstUpdate &&
+ null === updateExpirationTime &&
+ (newBaseState = resultState);
+ queue.baseState = newBaseState;
+ queue.firstUpdate = newFirstUpdate;
+ queue.firstCapturedUpdate = updateExpirationTime;
+ workInProgress.expirationTime = newExpirationTime;
+ workInProgress.memoizedState = resultState;
+}
+function commitUpdateQueue(finishedWork, finishedQueue, instance) {
+ null !== finishedQueue.firstCapturedUpdate &&
+ (null !== finishedQueue.lastUpdate &&
+ ((finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate),
+ (finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate)),
+ (finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null));
+ commitUpdateEffects(finishedQueue.firstEffect, instance);
+ finishedQueue.firstEffect = finishedQueue.lastEffect = null;
+ commitUpdateEffects(finishedQueue.firstCapturedEffect, instance);
+ finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null;
+}
+function commitUpdateEffects(effect, instance) {
+ for (; null !== effect; ) {
+ var _callback3 = effect.callback;
+ if (null !== _callback3) {
+ effect.callback = null;
+ var context = instance;
+ invariant(
+ "function" === typeof _callback3,
+ "Invalid argument passed as callback. Expected a function. Instead received: %s",
+ _callback3
+ );
+ _callback3.call(context);
+ }
+ effect = effect.nextEffect;
}
}
+function createCapturedValue(value, source) {
+ return {
+ value: value,
+ source: source,
+ stack: getStackByFiberInDevAndProd(source)
+ };
+}
var appendAllChildren = void 0,
updateHostContainer = void 0,
updateHostComponent$1 = void 0,
@@ -4611,6 +5167,7 @@
: Error("Unspecified error at:" + componentStack);
ExceptionsManager.handleException(error, !1);
}
+var PossiblyWeakSet$1 = "function" === typeof WeakSet ? WeakSet : Set;
function logError(boundary, errorInfo) {
var source = errorInfo.source,
stack = errorInfo.stack;
@@ -4651,6 +5208,81 @@
}
else ref.current = null;
}
+function commitHookEffectList(unmountTag, mountTag, finishedWork) {
+ finishedWork = finishedWork.updateQueue;
+ finishedWork = null !== finishedWork ? finishedWork.lastEffect : null;
+ if (null !== finishedWork) {
+ var effect = (finishedWork = finishedWork.next);
+ do {
+ if ((effect.tag & unmountTag) !== NoEffect$1) {
+ var destroy = effect.destroy;
+ effect.destroy = void 0;
+ void 0 !== destroy && destroy();
+ }
+ (effect.tag & mountTag) !== NoEffect$1 &&
+ ((destroy = effect.create), (effect.destroy = destroy()));
+ effect = effect.next;
+ } while (effect !== finishedWork);
+ }
+}
+function hideOrUnhideAllChildren(finishedWork, isHidden) {
+ for (var node = finishedWork; ; ) {
+ if (5 === node.tag) {
+ var instance = node.stateNode;
+ if (isHidden) {
+ var viewConfig = instance.viewConfig;
+ var updatePayload = diffProperties(
+ null,
+ emptyObject,
+ { style: { display: "none" } },
+ viewConfig.validAttributes
+ );
+ UIManager.updateView(
+ instance._nativeTag,
+ viewConfig.uiViewClassName,
+ updatePayload
+ );
+ } else {
+ instance = node.stateNode;
+ updatePayload = node.memoizedProps;
+ viewConfig = instance.viewConfig;
+ var prevProps = Object.assign({}, updatePayload, {
+ style: [updatePayload.style, { display: "none" }]
+ });
+ updatePayload = diffProperties(
+ null,
+ prevProps,
+ updatePayload,
+ viewConfig.validAttributes
+ );
+ UIManager.updateView(
+ instance._nativeTag,
+ viewConfig.uiViewClassName,
+ updatePayload
+ );
+ }
+ } else {
+ if (6 === node.tag) throw Error("Not yet implemented.");
+ if (13 === node.tag && null !== node.memoizedState) {
+ instance = node.child.sibling;
+ instance.return = node;
+ node = instance;
+ continue;
+ } else if (null !== node.child) {
+ node.child.return = node;
+ node = node.child;
+ continue;
+ }
+ }
+ if (node === finishedWork) break;
+ for (; null === node.sibling; ) {
+ if (null === node.return || node.return === finishedWork) return;
+ node = node.return;
+ }
+ node.sibling.return = node.return;
+ node = node.sibling;
+ }
+}
function commitUnmount(current$$1$jscomp$0) {
"function" === typeof onCommitFiberUnmount &&
onCommitFiberUnmount(current$$1$jscomp$0);
@@ -4667,7 +5299,7 @@
var effect = (updateQueue = updateQueue.next);
do {
var destroy = effect.destroy;
- if (null !== destroy) {
+ if (void 0 !== destroy) {
var current$$1 = current$$1$jscomp$0;
try {
destroy();
@@ -4748,7 +5380,7 @@
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;
@@ -4911,13 +5543,15 @@
node$jscomp$0.splice(child, 1);
UIManager.manageChildren(root._nativeTag, [], [], [], [], [child]);
}
- } else if (
- (4 === node.tag
- ? ((currentParent = node.stateNode.containerInfo),
- (currentParentIsContainer = !0))
- : commitUnmount(node),
- null !== node.child)
- ) {
+ } else if (4 === node.tag) {
+ if (null !== node.child) {
+ currentParent = node.stateNode.containerInfo;
+ currentParentIsContainer = !0;
+ node.child.return = node;
+ node = node.child;
+ continue;
+ }
+ } else if ((commitUnmount(node), null !== node.child)) {
node.child.return = node;
node = node.child;
continue;
@@ -4938,6 +5572,7 @@
case 11:
case 14:
case 15:
+ commitHookEffectList(UnmountMutation, MountMutation, finishedWork);
break;
case 1:
break;
@@ -4946,23 +5581,18 @@
if (null != instance) {
var newProps = finishedWork.memoizedProps;
current$$1 = null !== current$$1 ? current$$1.memoizedProps : newProps;
- var updatePayload = finishedWork.updateQueue;
+ var type = finishedWork.type,
+ updatePayload = finishedWork.updateQueue;
finishedWork.updateQueue = null;
null !== updatePayload &&
- ((finishedWork = instance.viewConfig),
- (instanceProps[instance._nativeTag] = newProps),
- (newProps = diffProperties(
- null,
+ commitUpdate(
+ instance,
+ updatePayload,
+ type,
current$$1,
newProps,
- finishedWork.validAttributes
- )),
- null != newProps &&
- UIManager.updateView(
- instance._nativeTag,
- finishedWork.uiViewClassName,
- newProps
- ));
+ finishedWork
+ );
}
break;
case 6:
@@ -4979,70 +5609,28 @@
case 12:
break;
case 13:
- newProps = finishedWork.memoizedState;
+ instance = finishedWork.memoizedState;
+ newProps = void 0;
current$$1 = finishedWork;
- null === newProps
- ? (instance = !1)
- : ((instance = !0),
+ null === instance
+ ? (newProps = !1)
+ : ((newProps = !0),
(current$$1 = finishedWork.child),
- 0 === newProps.timedOutAt &&
- (newProps.timedOutAt = requestCurrentTime()));
- if (null !== current$$1)
- a: for (newProps = finishedWork = current$$1; ; ) {
- if (5 === newProps.tag)
- if (((current$$1 = newProps.stateNode), instance)) {
- updatePayload = current$$1.viewConfig;
- var updatePayload$jscomp$0 = diffProperties(
- null,
- emptyObject,
- { style: { display: "none" } },
- updatePayload.validAttributes
- );
- UIManager.updateView(
- current$$1._nativeTag,
- updatePayload.uiViewClassName,
- updatePayload$jscomp$0
- );
- } else {
- current$$1 = newProps.stateNode;
- updatePayload$jscomp$0 = newProps.memoizedProps;
- updatePayload = current$$1.viewConfig;
- var prevProps = Object.assign({}, updatePayload$jscomp$0, {
- style: [updatePayload$jscomp$0.style, { display: "none" }]
+ 0 === instance.timedOutAt &&
+ (instance.timedOutAt = requestCurrentTime()));
+ null !== current$$1 && hideOrUnhideAllChildren(current$$1, newProps);
+ instance = finishedWork.updateQueue;
+ if (null !== instance) {
+ finishedWork.updateQueue = null;
+ var retryCache = finishedWork.stateNode;
+ null === retryCache &&
+ (retryCache = finishedWork.stateNode = new PossiblyWeakSet$1());
+ instance.forEach(function(thenable) {
+ var retry = resolveRetryThenable.bind(null, finishedWork, thenable);
+ retry = tracing.unstable_wrap(retry);
+ retryCache.has(thenable) ||
+ (retryCache.add(thenable), thenable.then(retry, retry));
});
- updatePayload$jscomp$0 = diffProperties(
- null,
- prevProps,
- updatePayload$jscomp$0,
- updatePayload.validAttributes
- );
- UIManager.updateView(
- current$$1._nativeTag,
- updatePayload.uiViewClassName,
- updatePayload$jscomp$0
- );
- }
- else {
- if (6 === newProps.tag) throw Error("Not yet implemented.");
- if (13 === newProps.tag && null !== newProps.memoizedState) {
- current$$1 = newProps.child.sibling;
- current$$1.return = newProps;
- newProps = current$$1;
- continue;
- } else if (null !== newProps.child) {
- newProps.child.return = newProps;
- newProps = newProps.child;
- continue;
- }
- }
- if (newProps === finishedWork) break a;
- for (; null === newProps.sibling; ) {
- if (null === newProps.return || newProps.return === finishedWork)
- break a;
- newProps = newProps.return;
- }
- newProps.sibling.return = newProps.return;
- newProps = newProps.sibling;
}
break;
case 17:
@@ -5054,9 +5642,10 @@
);
}
}
+var PossiblyWeakMap = "function" === typeof WeakMap ? WeakMap : Map;
function createRootErrorUpdate(fiber, errorInfo, expirationTime) {
expirationTime = createUpdate(expirationTime);
- expirationTime.tag = 3;
+ expirationTime.tag = CaptureUpdate;
expirationTime.payload = { element: null };
var error = errorInfo.value;
expirationTime.callback = function() {
@@ -5067,7 +5656,7 @@
}
function createClassErrorUpdate(fiber, errorInfo, expirationTime) {
expirationTime = createUpdate(expirationTime);
- expirationTime.tag = 3;
+ expirationTime.tag = CaptureUpdate;
var getDerivedStateFromError = fiber.type.getDerivedStateFromError;
if ("function" === typeof getDerivedStateFromError) {
var error$jscomp$0 = errorInfo.value;
@@ -5136,24 +5725,44 @@
? !1
: null === value.memoizedState;
if (current$$1) {
- returnFiber = retrySuspendedRoot.bind(
- null,
- root,
- value,
- sourceFiber,
- 0 === (value.mode & 1) ? 1073741823 : renderExpirationTime
- );
- returnFiber = tracing.unstable_wrap(returnFiber);
- thenable.then(returnFiber, returnFiber);
+ returnFiber = value.updateQueue;
+ null === returnFiber
+ ? ((returnFiber = new Set()),
+ returnFiber.add(thenable),
+ (value.updateQueue = returnFiber))
+ : returnFiber.add(thenable);
if (0 === (value.mode & 1)) {
value.effectTag |= 64;
sourceFiber.effectTag &= -1957;
1 === sourceFiber.tag &&
- null === sourceFiber.alternate &&
- (sourceFiber.tag = 17);
- sourceFiber.expirationTime = renderExpirationTime;
+ (null === sourceFiber.alternate
+ ? (sourceFiber.tag = 17)
+ : ((renderExpirationTime = createUpdate(1073741823)),
+ (renderExpirationTime.tag = ForceUpdate),
+ enqueueUpdate(sourceFiber, renderExpirationTime)));
+ sourceFiber.expirationTime = 1073741823;
return;
}
+ 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,
+ sourceFiber,
+ thenable,
+ returnFiber
+ )),
+ (sourceFiber = tracing.unstable_wrap(sourceFiber)),
+ thenable.then(sourceFiber, sourceFiber));
-1 === earliestTimeoutMs
? (root = 1073741823)
: (-1 === startTimeMs &&
@@ -5187,33 +5796,32 @@
do {
switch (root.tag) {
case 3:
- sourceFiber = value;
root.effectTag |= 2048;
root.expirationTime = renderExpirationTime;
renderExpirationTime = createRootErrorUpdate(
root,
- sourceFiber,
+ value,
renderExpirationTime
);
enqueueCapturedUpdate(root, renderExpirationTime);
return;
case 1:
if (
- ((sourceFiber = value),
- (returnFiber = root.type),
- (thenable = root.stateNode),
+ ((earliestTimeoutMs = value),
+ (startTimeMs = root.type),
+ (sourceFiber = root.stateNode),
0 === (root.effectTag & 64) &&
- ("function" === typeof returnFiber.getDerivedStateFromError ||
- (null !== thenable &&
- "function" === typeof thenable.componentDidCatch &&
+ ("function" === typeof startTimeMs.getDerivedStateFromError ||
+ (null !== sourceFiber &&
+ "function" === typeof sourceFiber.componentDidCatch &&
(null === legacyErrorBoundariesThatAlreadyFailed ||
- !legacyErrorBoundariesThatAlreadyFailed.has(thenable)))))
+ !legacyErrorBoundariesThatAlreadyFailed.has(sourceFiber)))))
) {
root.effectTag |= 2048;
root.expirationTime = renderExpirationTime;
renderExpirationTime = createClassErrorUpdate(
root,
- sourceFiber,
+ earliestTimeoutMs,
renderExpirationTime
);
enqueueCapturedUpdate(root, renderExpirationTime);
@@ -5254,6 +5862,8 @@
workInProgress)
: null
);
+ case 18:
+ return null;
case 4:
return popHostContainer(workInProgress), null;
case 10:
@@ -5262,7 +5872,7 @@
return null;
}
}
-var DispatcherWithoutHooks = { readContext: readContext },
+var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher,
ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner;
invariant(
null != tracing.__interactionsRef &&
@@ -5277,6 +5887,7 @@
nextRenderDidError = !1,
nextEffect = null,
isCommitting$1 = !1,
+ rootWithPendingPassiveEffects = null,
passiveEffectCallbackHandle = null,
passiveEffectCallback = null,
legacyErrorBoundariesThatAlreadyFailed = null;
@@ -5369,6 +5980,7 @@
case 0:
case 11:
case 15:
+ commitHookEffectList(UnmountSnapshot, NoEffect$1, finishedWork);
break a;
case 1:
if (finishedWork.effectTag & 256 && null !== current$$1) {
@@ -5415,6 +6027,7 @@
case 0:
case 11:
case 15:
+ commitHookEffectList(UnmountLayout, MountLayout, finishedWork);
break;
case 1:
finishedRoot = finishedWork.stateNode;
@@ -5493,19 +6106,47 @@
}
}
effectTag & 128 &&
- ((effectTag = nextEffect.ref),
- null !== effectTag &&
- ((finishedWork = nextEffect.stateNode),
- "function" === typeof effectTag
- ? effectTag(finishedWork)
- : (effectTag.current = finishedWork)));
+ ((finishedWork = nextEffect.ref),
+ null !== finishedWork &&
+ ((committedExpirationTime = nextEffect.stateNode),
+ "function" === typeof finishedWork
+ ? finishedWork(committedExpirationTime)
+ : (finishedWork.current = committedExpirationTime)));
+ effectTag & 512 && (rootWithPendingPassiveEffects = finishedRoot$jscomp$0);
nextEffect = nextEffect.nextEffect;
}
}
+function commitPassiveEffects(root, firstEffect) {
+ passiveEffectCallback = passiveEffectCallbackHandle = rootWithPendingPassiveEffects = null;
+ var previousIsRendering = isRendering;
+ isRendering = !0;
+ do {
+ if (firstEffect.effectTag & 512) {
+ var didError = !1,
+ error = void 0;
+ try {
+ var finishedWork = firstEffect;
+ commitHookEffectList(UnmountPassive, NoEffect$1, finishedWork);
+ commitHookEffectList(NoEffect$1, MountPassive, finishedWork);
+ } catch (e) {
+ (didError = !0), (error = e);
+ }
+ didError && captureCommitPhaseError(firstEffect, error);
+ }
+ firstEffect = firstEffect.nextEffect;
+ } while (null !== firstEffect);
+ isRendering = previousIsRendering;
+ previousIsRendering = root.expirationTime;
+ 0 !== previousIsRendering && requestWork(root, previousIsRendering);
+ isBatchingUpdates || isRendering || performWork(1073741823, !1);
+}
function flushPassiveEffects() {
- null !== passiveEffectCallback &&
- (scheduler.unstable_cancelCallback(passiveEffectCallbackHandle),
- passiveEffectCallback());
+ if (null !== passiveEffectCallbackHandle) {
+ var callbackID = passiveEffectCallbackHandle;
+ scheduledCallback = null;
+ clearTimeout(callbackID);
+ }
+ null !== passiveEffectCallback && passiveEffectCallback();
}
function commitRoot(root, finishedWork) {
isCommitting$1 = isWorking = !0;
@@ -5573,21 +6214,39 @@
}
root.current = finishedWork;
for (nextEffect = childExpirationTimeBeforeCommit; null !== nextEffect; ) {
- childExpirationTimeBeforeCommit = !1;
- didError = void 0;
+ didError = !1;
+ error$jscomp$0 = void 0;
try {
commitAllLifeCycles(root, committedExpirationTime);
} catch (e) {
- (childExpirationTimeBeforeCommit = !0), (didError = e);
+ (didError = !0), (error$jscomp$0 = e);
}
- childExpirationTimeBeforeCommit &&
+ didError &&
(invariant(
null !== nextEffect,
"Should have next effect. This error is likely caused by a bug in React. Please file an issue."
),
- captureCommitPhaseError(nextEffect, didError),
+ captureCommitPhaseError(nextEffect, error$jscomp$0),
null !== nextEffect && (nextEffect = nextEffect.nextEffect));
}
+ if (
+ null !== childExpirationTimeBeforeCommit &&
+ null !== rootWithPendingPassiveEffects
+ ) {
+ var callback = commitPassiveEffects.bind(
+ null,
+ root,
+ childExpirationTimeBeforeCommit
+ );
+ callback = tracing.unstable_wrap(callback);
+ passiveEffectCallbackHandle = scheduler.unstable_runWithPriority(
+ scheduler.unstable_NormalPriority,
+ function() {
+ return scheduleDeferredCallback$1(callback);
+ }
+ );
+ passiveEffectCallback = callback;
+ }
isWorking = isCommitting$1 = !1;
"function" === typeof onCommitFiberRoot &&
onCommitFiberRoot(finishedWork.stateNode);
@@ -5779,11 +6438,7 @@
: ((current$$1.firstEffect = current$$1.lastEffect = type),
(type.nextEffect = null)),
(type.effectTag = 8)));
- if (
- fiber !== renderExpirationTime ||
- (0 === (current$$1.effectTag & 1) && fiber)
- )
- current$$1.effectTag |= 4;
+ if (fiber || renderExpirationTime) current$$1.effectTag |= 4;
break;
case 7:
break;
@@ -5805,6 +6460,8 @@
case 17:
isContextProvider(current$$1.type) && popContext(current$$1);
break;
+ case 18:
+ break;
default:
invariant(
!1,
@@ -5911,7 +6568,8 @@
);
flushPassiveEffects();
isWorking = !0;
- ReactCurrentOwner$2.currentDispatcher = DispatcherWithoutHooks;
+ var previousDispatcher = ReactCurrentDispatcher.current;
+ ReactCurrentDispatcher.current = ContextOnlyDispatcher;
var expirationTime = root.nextExpirationTimeToWorkOn;
if (
expirationTime !== nextRenderExpirationTime ||
@@ -5958,7 +6616,7 @@
do {
try {
if (isYieldy)
- for (; null !== nextUnitOfWork && !shouldYieldToRenderer(); )
+ for (; null !== nextUnitOfWork && !(frameDeadline <= now$1()); )
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
else
for (; null !== nextUnitOfWork; )
@@ -5966,6 +6624,7 @@
} catch (thrownValue) {
if (
((lastContextWithAllBitsObserved = lastContextDependency = currentlyRenderingFiber = null),
+ resetHooks(),
null === nextUnitOfWork)
)
(threadID = !0), onUncaughtError(thrownValue);
@@ -5996,27 +6655,35 @@
} while (1);
tracing.__interactionsRef.current = subscriber;
isWorking = !1;
- lastContextWithAllBitsObserved = lastContextDependency = currentlyRenderingFiber = ReactCurrentOwner$2.currentDispatcher = null;
+ ReactCurrentDispatcher.current = previousDispatcher;
+ lastContextWithAllBitsObserved = lastContextDependency = currentlyRenderingFiber = null;
+ resetHooks();
if (threadID) (nextRoot = null), (root.finishedWork = null);
else if (null !== nextUnitOfWork) root.finishedWork = null;
else {
- subscriber = root.current.alternate;
+ previousDispatcher = root.current.alternate;
invariant(
- null !== subscriber,
+ null !== previousDispatcher,
"Finished root should have a work-in-progress. This error is likely caused by a bug in React. Please file an issue."
);
nextRoot = null;
if (nextRenderDidError) {
if (hasLowerPriorityWork(root, expirationTime)) {
markSuspendedPriorityLevel(root, expirationTime);
- onSuspend(root, subscriber, expirationTime, root.expirationTime, -1);
+ onSuspend(
+ root,
+ previousDispatcher,
+ expirationTime,
+ root.expirationTime,
+ -1
+ );
return;
}
if (!root.didError && isYieldy) {
root.didError = !0;
isYieldy = root.nextExpirationTimeToWorkOn = expirationTime;
- threadID = root.expirationTime = 1073741823;
- onSuspend(root, subscriber, isYieldy, threadID, -1);
+ subscriber = root.expirationTime = 1073741823;
+ onSuspend(root, previousDispatcher, isYieldy, subscriber, -1);
return;
}
}
@@ -6032,12 +6699,12 @@
(isYieldy = nextLatestAbsoluteTimeoutMs - isYieldy),
onSuspend(
root,
- subscriber,
+ previousDispatcher,
expirationTime,
root.expirationTime,
0 > isYieldy ? 0 : isYieldy
))
- : onComplete(root, subscriber, expirationTime);
+ : onComplete(root, previousDispatcher, expirationTime);
}
}
function captureCommitPhaseError(sourceFiber, value) {
@@ -6074,55 +6741,72 @@
scheduleWork(sourceFiber, 1073741823));
}
function computeExpirationForFiber(currentTime, fiber) {
- isWorking
- ? (currentTime = isCommitting$1 ? 1073741823 : nextRenderExpirationTime)
- : fiber.mode & 1
- ? ((currentTime = isBatchingInteractiveUpdates
- ? 1073741822 - 10 * ((((1073741822 - currentTime + 15) / 10) | 0) + 1)
- : 1073741822 -
- 25 * ((((1073741822 - currentTime + 500) / 25) | 0) + 1)),
+ var priorityLevel = scheduler.unstable_getCurrentPriorityLevel(),
+ expirationTime = void 0;
+ if (0 === (fiber.mode & 1)) expirationTime = 1073741823;
+ else if (isWorking && !isCommitting$1)
+ expirationTime = nextRenderExpirationTime;
+ else {
+ switch (priorityLevel) {
+ case scheduler.unstable_ImmediatePriority:
+ expirationTime = 1073741823;
+ break;
+ case scheduler.unstable_UserBlockingPriority:
+ expirationTime =
+ 1073741822 - 10 * ((((1073741822 - currentTime + 15) / 10) | 0) + 1);
+ break;
+ case scheduler.unstable_NormalPriority:
+ expirationTime =
+ 1073741822 - 25 * ((((1073741822 - currentTime + 500) / 25) | 0) + 1);
+ break;
+ case scheduler.unstable_LowPriority:
+ case scheduler.unstable_IdlePriority:
+ expirationTime = 1;
+ break;
+ default:
+ invariant(
+ !1,
+ "Unknown priority level. This error is likely caused by a bug in React. Please file an issue."
+ );
+ }
null !== nextRoot &&
- currentTime === nextRenderExpirationTime &&
- --currentTime)
- : (currentTime = 1073741823);
- isBatchingInteractiveUpdates &&
+ expirationTime === nextRenderExpirationTime &&
+ --expirationTime;
+ }
+ priorityLevel === scheduler.unstable_UserBlockingPriority &&
(0 === lowestPriorityPendingInteractiveExpirationTime ||
- currentTime < lowestPriorityPendingInteractiveExpirationTime) &&
- (lowestPriorityPendingInteractiveExpirationTime = currentTime);
- return currentTime;
-}
-function retrySuspendedRoot(root, boundaryFiber, sourceFiber, suspendedTime) {
- var retryTime = root.earliestSuspendedTime;
- var latestSuspendedTime = root.latestSuspendedTime;
- if (
- 0 !== retryTime &&
- suspendedTime <= retryTime &&
- suspendedTime >= latestSuspendedTime
+ expirationTime < lowestPriorityPendingInteractiveExpirationTime) &&
+ (lowestPriorityPendingInteractiveExpirationTime = expirationTime);
+ return expirationTime;
+}
+function pingSuspendedRoot(root, thenable, pingTime) {
+ var pingCache = root.pingCache;
+ null !== pingCache && pingCache.delete(thenable);
+ if (null !== nextRoot && nextRenderExpirationTime === pingTime)
+ nextRoot = null;
+ else if (
+ ((thenable = root.earliestSuspendedTime),
+ (pingCache = root.latestSuspendedTime),
+ 0 !== thenable && pingTime <= thenable && pingTime >= pingCache)
) {
- latestSuspendedTime = retryTime = suspendedTime;
root.didError = !1;
- var latestPingedTime = root.latestPingedTime;
- if (0 === latestPingedTime || latestPingedTime > latestSuspendedTime)
- root.latestPingedTime = latestSuspendedTime;
- findNextExpirationTimeToWorkOn(latestSuspendedTime, root);
- } else
- (retryTime = requestCurrentTime()),
- (retryTime = computeExpirationForFiber(retryTime, boundaryFiber)),
- markPendingPriorityLevel(root, retryTime);
- 0 !== (boundaryFiber.mode & 1) &&
- root === nextRoot &&
- nextRenderExpirationTime === suspendedTime &&
- (nextRoot = null);
- scheduleWorkToRoot(boundaryFiber, retryTime);
- 0 === (boundaryFiber.mode & 1) &&
- (scheduleWorkToRoot(sourceFiber, retryTime),
- 1 === sourceFiber.tag &&
- null !== sourceFiber.stateNode &&
- ((boundaryFiber = createUpdate(retryTime)),
- (boundaryFiber.tag = 2),
- enqueueUpdate(sourceFiber, boundaryFiber)));
- sourceFiber = root.expirationTime;
- 0 !== sourceFiber && requestWork(root, sourceFiber);
+ thenable = root.latestPingedTime;
+ if (0 === thenable || thenable > pingTime) root.latestPingedTime = pingTime;
+ findNextExpirationTimeToWorkOn(pingTime, root);
+ pingTime = root.expirationTime;
+ 0 !== pingTime && requestWork(root, pingTime);
+ }
+}
+function resolveRetryThenable(boundaryFiber, thenable) {
+ var retryCache = boundaryFiber.stateNode;
+ null !== retryCache && retryCache.delete(thenable);
+ thenable = requestCurrentTime();
+ thenable = computeExpirationForFiber(thenable, boundaryFiber);
+ boundaryFiber = scheduleWorkToRoot(boundaryFiber, thenable);
+ null !== boundaryFiber &&
+ (markPendingPriorityLevel(boundaryFiber, thenable),
+ (thenable = boundaryFiber.expirationTime),
+ 0 !== thenable && requestWork(boundaryFiber, thenable));
}
function scheduleWorkToRoot(fiber, expirationTime) {
fiber.expirationTime < expirationTime &&
@@ -6201,7 +6885,6 @@
unhandledError = null,
isBatchingUpdates = !1,
isUnbatchingUpdates = !1,
- isBatchingInteractiveUpdates = !1,
completedBatches = null,
originalStartTimeMs = now$1(),
currentRendererTime = 1073741822 - ((originalStartTimeMs / 10) | 0),
@@ -6220,9 +6903,10 @@
((root = callbackID), (scheduledCallback = null), clearTimeout(root));
}
callbackExpirationTime = expirationTime;
- now$1();
- scheduledCallback = performAsyncWork;
- callbackID = setTimeout(setTimeoutCallback, 1);
+ root = now$1() - originalStartTimeMs;
+ callbackID = scheduleDeferredCallback$1(performAsyncWork, {
+ timeout: 10 * (1073741822 - expirationTime) - root
+ });
}
function onComplete(root, finishedWork, expirationTime) {
root.pendingCommitExpirationTime = expirationTime;
@@ -6236,7 +6920,7 @@
msUntilTimeout
) {
root.expirationTime = rootExpirationTime;
- 0 !== msUntilTimeout || shouldYieldToRenderer()
+ 0 !== msUntilTimeout || frameDeadline <= now$1()
? 0 < msUntilTimeout &&
(root.timeoutHandle = scheduleTimeout(
onTimeout.bind(null, root, finishedWork, suspendedExpirationTime),
@@ -6336,27 +7020,19 @@
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) {
+function performAsyncWork(didTimeout) {
+ if (didTimeout && null !== firstScheduledRoot) {
recomputeCurrentRendererTime();
- var root = firstScheduledRoot;
+ didTimeout = firstScheduledRoot;
do {
- var expirationTime = root.expirationTime;
+ var expirationTime = didTimeout.expirationTime;
0 !== expirationTime &&
currentRendererTime <= expirationTime &&
- (root.nextExpirationTimeToWorkOn = currentRendererTime);
- root = root.nextScheduledRoot;
- } while (root !== firstScheduledRoot);
+ (didTimeout.nextExpirationTimeToWorkOn = currentRendererTime);
+ didTimeout = didTimeout.nextScheduledRoot;
+ } while (didTimeout !== firstScheduledRoot);
}
performWork(0, !0);
- } finally {
- didYield = !1;
- }
}
function performWork(minExpirationTime, isYieldy) {
findHighestPriorityRoot();
@@ -6367,7 +7043,10 @@
null !== nextFlushedRoot &&
0 !== nextFlushedExpirationTime &&
minExpirationTime <= nextFlushedExpirationTime &&
- !(didYield && currentRendererTime > nextFlushedExpirationTime);
+ !(
+ frameDeadline <= now$1() &&
+ currentRendererTime > nextFlushedExpirationTime
+ );
)
performWorkOnRoot(
@@ -6435,7 +7114,7 @@
renderRoot(root, isYieldy),
(_finishedWork = root.finishedWork),
null !== _finishedWork &&
- (shouldYieldToRenderer()
+ (frameDeadline <= now$1()
? (root.finishedWork = _finishedWork)
: completeRoot(root, _finishedWork, expirationTime)));
} else
@@ -6470,7 +7149,12 @@
root === lastCommittedRootDuringThisBatch
? nestedUpdateCount++
: ((lastCommittedRootDuringThisBatch = root), (nestedUpdateCount = 0));
+ scheduler.unstable_runWithPriority(
+ scheduler.unstable_ImmediatePriority,
+ function() {
commitRoot(root, finishedWork);
+ }
+ );
}
function onUncaughtError(error) {
invariant(
@@ -6671,18 +7355,20 @@
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
);
}
@@ -6691,6 +7377,21 @@
})(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) {
@@ -6706,6 +7407,7 @@
earliestSuspendedTime: 0,
latestSuspendedTime: 0,
latestPingedTime: 0,
+ pingCache: null,
didError: !1,
pendingCommitExpirationTime: 0,
finishedWork: null,
@@ -6785,17 +7487,20 @@
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
);
}
@@ -6819,6 +7524,8 @@
var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance;
return injectInternals(
Object.assign({}, devToolsConfig, {
+ overrideProps: null,
+ currentDispatcherRef: ReactSharedInternals.ReactCurrentDispatcher,
findHostInstanceByFiber: function(fiber) {
fiber = findCurrentHostFiber(fiber);
return null === fiber ? null : fiber.stateNode;
@@ -6834,7 +7541,7 @@
findFiberByHostInstance: getInstanceFromTag,
getInspectorDataForViewTag: getInspectorDataForViewTag,
bundleType: 0,
- version: "16.6.1",
+ version: "16.8.3",
rendererPackageName: "react-native-renderer"
});
var ReactNativeRenderer$2 = { default: ReactNativeRenderer },

Libraries/Renderer/REVISION

@@ -1 +1 @@
-6bf5e859860938b8cb7153ee928c01ad45656969
\ No newline at end of file
+8e25ed20bd27d126f670d04680db85209f779056
\ No newline at end of file

Libraries/Renderer/shims/ReactNativeTypes.js

@@ -131,6 +131,7 @@
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 ReactFabricType = {
NativeComponent: typeof ReactNativeComponent,
findNodeHandle(componentOrHandle: any): ?number,
+ setNativeProps(handle: any, nativeProps: Object): void,
render(
element: React$Element<any>,
containerTag: any,

Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js

@@ -15,7 +15,7 @@
ViewConfigGetter,
} from './ReactNativeTypes';
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
// Event configs
const customBubblingEventTypes = {};

Libraries/Sample/Sample.android.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Sample/Sample.h

@@ -1,3 +1,8 @@
+// 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.
+
#import <React/RCTBridgeModule.h>
@interface Sample : NSObject <RCTBridgeModule>

Libraries/Sample/Sample.ios.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Sample/Sample.m

@@ -1,3 +1,8 @@
+// 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.
+
#import "Sample.h"
@implementation Sample

Libraries/Settings/RCTSettingsManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Settings/RCTSettingsManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -53,6 +53,11 @@
- (NSDictionary<NSString *, id> *)constantsToExport
{
+ return [self getConstants];
+}
+
+- (NSDictionary<NSString *, id> *)getConstants
+{
return @{@"settings": RCTJSONClean([_defaults dictionaryRepresentation])};
}

Libraries/Settings/Settings.android.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Settings/Settings.ios.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -13,7 +13,7 @@
const RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
const RCTSettingsManager = require('NativeModules').SettingsManager;
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
const subscriptions: Array<{keys: Array<string>, callback: ?Function}> = [];

Libraries/Share/Share.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.
@@ -12,7 +12,7 @@
const Platform = require('Platform');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
const processColor = require('processColor');
const {ActionSheetManager, ShareModule} = require('NativeModules');

Libraries/Storage/AsyncStorage.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/StyleSheet/ColorPropType.js

@@ -1,76 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const normalizeColor = require('normalizeColor');
-
-const colorPropType = function(
- isRequired,
- props,
- propName,
- componentName,
- location,
- propFullName,
-) {
- const color = props[propName];
- if (color === undefined || color === null) {
- if (isRequired) {
- return new Error(
- 'Required ' +
- location +
- ' `' +
- (propFullName || propName) +
- '` was not specified in `' +
- componentName +
- '`.',
- );
- }
- return;
- }
-
- if (typeof color === 'number') {
- // Developers should not use a number, but we are using the prop type
- // both for user provided colors and for transformed ones. This isn't ideal
- // and should be fixed but will do for now...
- return;
- }
-
- if (normalizeColor(color) === null) {
- return new Error(
- 'Invalid ' +
- location +
- ' `' +
- (propFullName || propName) +
- '` supplied to `' +
- componentName +
- '`: ' +
- color +
- '\n' +
- `Valid color formats are
- - '#f0f' (#rgb)
- - '#f0fc' (#rgba)
- - '#ff00ff' (#rrggbb)
- - '#ff00ff00' (#rrggbbaa)
- - 'rgb(255, 255, 255)'
- - 'rgba(255, 255, 255, 1.0)'
- - 'hsl(360, 100%, 100%)'
- - 'hsla(360, 100%, 100%, 1.0)'
- - 'transparent'
- - 'red'
- - 0xff00ff00 (0xrrggbbaa)
-`,
- );
- }
-};
-
-const ColorPropType = colorPropType.bind(null, false /* isRequired */);
-ColorPropType.isRequired = colorPropType.bind(null, true /* isRequired */);
-
-module.exports = ColorPropType;

Libraries/StyleSheet/EdgeInsetsPropType.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,20 +10,9 @@
'use strict';
-const PropTypes = require('prop-types');
-
-const EdgeInsetsPropType = PropTypes.shape({
- top: PropTypes.number,
- left: PropTypes.number,
- bottom: PropTypes.number,
- right: PropTypes.number,
-});
-
export type EdgeInsetsProp = $ReadOnly<{|
top?: ?number,
left?: ?number,
bottom?: ?number,
right?: ?number,
|}>;
-
-module.exports = EdgeInsetsPropType;

Libraries/StyleSheet/flattenStyle.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/StyleSheet/__flowtests__/StyleSheet-flowtest.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/StyleSheet/LayoutPropTypes.js

@@ -1,561 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow strict
- */
-
-'use strict';
-
-const ReactPropTypes = require('prop-types');
-
-/**
- * React Native's layout system is based on Flexbox and is powered both
- * on iOS and Android by an open source project called `Yoga`:
- * https://github.com/facebook/yoga
- *
- * The implementation in Yoga is slightly different from what the
- * Flexbox spec defines - for example, we chose more sensible default
- * values. Since our layout docs are generated from the comments in this
- * file, please keep a brief comment describing each prop type.
- *
- * These properties are a subset of our styles that are consumed by the layout
- * algorithm and affect the positioning and sizing of views.
- */
-const LayoutPropTypes = {
- /** `display` sets the display type of this component.
- *
- * It works similarly to `display` in CSS, but only support 'flex' and 'none'.
- * 'flex' is the default.
- */
- display: ReactPropTypes.oneOf(['none', 'flex']),
-
- /** `width` sets the width of this component.
- *
- * It works similarly to `width` in CSS, but in React Native you
- * must use points or percentages. Ems and other units are not supported.
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/width for more details.
- */
- width: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /** `height` sets the height of this component.
- *
- * It works similarly to `height` in CSS, but in React Native you
- * must use points or percentages. Ems and other units are not supported.
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/height for more details.
- */
- height: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /**
- * When the direction is `ltr`, `start` is equivalent to `left`.
- * When the direction is `rtl`, `start` is equivalent to `right`.
- *
- * This style takes precedence over the `left`, `right`, and `end` styles.
- */
- start: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /**
- * When the direction is `ltr`, `end` is equivalent to `right`.
- * When the direction is `rtl`, `end` is equivalent to `left`.
- *
- * This style takes precedence over the `left` and `right` styles.
- */
- end: ReactPropTypes.oneOfType([ReactPropTypes.number, ReactPropTypes.string]),
-
- /** `top` is the number of logical pixels to offset the top edge of
- * this component.
- *
- * It works similarly to `top` in CSS, but in React Native you
- * must use points or percentages. Ems and other units are not supported.
- *
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/top
- * for more details of how `top` affects layout.
- */
- top: ReactPropTypes.oneOfType([ReactPropTypes.number, ReactPropTypes.string]),
-
- /** `left` is the number of logical pixels to offset the left edge of
- * this component.
- *
- * It works similarly to `left` in CSS, but in React Native you
- * must use points or percentages. Ems and other units are not supported.
- *
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/left
- * for more details of how `left` affects layout.
- */
- left: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /** `right` is the number of logical pixels to offset the right edge of
- * this component.
- *
- * It works similarly to `right` in CSS, but in React Native you
- * must use points or percentages. Ems and other units are not supported.
- *
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/right
- * for more details of how `right` affects layout.
- */
- right: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /** `bottom` is the number of logical pixels to offset the bottom edge of
- * this component.
- *
- * It works similarly to `bottom` in CSS, but in React Native you
- * must use points or percentages. Ems and other units are not supported.
- *
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/bottom
- * for more details of how `bottom` affects layout.
- */
- bottom: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /** `minWidth` is the minimum width for this component, in logical pixels.
- *
- * It works similarly to `min-width` in CSS, but in React Native you
- * must use points or percentages. Ems and other units are not supported.
- *
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/min-width
- * for more details.
- */
- minWidth: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /** `maxWidth` is the maximum width for this component, in logical pixels.
- *
- * It works similarly to `max-width` in CSS, but in React Native you
- * must use points or percentages. Ems and other units are not supported.
- *
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/max-width
- * for more details.
- */
- maxWidth: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /** `minHeight` is the minimum height for this component, in logical pixels.
- *
- * It works similarly to `min-height` in CSS, but in React Native you
- * must use points or percentages. Ems and other units are not supported.
- *
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/min-height
- * for more details.
- */
- minHeight: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /** `maxHeight` is the maximum height for this component, in logical pixels.
- *
- * It works similarly to `max-height` in CSS, but in React Native you
- * must use points or percentages. Ems and other units are not supported.
- *
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/max-height
- * for more details.
- */
- maxHeight: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /** Setting `margin` has the same effect as setting each of
- * `marginTop`, `marginLeft`, `marginBottom`, and `marginRight`.
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/margin
- * for more details.
- */
- margin: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /** Setting `marginVertical` has the same effect as setting both
- * `marginTop` and `marginBottom`.
- */
- marginVertical: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /** Setting `marginHorizontal` has the same effect as setting
- * both `marginLeft` and `marginRight`.
- */
- marginHorizontal: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /** `marginTop` works like `margin-top` in CSS.
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/margin-top
- * for more details.
- */
- marginTop: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /** `marginBottom` works like `margin-bottom` in CSS.
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/margin-bottom
- * for more details.
- */
- marginBottom: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /** `marginLeft` works like `margin-left` in CSS.
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/margin-left
- * for more details.
- */
- marginLeft: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /** `marginRight` works like `margin-right` in CSS.
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/margin-right
- * for more details.
- */
- marginRight: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /**
- * When direction is `ltr`, `marginStart` is equivalent to `marginLeft`.
- * When direction is `rtl`, `marginStart` is equivalent to `marginRight`.
- */
- marginStart: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /**
- * When direction is `ltr`, `marginEnd` is equivalent to `marginRight`.
- * When direction is `rtl`, `marginEnd` is equivalent to `marginLeft`.
- */
- marginEnd: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /** Setting `padding` has the same effect as setting each of
- * `paddingTop`, `paddingBottom`, `paddingLeft`, and `paddingRight`.
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/padding
- * for more details.
- */
- padding: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /** Setting `paddingVertical` is like setting both of
- * `paddingTop` and `paddingBottom`.
- */
- paddingVertical: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /** Setting `paddingHorizontal` is like setting both of
- * `paddingLeft` and `paddingRight`.
- */
- paddingHorizontal: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /** `paddingTop` works like `padding-top` in CSS.
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/padding-top
- * for more details.
- */
- paddingTop: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /** `paddingBottom` works like `padding-bottom` in CSS.
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/padding-bottom
- * for more details.
- */
- paddingBottom: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /** `paddingLeft` works like `padding-left` in CSS.
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/padding-left
- * for more details.
- */
- paddingLeft: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /** `paddingRight` works like `padding-right` in CSS.
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/padding-right
- * for more details.
- */
- paddingRight: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /**
- * When direction is `ltr`, `paddingStart` is equivalent to `paddingLeft`.
- * When direction is `rtl`, `paddingStart` is equivalent to `paddingRight`.
- */
- paddingStart: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /**
- * When direction is `ltr`, `paddingEnd` is equivalent to `paddingRight`.
- * When direction is `rtl`, `paddingEnd` is equivalent to `paddingLeft`.
- */
- paddingEnd: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /** `borderWidth` works like `border-width` in CSS.
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/border-width
- * for more details.
- */
- borderWidth: ReactPropTypes.number,
-
- /** `borderTopWidth` works like `border-top-width` in CSS.
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/border-top-width
- * for more details.
- */
- borderTopWidth: ReactPropTypes.number,
-
- /**
- * When direction is `ltr`, `borderStartWidth` is equivalent to `borderLeftWidth`.
- * When direction is `rtl`, `borderStartWidth` is equivalent to `borderRightWidth`.
- */
- borderStartWidth: ReactPropTypes.number,
-
- /**
- * When direction is `ltr`, `borderEndWidth` is equivalent to `borderRightWidth`.
- * When direction is `rtl`, `borderEndWidth` is equivalent to `borderLeftWidth`.
- */
- borderEndWidth: ReactPropTypes.number,
-
- /** `borderRightWidth` works like `border-right-width` in CSS.
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/border-right-width
- * for more details.
- */
- borderRightWidth: ReactPropTypes.number,
-
- /** `borderBottomWidth` works like `border-bottom-width` in CSS.
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/border-bottom-width
- * for more details.
- */
- borderBottomWidth: ReactPropTypes.number,
-
- /** `borderLeftWidth` works like `border-left-width` in CSS.
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/border-left-width
- * for more details.
- */
- borderLeftWidth: ReactPropTypes.number,
-
- /** `position` in React Native is similar to regular CSS, but
- * everything is set to `relative` by default, so `absolute`
- * positioning is always just relative to the parent.
- *
- * If you want to position a child using specific numbers of logical
- * pixels relative to its parent, set the child to have `absolute`
- * position.
- *
- * If you want to position a child relative to something
- * that is not its parent, just don't use styles for that. Use the
- * component tree.
- *
- * See https://github.com/facebook/yoga
- * for more details on how `position` differs between React Native
- * and CSS.
- */
- position: ReactPropTypes.oneOf(['absolute', 'relative']),
-
- /** `flexDirection` controls which directions children of a container go.
- * `row` goes left to right, `column` goes top to bottom, and you may
- * be able to guess what the other two do. It works like `flex-direction`
- * in CSS, except the default is `column`.
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/flex-direction
- * for more details.
- */
- flexDirection: ReactPropTypes.oneOf([
- 'row',
- 'row-reverse',
- 'column',
- 'column-reverse',
- ]),
-
- /** `flexWrap` controls whether children can wrap around after they
- * hit the end of a flex container.
- * It works like `flex-wrap` in CSS (default: nowrap).
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/flex-wrap
- * for more details.
- */
- flexWrap: ReactPropTypes.oneOf(['wrap', 'nowrap', 'wrap-reverse']),
-
- /** `justifyContent` aligns children in the main direction.
- * For example, if children are flowing vertically, `justifyContent`
- * controls how they align vertically.
- * It works like `justify-content` in CSS (default: flex-start).
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/justify-content
- * for more details.
- */
- justifyContent: ReactPropTypes.oneOf([
- 'flex-start',
- 'flex-end',
- 'center',
- 'space-between',
- 'space-around',
- 'space-evenly',
- ]),
-
- /** `alignItems` aligns children in the cross direction.
- * For example, if children are flowing vertically, `alignItems`
- * controls how they align horizontally.
- * It works like `align-items` in CSS (default: stretch).
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/align-items
- * for more details.
- */
- alignItems: ReactPropTypes.oneOf([
- 'flex-start',
- 'flex-end',
- 'center',
- 'stretch',
- 'baseline',
- ]),
-
- /** `alignSelf` controls how a child aligns in the cross direction,
- * overriding the `alignItems` of the parent. It works like `align-self`
- * in CSS (default: auto).
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/align-self
- * for more details.
- */
- alignSelf: ReactPropTypes.oneOf([
- 'auto',
- 'flex-start',
- 'flex-end',
- 'center',
- 'stretch',
- 'baseline',
- ]),
-
- /** `alignContent` controls how rows align in the cross direction,
- * overriding the `alignContent` of the parent.
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/align-content
- * for more details.
- */
- alignContent: ReactPropTypes.oneOf([
- 'flex-start',
- 'flex-end',
- 'center',
- 'stretch',
- 'space-between',
- 'space-around',
- ]),
-
- /** `overflow` controls how children are measured and displayed.
- * `overflow: hidden` causes views to be clipped while `overflow: scroll`
- * causes views to be measured independently of their parents main axis.
- * It works like `overflow` in CSS (default: visible).
- * See https://developer.mozilla.org/en/docs/Web/CSS/overflow
- * for more details.
- * `overflow: visible` only works on iOS. On Android, all views will clip
- * their children.
- */
- overflow: ReactPropTypes.oneOf(['visible', 'hidden', 'scroll']),
-
- /** In React Native `flex` does not work the same way that it does in CSS.
- * `flex` is a number rather than a string, and it works
- * according to the `Yoga` library
- * at https://github.com/facebook/yoga
- *
- * When `flex` is a positive number, it makes the component flexible
- * and it will be sized proportional to its flex value. So a
- * component with `flex` set to 2 will take twice the space as a
- * component with `flex` set to 1.
- *
- * When `flex` is 0, the component is sized according to `width`
- * and `height` and it is inflexible.
- *
- * When `flex` is -1, the component is normally sized according
- * `width` and `height`. However, if there's not enough space,
- * the component will shrink to its `minWidth` and `minHeight`.
- *
- * flexGrow, flexShrink, and flexBasis work the same as in CSS.
- */
- flex: ReactPropTypes.number,
- flexGrow: ReactPropTypes.number,
- flexShrink: ReactPropTypes.number,
- flexBasis: ReactPropTypes.oneOfType([
- ReactPropTypes.number,
- ReactPropTypes.string,
- ]),
-
- /**
- * Aspect ratio control the size of the undefined dimension of a node. Aspect ratio is a
- * non-standard property only available in react native and not CSS.
- *
- * - On a node with a set width/height aspect ratio control the size of the unset dimension
- * - On a node with a set flex basis aspect ratio controls the size of the node in the cross axis
- * if unset
- * - On a node with a measure function aspect ratio works as though the measure function measures
- * the flex basis
- * - On a node with flex grow/shrink aspect ratio controls the size of the node in the cross axis
- * if unset
- * - Aspect ratio takes min/max dimensions into account
- */
- aspectRatio: ReactPropTypes.number,
-
- /** `zIndex` controls which components display on top of others.
- * Normally, you don't use `zIndex`. Components render according to
- * their order in the document tree, so later components draw over
- * earlier ones. `zIndex` may be useful if you have animations or custom
- * modal interfaces where you don't want this behavior.
- *
- * It works like the CSS `z-index` property - components with a larger
- * `zIndex` will render on top. Think of the z-direction like it's
- * pointing from the phone into your eyeball.
- * See https://developer.mozilla.org/en-US/docs/Web/CSS/z-index for
- * more details.
- */
- zIndex: ReactPropTypes.number,
-
- /** `direction` specifies the directional flow of the user interface.
- * The default is `inherit`, except for root node which will have
- * value based on the current locale.
- * See https://facebook.github.io/yoga/docs/rtl/
- * for more details.
- * @platform ios
- */
- direction: ReactPropTypes.oneOf(['inherit', 'ltr', 'rtl']),
-};
-
-module.exports = LayoutPropTypes;

Libraries/StyleSheet/PointPropType.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,16 +10,7 @@
'use strict';
-const PropTypes = require('prop-types');
-
-const PointPropType = PropTypes.shape({
- x: PropTypes.number,
- y: PropTypes.number,
-});
-
export type PointProp = $ReadOnly<{
x: number,
y: number,
}>;
-
-module.exports = PointPropType;

Libraries/StyleSheet/processColor.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/StyleSheet/processTransform.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -13,7 +13,7 @@
const MatrixMath = require('MatrixMath');
const Platform = require('Platform');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
const stringifySafe = require('stringifySafe');
/**
@@ -170,17 +170,29 @@
switch (key) {
case 'matrix':
invariant(
+ /* $FlowFixMe(>=0.88.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.88 was deployed. To see the error, delete
+ * this comment and run Flow. */
value.length === 9 || value.length === 16,
'Matrix transform must have a length of 9 (2d) or 16 (3d). ' +
'Provided matrix has a length of %s: %s',
+ /* $FlowFixMe(>=0.84.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.84 was deployed. To see the error, delete
+ * this comment and run Flow. */
value.length,
stringifySafe(transformation),
);
break;
case 'translate':
invariant(
+ /* $FlowFixMe(>=0.88.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.88 was deployed. To see the error, delete
+ * this comment and run Flow. */
value.length === 2 || value.length === 3,
'Transform with key translate must be an array of length 2 or 3, found %s: %s',
+ /* $FlowFixMe(>=0.84.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.84 was deployed. To see the error, delete
+ * this comment and run Flow. */
value.length,
stringifySafe(transformation),
);

Libraries/StyleSheet/setNormalizedColorAlpha.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/StyleSheet/StyleSheet.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -25,9 +25,6 @@
____TextStyleProp_Internal,
____ImageStyle_Internal,
____ImageStyleProp_Internal,
- ____LayoutStyle_Internal,
- ____ShadowStyle_Internal,
- ____TransformStyle_Internal,
} from 'StyleSheetTypes';
/**
@@ -154,21 +151,12 @@
*/
export type DangerouslyImpreciseStyle = ____DangerouslyImpreciseStyle_Internal;
-/**
- * These types are simlilar to the style types above. They are objects of the
- * possible style keys in that group. For example, ShadowStyle contains
- * keys like `shadowColor` and `shadowRadius`.
- */
-export type LayoutStyle = ____LayoutStyle_Internal;
-export type ShadowStyle = ____ShadowStyle_Internal;
-export type TransformStyle = ____TransformStyle_Internal;
-
let hairlineWidth = PixelRatio.roundToNearestPixel(0.4);
if (hairlineWidth === 0) {
hairlineWidth = 1 / PixelRatio.get();
}
-const absoluteFill: LayoutStyle = {
+const absoluteFill = {
position: 'absolute',
left: 0,
right: 0,

Libraries/StyleSheet/StyleSheetPropType.js

@@ -1,31 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow strict-local
- */
-
-'use strict';
-
-const createStrictShapeTypeChecker = require('createStrictShapeTypeChecker');
-const flattenStyle = require('flattenStyle');
-
-function StyleSheetPropType(shape: {
- [key: string]: ReactPropsCheckType,
-}): ReactPropsCheckType {
- const shapePropType = createStrictShapeTypeChecker(shape);
- return function(props, propName, componentName, location?, ...rest) {
- let newProps = props;
- if (props[propName]) {
- // Just make a dummy prop object with only the flattened style
- newProps = {};
- newProps[propName] = flattenStyle(props[propName]);
- }
- return shapePropType(newProps, propName, componentName, location, ...rest);
- };
-}
-
-module.exports = StyleSheetPropType;

Libraries/StyleSheet/StyleSheetTypes.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -15,48 +15,333 @@
export type ColorValue = null | string;
export type DimensionValue = null | number | string | AnimatedNode;
-export type ____LayoutStyle_Internal = $ReadOnly<{|
+/**
+ * React Native's layout system is based on Flexbox and is powered both
+ * on iOS and Android by an open source project called `Yoga`:
+ * https://github.com/facebook/yoga
+ *
+ * The implementation in Yoga is slightly different from what the
+ * Flexbox spec defines - for example, we chose more sensible default
+ * values. Since our layout docs are generated from the comments in this
+ * file, please keep a brief comment describing each prop type.
+ *
+ * These properties are a subset of our styles that are consumed by the layout
+ * algorithm and affect the positioning and sizing of views.
+ */
+type ____LayoutStyle_Internal = $ReadOnly<{|
+ /** `display` sets the display type of this component.
+ *
+ * It works similarly to `display` in CSS, but only support 'flex' and 'none'.
+ * 'flex' is the default.
+ */
display?: 'none' | 'flex',
+
+ /** `width` sets the width of this component.
+ *
+ * It works similarly to `width` in CSS, but in React Native you
+ * must use points or percentages. Ems and other units are not supported.
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/width for more details.
+ */
width?: DimensionValue,
+
+ /** `height` sets the height of this component.
+ *
+ * It works similarly to `height` in CSS, but in React Native you
+ * must use points or percentages. Ems and other units are not supported.
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/height for more details.
+ */
height?: DimensionValue,
+
+ /** `bottom` is the number of logical pixels to offset the bottom edge of
+ * this component.
+ *
+ * It works similarly to `bottom` in CSS, but in React Native you
+ * must use points or percentages. Ems and other units are not supported.
+ *
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/bottom
+ * for more details of how `bottom` affects layout.
+ */
bottom?: DimensionValue,
+
+ /**
+ * When the direction is `ltr`, `end` is equivalent to `right`.
+ * When the direction is `rtl`, `end` is equivalent to `left`.
+ *
+ * This style takes precedence over the `left` and `right` styles.
+ */
end?: DimensionValue,
+
+ /** `left` is the number of logical pixels to offset the left edge of
+ * this component.
+ *
+ * It works similarly to `left` in CSS, but in React Native you
+ * must use points or percentages. Ems and other units are not supported.
+ *
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/left
+ * for more details of how `left` affects layout.
+ */
left?: DimensionValue,
+
+ /** `right` is the number of logical pixels to offset the right edge of
+ * this component.
+ *
+ * It works similarly to `right` in CSS, but in React Native you
+ * must use points or percentages. Ems and other units are not supported.
+ *
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/right
+ * for more details of how `right` affects layout.
+ */
right?: DimensionValue,
+
+ /**
+ * When the direction is `ltr`, `start` is equivalent to `left`.
+ * When the direction is `rtl`, `start` is equivalent to `right`.
+ *
+ * This style takes precedence over the `left`, `right`, and `end` styles.
+ */
start?: DimensionValue,
+
+ /** `top` is the number of logical pixels to offset the top edge of
+ * this component.
+ *
+ * It works similarly to `top` in CSS, but in React Native you
+ * must use points or percentages. Ems and other units are not supported.
+ *
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/top
+ * for more details of how `top` affects layout.
+ */
top?: DimensionValue,
+
+ /** `minWidth` is the minimum width for this component, in logical pixels.
+ *
+ * It works similarly to `min-width` in CSS, but in React Native you
+ * must use points or percentages. Ems and other units are not supported.
+ *
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/min-width
+ * for more details.
+ */
minWidth?: DimensionValue,
+
+ /** `maxWidth` is the maximum width for this component, in logical pixels.
+ *
+ * It works similarly to `max-width` in CSS, but in React Native you
+ * must use points or percentages. Ems and other units are not supported.
+ *
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/max-width
+ * for more details.
+ */
maxWidth?: DimensionValue,
+
+ /** `minHeight` is the minimum height for this component, in logical pixels.
+ *
+ * It works similarly to `min-height` in CSS, but in React Native you
+ * must use points or percentages. Ems and other units are not supported.
+ *
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/min-height
+ * for more details.
+ */
minHeight?: DimensionValue,
+
+ /** `maxHeight` is the maximum height for this component, in logical pixels.
+ *
+ * It works similarly to `max-height` in CSS, but in React Native you
+ * must use points or percentages. Ems and other units are not supported.
+ *
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/max-height
+ * for more details.
+ */
maxHeight?: DimensionValue,
+
+ /** Setting `margin` has the same effect as setting each of
+ * `marginTop`, `marginLeft`, `marginBottom`, and `marginRight`.
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/margin
+ * for more details.
+ */
margin?: DimensionValue,
+
+ /** `marginBottom` works like `margin-bottom` in CSS.
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/margin-bottom
+ * for more details.
+ */
marginBottom?: DimensionValue,
+
+ /**
+ * When direction is `ltr`, `marginEnd` is equivalent to `marginRight`.
+ * When direction is `rtl`, `marginEnd` is equivalent to `marginLeft`.
+ */
marginEnd?: DimensionValue,
+
+ /** Setting `marginHorizontal` has the same effect as setting
+ * both `marginLeft` and `marginRight`.
+ */
marginHorizontal?: DimensionValue,
+
+ /** `marginLeft` works like `margin-left` in CSS.
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/margin-left
+ * for more details.
+ */
marginLeft?: DimensionValue,
+
+ /** `marginRight` works like `margin-right` in CSS.
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/margin-right
+ * for more details.
+ */
marginRight?: DimensionValue,
+
+ /**
+ * When direction is `ltr`, `marginStart` is equivalent to `marginLeft`.
+ * When direction is `rtl`, `marginStart` is equivalent to `marginRight`.
+ */
marginStart?: DimensionValue,
+
+ /** `marginTop` works like `margin-top` in CSS.
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/margin-top
+ * for more details.
+ */
marginTop?: DimensionValue,
+
+ /** Setting `marginVertical` has the same effect as setting both
+ * `marginTop` and `marginBottom`.
+ */
marginVertical?: DimensionValue,
+
+ /** Setting `padding` has the same effect as setting each of
+ * `paddingTop`, `paddingBottom`, `paddingLeft`, and `paddingRight`.
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/padding
+ * for more details.
+ */
padding?: DimensionValue,
+
+ /** `paddingBottom` works like `padding-bottom` in CSS.
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/padding-bottom
+ * for more details.
+ */
paddingBottom?: DimensionValue,
+
+ /**
+ * When direction is `ltr`, `paddingEnd` is equivalent to `paddingRight`.
+ * When direction is `rtl`, `paddingEnd` is equivalent to `paddingLeft`.
+ */
paddingEnd?: DimensionValue,
+
+ /** Setting `paddingHorizontal` is like setting both of
+ * `paddingLeft` and `paddingRight`.
+ */
paddingHorizontal?: DimensionValue,
+
+ /** `paddingLeft` works like `padding-left` in CSS.
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/padding-left
+ * for more details.
+ */
paddingLeft?: DimensionValue,
+
+ /** `paddingRight` works like `padding-right` in CSS.
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/padding-right
+ * for more details.
+ */
paddingRight?: DimensionValue,
+
+ /**
+ * When direction is `ltr`, `paddingStart` is equivalent to `paddingLeft`.
+ * When direction is `rtl`, `paddingStart` is equivalent to `paddingRight`.
+ */
paddingStart?: DimensionValue,
+
+ /** `paddingTop` works like `padding-top` in CSS.
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/padding-top
+ * for more details.
+ */
paddingTop?: DimensionValue,
+
+ /** Setting `paddingVertical` is like setting both of
+ * `paddingTop` and `paddingBottom`.
+ */
paddingVertical?: DimensionValue,
+
+ /** `borderWidth` works like `border-width` in CSS.
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/border-width
+ * for more details.
+ */
borderWidth?: number,
+
+ /** `borderBottomWidth` works like `border-bottom-width` in CSS.
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/border-bottom-width
+ * for more details.
+ */
borderBottomWidth?: number,
+
+ /**
+ * When direction is `ltr`, `borderEndWidth` is equivalent to `borderRightWidth`.
+ * When direction is `rtl`, `borderEndWidth` is equivalent to `borderLeftWidth`.
+ */
borderEndWidth?: number,
+
+ /** `borderLeftWidth` works like `border-left-width` in CSS.
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/border-left-width
+ * for more details.
+ */
borderLeftWidth?: number,
+
+ /** `borderRightWidth` works like `border-right-width` in CSS.
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/border-right-width
+ * for more details.
+ */
borderRightWidth?: number,
+
+ /**
+ * When direction is `ltr`, `borderStartWidth` is equivalent to `borderLeftWidth`.
+ * When direction is `rtl`, `borderStartWidth` is equivalent to `borderRightWidth`.
+ */
borderStartWidth?: number,
+
+ /** `borderTopWidth` works like `border-top-width` in CSS.
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/border-top-width
+ * for more details.
+ */
borderTopWidth?: number,
+
+ /** `position` in React Native is similar to regular CSS, but
+ * everything is set to `relative` by default, so `absolute`
+ * positioning is always just relative to the parent.
+ *
+ * If you want to position a child using specific numbers of logical
+ * pixels relative to its parent, set the child to have `absolute`
+ * position.
+ *
+ * If you want to position a child relative to something
+ * that is not its parent, just don't use styles for that. Use the
+ * component tree.
+ *
+ * See https://github.com/facebook/yoga
+ * for more details on how `position` differs between React Native
+ * and CSS.
+ */
position?: 'absolute' | 'relative',
+
+ /** `flexDirection` controls which directions children of a container go.
+ * `row` goes left to right, `column` goes top to bottom, and you may
+ * be able to guess what the other two do. It works like `flex-direction`
+ * in CSS, except the default is `column`.
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/flex-direction
+ * for more details.
+ */
flexDirection?: 'row' | 'row-reverse' | 'column' | 'column-reverse',
+
+ /** `flexWrap` controls whether children can wrap around after they
+ * hit the end of a flex container.
+ * It works like `flex-wrap` in CSS (default: nowrap).
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/flex-wrap
+ * for more details.
+ */
flexWrap?: 'wrap' | 'nowrap' | 'wrap-reverse',
+
+ /** `justifyContent` aligns children in the main direction.
+ * For example, if children are flowing vertically, `justifyContent`
+ * controls how they align vertically.
+ * It works like `justify-content` in CSS (default: flex-start).
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/justify-content
+ * for more details.
+ */
justifyContent?:
| 'flex-start'
| 'flex-end'
@@ -64,7 +349,22 @@
| 'space-between'
| 'space-around'
| 'space-evenly',
+
+ /** `alignItems` aligns children in the cross direction.
+ * For example, if children are flowing vertically, `alignItems`
+ * controls how they align horizontally.
+ * It works like `align-items` in CSS (default: stretch).
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/align-items
+ * for more details.
+ */
alignItems?: 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline',
+
+ /** `alignSelf` controls how a child aligns in the cross direction,
+ * overriding the `alignItems` of the parent. It works like `align-self`
+ * in CSS (default: auto).
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/align-self
+ * for more details.
+ */
alignSelf?:
| 'auto'
| 'flex-start'
@@ -72,6 +372,12 @@
| 'center'
| 'stretch'
| 'baseline',
+
+ /** `alignContent` controls how rows align in the cross direction,
+ * overriding the `alignContent` of the parent.
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/align-content
+ * for more details.
+ */
alignContent?:
| 'flex-start'
| 'flex-end'
@@ -79,17 +385,98 @@
| 'stretch'
| 'space-between'
| 'space-around',
+
+ /** `overflow` controls how children are measured and displayed.
+ * `overflow: hidden` causes views to be clipped while `overflow: scroll`
+ * causes views to be measured independently of their parents main axis.
+ * It works like `overflow` in CSS (default: visible).
+ * See https://developer.mozilla.org/en/docs/Web/CSS/overflow
+ * for more details.
+ * `overflow: visible` only works on iOS. On Android, all views will clip
+ * their children.
+ */
overflow?: 'visible' | 'hidden' | 'scroll',
+
+ /** In React Native `flex` does not work the same way that it does in CSS.
+ * `flex` is a number rather than a string, and it works
+ * according to the `Yoga` library
+ * at https://github.com/facebook/yoga
+ *
+ * When `flex` is a positive number, it makes the component flexible
+ * and it will be sized proportional to its flex value. So a
+ * component with `flex` set to 2 will take twice the space as a
+ * component with `flex` set to 1.
+ *
+ * When `flex` is 0, the component is sized according to `width`
+ * and `height` and it is inflexible.
+ *
+ * When `flex` is -1, the component is normally sized according
+ * `width` and `height`. However, if there's not enough space,
+ * the component will shrink to its `minWidth` and `minHeight`.
+ *
+ * flexGrow, flexShrink, and flexBasis work the same as in CSS.
+ */
flex?: number,
flexGrow?: number,
flexShrink?: number,
flexBasis?: number | string,
+
+ /**
+ * Aspect ratio control the size of the undefined dimension of a node. Aspect ratio is a
+ * non-standard property only available in react native and not CSS.
+ *
+ * - On a node with a set width/height aspect ratio control the size of the unset dimension
+ * - On a node with a set flex basis aspect ratio controls the size of the node in the cross axis
+ * if unset
+ * - On a node with a measure function aspect ratio works as though the measure function measures
+ * the flex basis
+ * - On a node with flex grow/shrink aspect ratio controls the size of the node in the cross axis
+ * if unset
+ * - Aspect ratio takes min/max dimensions into account
+ */
aspectRatio?: number,
+
+ /** `zIndex` controls which components display on top of others.
+ * Normally, you don't use `zIndex`. Components render according to
+ * their order in the document tree, so later components draw over
+ * earlier ones. `zIndex` may be useful if you have animations or custom
+ * modal interfaces where you don't want this behavior.
+ *
+ * It works like the CSS `z-index` property - components with a larger
+ * `zIndex` will render on top. Think of the z-direction like it's
+ * pointing from the phone into your eyeball.
+ * See https://developer.mozilla.org/en-US/docs/Web/CSS/z-index for
+ * more details.
+ */
zIndex?: number,
+
+ /** `direction` specifies the directional flow of the user interface.
+ * The default is `inherit`, except for root node which will have
+ * value based on the current locale.
+ * See https://facebook.github.io/yoga/docs/rtl/
+ * for more details.
+ * @platform ios
+ */
direction?: 'inherit' | 'ltr' | 'rtl',
|}>;
-export type ____TransformStyle_Internal = $ReadOnly<{|
+type ____TransformStyle_Internal = $ReadOnly<{|
+ /**
+ * `transform` accepts an array of transformation objects. Each object specifies
+ * the property that will be transformed as the key, and the value to use in the
+ * transformation. Objects should not be combined. Use a single key/value pair
+ * per object.
+ *
+ * The rotate transformations require a string so that the transform may be
+ * expressed in degrees (deg) or radians (rad). For example:
+ *
+ * `transform([{ rotateX: '45deg' }, { rotateZ: '0.785398rad' }])`
+ *
+ * The skew transformations require a string so that the transform may be
+ * expressed in degrees (deg). For example:
+ *
+ * `transform([{ skewX: '45deg' }])`
+ */
transform?: $ReadOnlyArray<
| {|+perspective: number | AnimatedNode|}
| {|+rotate: string | AnimatedNode|}
@@ -115,13 +502,38 @@
>,
|}>;
+/**
+ * These props can be used to dynamically generate shadows on views, images, text, etc.
+ *
+ * Because they are dynamically generated, they may cause performance regressions. Static
+ * shadow image asset may be a better way to go for optimal performance.
+ *
+ * These properties are iOS only - for similar functionality on Android, use the [`elevation`
+ * property](docs/viewstyleproptypes.html#elevation).
+ */
export type ____ShadowStyle_Internal = $ReadOnly<{|
+ /**
+ * Sets the drop shadow color
+ * @platform ios
+ */
shadowColor?: ColorValue,
+ /**
+ * Sets the drop shadow offset
+ * @platform ios
+ */
shadowOffset?: $ReadOnly<{|
width?: number,
height?: number,
|}>,
+ /**
+ * Sets the drop shadow opacity (multiplied by the color's alpha component)
+ * @platform ios
+ */
shadowOpacity?: number | AnimatedNode,
+ /**
+ * Sets the drop shadow blur radius
+ * @platform ios
+ */
shadowRadius?: number,
|}>;

Libraries/StyleSheet/StyleSheetValidation.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,11 +10,11 @@
'use strict';
-const ImageStylePropTypes = require('ImageStylePropTypes');
+const DeprecatedImageStylePropTypes = require('DeprecatedImageStylePropTypes');
const TextStylePropTypes = require('TextStylePropTypes');
-const ViewStylePropTypes = require('ViewStylePropTypes');
+const DeprecatedViewStylePropTypes = require('DeprecatedViewStylePropTypes');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
// Hardcoded because this is a legit case but we don't want to load it from
// a private API. We might likely want to unify style sheet creation with how it
@@ -24,7 +24,7 @@
class StyleSheetValidation {
static validateStyleProp(prop: string, style: Object, caller: string) {
- if (!__DEV__) {
+ if (!__DEV__ || global.__RCTProfileIsProfiling) {
return;
}
if (allStylePropTypes[prop] === undefined) {
@@ -48,7 +48,7 @@
}
static validateStyle(name: string, styles: Object) {
- if (!__DEV__) {
+ if (!__DEV__ || global.__RCTProfileIsProfiling) {
return;
}
for (const prop in styles[name]) {
@@ -60,7 +60,13 @@
}
}
+ /* $FlowFixMe(>=0.85.0 site=react_native_fb) This comment suppresses an error
+ * found when Flow v0.85 was deployed. To see the error, delete this comment
+ * and run Flow. */
static addValidStylePropTypes(stylePropTypes) {
+ if (!__DEV__ || global.__RCTProfileIsProfiling) {
+ return;
+ }
for (const key in stylePropTypes) {
allStylePropTypes[key] = stylePropTypes[key];
}
@@ -81,8 +87,10 @@
const allStylePropTypes = {};
-StyleSheetValidation.addValidStylePropTypes(ImageStylePropTypes);
-StyleSheetValidation.addValidStylePropTypes(TextStylePropTypes);
-StyleSheetValidation.addValidStylePropTypes(ViewStylePropTypes);
+if (__DEV__ && !global.__RCTProfileIsProfiling) {
+ StyleSheetValidation.addValidStylePropTypes(DeprecatedImageStylePropTypes);
+ StyleSheetValidation.addValidStylePropTypes(TextStylePropTypes);
+ StyleSheetValidation.addValidStylePropTypes(DeprecatedViewStylePropTypes);
+}
module.exports = StyleSheetValidation;

Libraries/StyleSheet/TransformPropTypes.js

@@ -1,109 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow
- */
-
-'use strict';
-
-const ReactPropTypes = require('prop-types');
-
-const deprecatedPropType = require('deprecatedPropType');
-
-const TransformMatrixPropType = function(
- props: Object,
- propName: string,
- componentName: string,
-): ?Error {
- if (props[propName]) {
- return new Error(
- 'The transformMatrix style property is deprecated. ' +
- 'Use `transform: [{ matrix: ... }]` instead.',
- );
- }
-};
-
-const DecomposedMatrixPropType = function(
- props: Object,
- propName: string,
- componentName: string,
-): ?Error {
- if (props[propName]) {
- return new Error(
- 'The decomposedMatrix style property is deprecated. ' +
- 'Use `transform: [...]` instead.',
- );
- }
-};
-
-const TransformPropTypes = {
- /**
- * `transform` accepts an array of transformation objects. Each object specifies
- * the property that will be transformed as the key, and the value to use in the
- * transformation. Objects should not be combined. Use a single key/value pair
- * per object.
- *
- * The rotate transformations require a string so that the transform may be
- * expressed in degrees (deg) or radians (rad). For example:
- *
- * `transform([{ rotateX: '45deg' }, { rotateZ: '0.785398rad' }])`
- *
- * The skew transformations require a string so that the transform may be
- * expressed in degrees (deg). For example:
- *
- * `transform([{ skewX: '45deg' }])`
- */
- transform: ReactPropTypes.arrayOf(
- ReactPropTypes.oneOfType([
- ReactPropTypes.shape({perspective: ReactPropTypes.number}),
- ReactPropTypes.shape({rotate: ReactPropTypes.string}),
- ReactPropTypes.shape({rotateX: ReactPropTypes.string}),
- ReactPropTypes.shape({rotateY: ReactPropTypes.string}),
- ReactPropTypes.shape({rotateZ: ReactPropTypes.string}),
- ReactPropTypes.shape({scale: ReactPropTypes.number}),
- ReactPropTypes.shape({scaleX: ReactPropTypes.number}),
- ReactPropTypes.shape({scaleY: ReactPropTypes.number}),
- ReactPropTypes.shape({translateX: ReactPropTypes.number}),
- ReactPropTypes.shape({translateY: ReactPropTypes.number}),
- ReactPropTypes.shape({skewX: ReactPropTypes.string}),
- ReactPropTypes.shape({skewY: ReactPropTypes.string}),
- ]),
- ),
-
- /**
- * Deprecated. Use the transform prop instead.
- */
- transformMatrix: TransformMatrixPropType,
- /**
- * Deprecated. Use the transform prop instead.
- */
- decomposedMatrix: DecomposedMatrixPropType,
-
- /* Deprecated transform props used on Android only */
- scaleX: deprecatedPropType(
- ReactPropTypes.number,
- 'Use the transform prop instead.',
- ),
- scaleY: deprecatedPropType(
- ReactPropTypes.number,
- 'Use the transform prop instead.',
- ),
- rotation: deprecatedPropType(
- ReactPropTypes.number,
- 'Use the transform prop instead.',
- ),
- translateX: deprecatedPropType(
- ReactPropTypes.number,
- 'Use the transform prop instead.',
- ),
- translateY: deprecatedPropType(
- ReactPropTypes.number,
- 'Use the transform prop instead.',
- ),
-};
-
-module.exports = TransformPropTypes;

Libraries/SurfaceBackedComponent/RCTSurfaceBackedComponent.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/SurfaceBackedComponent/RCTSurfaceBackedComponent.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -38,6 +38,8 @@
moduleName:moduleName
initialProperties:properties];
+ [surface start];
+
state = [RCTSurfaceBackedComponentState newWithSurface:surface];
CKComponentScope::replaceState(scope, state);

Libraries/SurfaceBackedComponent/RCTSurfaceBackedComponentState.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/SurfaceBackedComponent/RCTSurfaceBackedComponentState.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/SurfaceHostingComponent/RCTSurfaceHostingComponentController.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/SurfaceHostingComponent/RCTSurfaceHostingComponentController.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/SurfaceHostingComponent/RCTSurfaceHostingComponent.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/SurfaceHostingComponent/RCTSurfaceHostingComponent+Internal.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/SurfaceHostingComponent/RCTSurfaceHostingComponent.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/SurfaceHostingComponent/RCTSurfaceHostingComponentOptions.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/SurfaceHostingComponent/RCTSurfaceHostingComponentState.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/SurfaceHostingComponent/RCTSurfaceHostingComponentState.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/BaseText/RCTBaseTextShadowView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/BaseText/RCTBaseTextShadowView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/BaseText/RCTBaseTextViewManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/BaseText/RCTBaseTextViewManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -36,6 +36,7 @@
RCT_REMAP_SHADOW_PROPERTY(fontStyle, textAttributes.fontStyle, NSString)
RCT_REMAP_SHADOW_PROPERTY(fontVariant, textAttributes.fontVariant, NSArray)
RCT_REMAP_SHADOW_PROPERTY(allowFontScaling, textAttributes.allowFontScaling, BOOL)
+RCT_REMAP_SHADOW_PROPERTY(maxFontSizeMultiplier, textAttributes.maxFontSizeMultiplier, CGFloat)
RCT_REMAP_SHADOW_PROPERTY(letterSpacing, textAttributes.letterSpacing, CGFloat)
// Paragraph Styles
RCT_REMAP_SHADOW_PROPERTY(lineHeight, textAttributes.lineHeight, CGFloat)

Libraries/Text/RawText/RCTRawTextShadowView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/RawText/RCTRawTextShadowView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/RawText/RCTRawTextViewManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/RawText/RCTRawTextViewManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/RCTConvert+Text.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/RCTConvert+Text.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/RCTTextAttributes.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -31,6 +31,7 @@
@property (nonatomic, copy, nullable) NSString *fontFamily;
@property (nonatomic, assign) CGFloat fontSize;
@property (nonatomic, assign) CGFloat fontSizeMultiplier;
+@property (nonatomic, assign) CGFloat maxFontSizeMultiplier;
@property (nonatomic, copy, nullable) NSString *fontWeight;
@property (nonatomic, copy, nullable) NSString *fontStyle;
@property (nonatomic, copy, nullable) NSArray<NSString *> *fontVariant;
@@ -71,7 +72,7 @@
- (UIFont *)effectiveFont;
/**
- * Font size multiplier reflects `allowFontScaling` and `fontSizeMultiplier`.
+ * Font size multiplier reflects `allowFontScaling`, `fontSizeMultiplier`, and `maxFontSizeMultiplier`.
*/
- (CGFloat)effectiveFontSizeMultiplier;

Libraries/Text/RCTTextAttributes.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -24,6 +24,7 @@
_lineHeight = NAN;
_textDecorationStyle = NSUnderlineStyleSingle;
_fontSizeMultiplier = NAN;
+ _maxFontSizeMultiplier = NAN;
_alignment = NSTextAlignmentNatural;
_baseWritingDirection = NSWritingDirectionNatural;
_textShadowRadius = NAN;
@@ -49,6 +50,7 @@
_fontFamily = textAttributes->_fontFamily ?: _fontFamily;
_fontSize = !isnan(textAttributes->_fontSize) ? textAttributes->_fontSize : _fontSize;
_fontSizeMultiplier = !isnan(textAttributes->_fontSizeMultiplier) ? textAttributes->_fontSizeMultiplier : _fontSizeMultiplier;
+ _maxFontSizeMultiplier = !isnan(textAttributes->_maxFontSizeMultiplier) ? textAttributes->_maxFontSizeMultiplier : _maxFontSizeMultiplier;
_fontWeight = textAttributes->_fontWeight ?: _fontWeight;
_fontStyle = textAttributes->_fontStyle ?: _fontStyle;
_fontVariant = textAttributes->_fontVariant ?: _fontVariant;
@@ -191,7 +193,15 @@
- (CGFloat)effectiveFontSizeMultiplier
{
- return !RCTHasFontHandlerSet() && _allowFontScaling && !isnan(_fontSizeMultiplier) ? _fontSizeMultiplier : 1.0;
+ bool fontScalingEnabled = !RCTHasFontHandlerSet() && _allowFontScaling;
+
+ if (fontScalingEnabled) {
+ CGFloat fontSizeMultiplier = !isnan(_fontSizeMultiplier) ? _fontSizeMultiplier : 1.0;
+ CGFloat maxFontSizeMultiplier = !isnan(_maxFontSizeMultiplier) ? _maxFontSizeMultiplier : 0.0;
+ return maxFontSizeMultiplier >= 1.0 ? fminf(maxFontSizeMultiplier, fontSizeMultiplier) : fontSizeMultiplier;
+ } else {
+ return 1.0;
+ }
}
- (UIColor *)effectiveForegroundColor
@@ -260,6 +270,7 @@
RCTTextAttributesCompareObjects(_fontFamily) &&
RCTTextAttributesCompareFloats(_fontSize) &&
RCTTextAttributesCompareFloats(_fontSizeMultiplier) &&
+ RCTTextAttributesCompareFloats(_maxFontSizeMultiplier) &&
RCTTextAttributesCompareStrings(_fontWeight) &&
RCTTextAttributesCompareObjects(_fontStyle) &&
RCTTextAttributesCompareObjects(_fontVariant) &&

Libraries/Text/RCTTextTransform.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/Text/NSTextStorage+FontScaling.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/Text/NSTextStorage+FontScaling.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/Text/RCTTextShadowView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/Text/RCTTextShadowView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/Text/RCTTextView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/Text/RCTTextView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/Text/RCTTextViewManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/Text/RCTTextViewManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -24,7 +24,6 @@
@implementation RCTTextViewManager
{
NSHashTable<RCTTextShadowView *> *_shadowViews;
- CGFloat _fontSizeMultiplier;
}
RCT_EXPORT_MODULE(RCTText)

Libraries/Text/TextAncestor.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -15,4 +15,7 @@
/**
* Whether the current element is the descendant of a <Text> element.
*/
+/* $FlowFixMe(>=0.85.0 site=react_native_fb) This comment suppresses an error
+ * found when Flow v0.85 was deployed. To see the error, delete this comment
+ * and run Flow. */
module.exports = React.createContext(false);

Libraries/Text/TextInput/Multiline/RCTMultilineTextInputView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/Multiline/RCTMultilineTextInputView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/Multiline/RCTMultilineTextInputViewManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/Multiline/RCTMultilineTextInputViewManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/Multiline/RCTUITextView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/Multiline/RCTUITextView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/RCTBackedTextInputDelegate.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/RCTBackedTextInputViewProtocol.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/RCTBaseTextInputShadowView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/RCTBaseTextInputShadowView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/RCTBaseTextInputView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -43,6 +43,7 @@
@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;

Libraries/Text/TextInput/RCTBaseTextInputView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -105,12 +105,22 @@
// Similarly, when the user is in the middle of inputting some text in Japanese/Chinese, there will be styling on the
// text that we should disregard. See https://developer.apple.com/documentation/uikit/uitextinput/1614489-markedtextrange?language=objc
// for more info.
+ // If the user added an emoji, the sytem adds a font attribute for the emoji and stores the original font in NSOriginalFont.
// Lastly, when entering a password, etc., there will be additional styling on the field as the native text view
// handles showing the last character for a split second.
+ __block BOOL fontHasBeenUpdatedBySystem = false;
+ [oldText enumerateAttribute:@"NSOriginalFont" inRange:NSMakeRange(0, oldText.length) options:0 usingBlock:^(id value, NSRange range, BOOL *stop) {
+ if (value){
+ fontHasBeenUpdatedBySystem = true;
+ }
+ }];
+
BOOL shouldFallbackToBareTextComparison =
[self.backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"dictation"] ||
self.backedTextInputView.markedTextRange ||
- self.backedTextInputView.isSecureTextEntry;
+ self.backedTextInputView.isSecureTextEntry ||
+ fontHasBeenUpdatedBySystem;
+
if (shouldFallbackToBareTextComparison) {
return ([newText.string isEqualToString:oldText.string]);
} else {
@@ -193,9 +203,65 @@
{
#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
}
@@ -217,6 +283,24 @@
}
}
+- (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
@@ -320,18 +404,12 @@
}
}
- 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
- _predictedText = backedTextInputView.attributedText.string;
- }
+ NSString *previousText = backedTextInputView.attributedText.string ?: @"";
- NSString *previousText = [_predictedText substringWithRange:range] ?: @"";
-
- if (!_predictedText || backedTextInputView.attributedText.string.length == 0) {
- _predictedText = text;
+ if (range.location + range.length > backedTextInputView.attributedText.string.length) {
+ _predictedText = backedTextInputView.attributedText.string;
} else {
- _predictedText = [_predictedText stringByReplacingCharactersInRange:range withString:text];
+ _predictedText = [backedTextInputView.attributedText.string stringByReplacingCharactersInRange:range withString:text];
}
if (_onTextInput) {
@@ -366,7 +444,6 @@
[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++;

Libraries/Text/TextInput/RCTBaseTextInputViewManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/RCTBaseTextInputViewManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -43,12 +43,12 @@
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)

Libraries/Text/TextInput/RCTInputAccessoryShadowView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/RCTInputAccessoryShadowView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/RCTInputAccessoryViewContent.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/RCTInputAccessoryViewContent.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/RCTInputAccessoryView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/RCTInputAccessoryView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/RCTInputAccessoryViewManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/RCTInputAccessoryViewManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/RCTTextSelection.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/RCTTextSelection.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputViewManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputViewManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/Singleline/RCTUITextField.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/TextInput/Singleline/RCTUITextField.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -85,6 +85,16 @@
self.enabled = editable;
}
+- (void)setScrollEnabled:(BOOL)enabled
+{
+ // Do noting, compatible with multiline textinput
+}
+
+- (BOOL)scrollEnabled
+{
+ return NO;
+}
+
#pragma mark - Context Menu
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender

Libraries/Text/Text.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,15 +10,15 @@
'use strict';
+const DeprecatedTextPropTypes = require('DeprecatedTextPropTypes');
const React = require('React');
const ReactNativeViewAttributes = require('ReactNativeViewAttributes');
const TextAncestor = require('TextAncestor');
-const TextPropTypes = require('TextPropTypes');
const Touchable = require('Touchable');
const UIManager = require('UIManager');
const createReactNativeComponentClass = require('createReactNativeComponentClass');
-const nullthrows = require('fbjs/lib/nullthrows');
+const nullthrows = require('nullthrows');
const processColor = require('processColor');
import type {PressEvent} from 'CoreEventTypes';
@@ -27,17 +27,17 @@
type ResponseHandlers = $ReadOnly<{|
onStartShouldSetResponder: () => boolean,
- onResponderGrant: (event: SyntheticEvent<>, dispatchID: string) => void,
- onResponderMove: (event: SyntheticEvent<>) => void,
- onResponderRelease: (event: SyntheticEvent<>) => void,
- onResponderTerminate: (event: SyntheticEvent<>) => void,
+ onResponderGrant: (event: PressEvent, dispatchID: string) => void,
+ onResponderMove: (event: PressEvent) => void,
+ onResponderRelease: (event: PressEvent) => void,
+ onResponderTerminate: (event: PressEvent) => void,
onResponderTerminationRequest: () => boolean,
|}>;
-type Props = $ReadOnly<{
+type Props = $ReadOnly<{|
...TextProps,
forwardedRef: ?React.Ref<'RCTText' | 'RCTVirtualText'>,
-}>;
+|}>;
type State = {|
touchable: {|
@@ -58,6 +58,7 @@
numberOfLines: true,
ellipsizeMode: true,
allowFontScaling: true,
+ maxFontSizeMultiplier: true,
disabled: true,
selectable: true,
selectionColor: true,
@@ -92,12 +93,12 @@
touchableHandleLongPress: ?(event: PressEvent) => void;
touchableHandlePress: ?(event: PressEvent) => void;
touchableHandleResponderGrant: ?(
- event: SyntheticEvent<>,
+ event: PressEvent,
dispatchID: string,
) => void;
- touchableHandleResponderMove: ?(event: SyntheticEvent<>) => void;
- touchableHandleResponderRelease: ?(event: SyntheticEvent<>) => void;
- touchableHandleResponderTerminate: ?(event: SyntheticEvent<>) => void;
+ touchableHandleResponderMove: ?(event: PressEvent) => void;
+ touchableHandleResponderRelease: ?(event: PressEvent) => void;
+ touchableHandleResponderTerminate: ?(event: PressEvent) => void;
touchableHandleResponderTerminationRequest: ?() => boolean;
state = {
@@ -107,10 +108,12 @@
responseHandlers: null,
};
- static getDerivedStateFromProps(nextProps: Props, prevState: State): ?State {
+ static getDerivedStateFromProps(
+ nextProps: Props,
+ prevState: State,
+ ): $Shape<State> | null {
return prevState.responseHandlers == null && isTouchable(nextProps)
? {
- ...prevState,
responseHandlers: prevState.createResponderHandlers(),
}
: null;
@@ -170,25 +173,25 @@
}
return shouldSetResponder;
},
- onResponderGrant: (event: SyntheticEvent<>, dispatchID: string): void => {
+ onResponderGrant: (event: PressEvent, dispatchID: string): void => {
nullthrows(this.touchableHandleResponderGrant)(event, dispatchID);
if (this.props.onResponderGrant != null) {
this.props.onResponderGrant.call(this, event, dispatchID);
}
},
- onResponderMove: (event: SyntheticEvent<>): void => {
+ onResponderMove: (event: PressEvent): void => {
nullthrows(this.touchableHandleResponderMove)(event);
if (this.props.onResponderMove != null) {
this.props.onResponderMove.call(this, event);
}
},
- onResponderRelease: (event: SyntheticEvent<>): void => {
+ onResponderRelease: (event: PressEvent): void => {
nullthrows(this.touchableHandleResponderRelease)(event);
if (this.props.onResponderRelease != null) {
this.props.onResponderRelease.call(this, event);
}
},
- onResponderTerminate: (event: SyntheticEvent<>): void => {
+ onResponderTerminate: (event: PressEvent): void => {
nullthrows(this.touchableHandleResponderTerminate)(event);
if (this.props.onResponderTerminate != null) {
this.props.onResponderTerminate.call(this, event);
@@ -257,12 +260,13 @@
);
const RCTVirtualText =
- UIManager.RCTVirtualText == null
+ UIManager.getViewManagerConfig('RCTVirtualText') == null
? RCTText
: createReactNativeComponentClass('RCTVirtualText', () => ({
validAttributes: {
...ReactNativeViewAttributes.UIView,
isHighlighted: true,
+ maxFontSizeMultiplier: true,
},
uiViewClassName: 'RCTVirtualText',
}));
@@ -273,11 +277,15 @@
) => {
return <TouchableText {...props} forwardedRef={forwardedRef} />;
};
-// $FlowFixMe - TODO T29156721 `React.forwardRef` is not defined in Flow, yet.
const TextToExport = React.forwardRef(Text);
TextToExport.displayName = 'Text';
// TODO: Deprecate this.
-TextToExport.propTypes = TextPropTypes;
-
-module.exports = (TextToExport: Class<NativeComponent<TextProps>>);
+/* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an error
+ * found when Flow v0.89 was deployed. To see the error, delete this comment
+ * and run Flow. */
+TextToExport.propTypes = DeprecatedTextPropTypes;
+
+module.exports = ((TextToExport: $FlowFixMe): Class<
+ NativeComponent<TextProps>,
+>);

Libraries/Text/TextProps.js

@@ -1,23 +1,23 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
*
- * @flow
+ * @flow strict-local
* @format
*/
'use strict';
-import type {AccessibilityRole} from 'ViewAccessibility';
-import type {AccessibilityState} from 'ViewAccessibility';
-import type {AccessibilityTrait} from 'ViewAccessibility';
-
-import type {Node} from 'react';
-
-import type {LayoutEvent, PressEvent} from 'CoreEventTypes';
-import type {DangerouslyImpreciseStyleProp} from 'StyleSheet';
+import type {LayoutEvent, PressEvent, TextLayoutEvent} from 'CoreEventTypes';
+import type React from 'React';
+import type {TextStyleProp} from 'StyleSheet';
+import type {
+ AccessibilityRole,
+ AccessibilityStates,
+ AccessibilityTrait,
+} from 'ViewAccessibility';
export type PressRetentionOffset = $ReadOnly<{|
top: number,
@@ -29,37 +29,158 @@
/**
* @see https://facebook.github.io/react-native/docs/text.html#reference
*/
-export type TextProps = $ReadOnly<{
+export type TextProps = $ReadOnly<{|
+ /**
+ * Indicates whether the view is an accessibility element.
+ *
+ * See https://facebook.github.io/react-native/docs/text.html#accessible
+ */
accessible?: ?boolean,
- accessibilityRole?: AccessibilityRole,
- accessibilityStates?: Array<AccessibilityState>,
- accessibilityTraits?: AccessibilityTrait | Array<AccessibilityTrait>,
+ accessibilityHint?: ?Stringish,
+ accessibilityLabel?: ?Stringish,
+ accessibilityRole?: ?AccessibilityRole,
+ accessibilityStates?: ?AccessibilityStates,
+ accessibilityTraits?: ?(AccessibilityTrait | Array<AccessibilityTrait>),
+
+ /**
+ * Whether font should be scaled down automatically.
+ *
+ * See https://facebook.github.io/react-native/docs/text.html#adjustsfontsizetofit
+ */
+ adjustsFontSizeToFit?: ?boolean,
+
+ /**
+ * Whether fonts should scale to respect Text Size accessibility settings.
+ *
+ * See https://facebook.github.io/react-native/docs/text.html#allowfontscaling
+ */
allowFontScaling?: ?boolean,
- children?: Node,
- ellipsizeMode?: 'clip' | 'head' | 'middle' | 'tail',
- nativeID?: string,
+ children?: ?React.Node,
+
+ /**
+ * When `numberOfLines` is set, this prop defines how text will be
+ * truncated.
+ *
+ * See https://facebook.github.io/react-native/docs/text.html#ellipsizemode
+ */
+ ellipsizeMode?: ?('clip' | 'head' | 'middle' | 'tail'),
+
+ /**
+ * Specifies largest possible scale a font can reach when `allowFontScaling` is enabled.
+ * Possible values:
+ * `null/undefined` (default): inherit from the parent node or the global default (0)
+ * `0`: no max, ignore parent/global default
+ * `>= 1`: sets the maxFontSizeMultiplier of this node to this value
+ */
+ maxFontSizeMultiplier?: ?number,
+
+ /**
+ * Used to locate this view from native code.
+ *
+ * See https://facebook.github.io/react-native/docs/text.html#nativeid
+ */
+ nativeID?: ?string,
+
+ /**
+ * Used to truncate the text with an ellipsis.
+ *
+ * See https://facebook.github.io/react-native/docs/text.html#numberoflines
+ */
numberOfLines?: ?number,
+
+ /**
+ * Invoked on mount and layout changes.
+ *
+ * See https://facebook.github.io/react-native/docs/text.html#onlayout
+ */
onLayout?: ?(event: LayoutEvent) => mixed,
+
+ /**
+ * This function is called on long press.
+ *
+ * See https://facebook.github.io/react-native/docs/text.html#onlongpress
+ */
onLongPress?: ?(event: PressEvent) => mixed,
+
+ /**
+ * This function is called on press.
+ *
+ * See https://facebook.github.io/react-native/docs/text.html#onpress
+ */
onPress?: ?(event: PressEvent) => mixed,
- onResponderGrant?: ?Function,
- onResponderMove?: ?Function,
- onResponderRelease?: ?Function,
- onResponderTerminate?: ?Function,
- onResponderTerminationRequest?: ?Function,
- onStartShouldSetResponder?: ?Function,
+ onResponderGrant?: ?(event: PressEvent, dispatchID: string) => void,
+ onResponderMove?: ?(event: PressEvent) => void,
+ onResponderRelease?: ?(event: PressEvent) => void,
+ onResponderTerminate?: ?(event: PressEvent) => void,
+ onResponderTerminationRequest?: ?() => boolean,
+ onStartShouldSetResponder?: ?() => boolean,
+ onMoveShouldSetResponder?: ?() => boolean,
+ onTextLayout?: ?(event: TextLayoutEvent) => mixed,
+
+ /**
+ * Defines how far your touch may move off of the button, before
+ * deactivating the button.
+ *
+ * See https://facebook.github.io/react-native/docs/text.html#pressretentionoffset
+ */
pressRetentionOffset?: ?PressRetentionOffset,
+
+ /**
+ * Lets the user select text.
+ *
+ * See https://facebook.github.io/react-native/docs/text.html#selectable
+ */
selectable?: ?boolean,
- style?: ?DangerouslyImpreciseStyleProp,
- testID?: string,
+ style?: ?TextStyleProp,
- // Android Only
+ /**
+ * Used to locate this view in end-to-end tests.
+ *
+ * See https://facebook.github.io/react-native/docs/text.html#testid
+ */
+ testID?: ?string,
+
+ /**
+ * Android Only
+ */
+
+ /**
+ * Specifies the disabled state of the text view for testing purposes.
+ *
+ * See https://facebook.github.io/react-native/docs/text.html#disabled
+ */
disabled?: ?boolean,
+
+ /**
+ * The highlight color of the text.
+ *
+ * See https://facebook.github.io/react-native/docs/text.html#selectioncolor
+ */
selectionColor?: ?string,
- textBreakStrategy?: 'balanced' | 'highQuality' | 'simple',
- // iOS Only
+ /**
+ * Set text break strategy on Android.
+ *
+ * See https://facebook.github.io/react-native/docs/text.html#textbreakstrategy
+ */
+ textBreakStrategy?: ?('balanced' | 'highQuality' | 'simple'),
+
+ /**
+ * iOS Only
+ */
adjustsFontSizeToFit?: ?boolean,
+
+ /**
+ * Smallest possible scale a font can reach.
+ *
+ * See https://facebook.github.io/react-native/docs/text.html#minimumfontscale
+ */
minimumFontScale?: ?number,
+
+ /**
+ * When `true`, no visual change is made when text is pressed down.
+ *
+ * See https://facebook.github.io/react-native/docs/text.html#supperhighlighting
+ */
suppressHighlighting?: ?boolean,
-}>;
+|}>;

Libraries/Text/TextPropTypes.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,13 +10,13 @@
'use strict';
-const ColorPropType = require('ColorPropType');
-const EdgeInsetsPropType = require('EdgeInsetsPropType');
+const DeprecatedColorPropType = require('DeprecatedColorPropType');
+const DeprecatedEdgeInsetsPropType = require('DeprecatedEdgeInsetsPropType');
const PropTypes = require('prop-types');
-const StyleSheetPropType = require('StyleSheetPropType');
+const DeprecatedStyleSheetPropType = require('DeprecatedStyleSheetPropType');
const TextStylePropTypes = require('TextStylePropTypes');
-const stylePropType = StyleSheetPropType(TextStylePropTypes);
+const stylePropType = DeprecatedStyleSheetPropType(TextStylePropTypes);
module.exports = {
/**
@@ -62,7 +62,7 @@
*
* See https://facebook.github.io/react-native/docs/text.html#pressretentionoffset
*/
- pressRetentionOffset: EdgeInsetsPropType,
+ pressRetentionOffset: DeprecatedEdgeInsetsPropType,
/**
* Lets the user select text.
*
@@ -74,7 +74,7 @@
*
* See https://facebook.github.io/react-native/docs/text.html#selectioncolor
*/
- selectionColor: ColorPropType,
+ selectionColor: DeprecatedColorPropType,
/**
* When `true`, no visual change is made when text is pressed down.
*
@@ -101,6 +101,14 @@
*/
allowFontScaling: PropTypes.bool,
/**
+ * Specifies largest possible scale a font can reach when `allowFontScaling` is enabled.
+ * Possible values:
+ * `null/undefined` (default): inherit from the parent node or the global default (0)
+ * `0`: no max, ignore parent/global default
+ * `>= 1`: sets the maxFontSizeMultiplier of this node to this value
+ */
+ maxFontSizeMultiplier: PropTypes.number,
+ /**
* Indicates whether the view is an accessibility element.
*
* See https://facebook.github.io/react-native/docs/text.html#accessible

Libraries/Text/TextStylePropTypes.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,14 +10,14 @@
'use strict';
-const ColorPropType = require('ColorPropType');
+const DeprecatedColorPropType = require('DeprecatedColorPropType');
const ReactPropTypes = require('prop-types');
-const ViewStylePropTypes = require('ViewStylePropTypes');
+const DeprecatedViewStylePropTypes = require('DeprecatedViewStylePropTypes');
const TextStylePropTypes = {
- ...ViewStylePropTypes,
+ ...DeprecatedViewStylePropTypes,
- color: ColorPropType,
+ color: DeprecatedColorPropType,
fontFamily: ReactPropTypes.string,
fontSize: ReactPropTypes.number,
fontStyle: ReactPropTypes.oneOf(['normal', 'italic']),
@@ -56,7 +56,7 @@
height: ReactPropTypes.number,
}),
textShadowRadius: ReactPropTypes.number,
- textShadowColor: ColorPropType,
+ textShadowColor: DeprecatedColorPropType,
/**
* @platform ios
*/
@@ -107,7 +107,7 @@
/**
* @platform ios
*/
- textDecorationColor: ColorPropType,
+ textDecorationColor: DeprecatedColorPropType,
textTransform: ReactPropTypes.oneOf([
'none' /*default*/,
'capitalize',

Libraries/Text/VirtualText/RCTVirtualTextShadowView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/VirtualText/RCTVirtualTextShadowView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/VirtualText/RCTVirtualTextViewManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Text/VirtualText/RCTVirtualTextViewManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/TurboModule/RCTExport.js

@@ -0,0 +1,35 @@
+/**
+ * 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.
+ *
+ * @flow strict
+ * @format
+ */
+
+'use strict';
+
+/**
+ * NOTE: This is React Native specific export type.
+ *
+ * RCTExport is an interface type that allows native code generation for React
+ * Native native modules. It exists as a hint to the codegen tool that any
+ * interface that extends it needs to be codegen'ed. Example usage:
+ *
+ * export interface RCTFoobar extends RCTExport<void> {}
+ *
+ * Native definition for RCTFoobar will then be generated.
+ *
+ * The type param T is a placeholder for future codegen hinting, like versioning
+ * information, native base classes, etc. For now, simply use `void` type as
+ * there's nothing to give hint about.
+ */
+
+// eslint-disable-next-line no-unused-vars
+export interface RCTExport<T: void = void> {
+ +getConstants?: () => {};
+}
+
+// eslint-disable-next-line lint/react-native-modules
+export interface TurboModule extends RCTExport<void> {}

Libraries/TurboModule/TurboModuleRegistry.js

@@ -0,0 +1,42 @@
+/**
+ * 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.
+ *
+ * @flow
+ * @format
+ */
+
+'use strict';
+
+const NativeModules = require('NativeModules');
+
+import type {TurboModule} from 'RCTExport';
+import invariant from 'invariant';
+
+const turboModuleProxy = global.__turboModuleProxy;
+
+function get<T: TurboModule>(name: string): ?T {
+ // Backward compatibility layer during migration.
+ const legacyModule = NativeModules[name];
+ if (legacyModule != null) {
+ return ((legacyModule: any): T);
+ }
+
+ if (turboModuleProxy != null) {
+ const module: ?T = turboModuleProxy(name);
+ return module;
+ }
+
+ return null;
+}
+
+function getEnforcing<T: TurboModule>(name: string): T {
+ const module = get(name);
+ invariant(module != null, `${name} is not available in this app.`);
+ return module;
+}
+
+export {get};
+export {getEnforcing};

Libraries/Types/CoreEventTypes.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -19,7 +19,9 @@
registrationName: string,
|}>,
eventPhase: ?number,
+ preventDefault: () => void,
isDefaultPrevented: () => boolean,
+ stopPropagation: () => void,
isPropagationStopped: () => boolean,
isTrusted: ?boolean,
nativeEvent: T,
@@ -29,6 +31,29 @@
type: ?string,
|}>;
+export type ResponderSyntheticEvent<T> = $ReadOnly<{|
+ ...SyntheticEvent<T>,
+ touchHistory: $ReadOnly<{|
+ indexOfSingleActiveTouch: number,
+ mostRecentTimeStamp: number,
+ numberActiveTouches: number,
+ touchBank: $ReadOnlyArray<
+ $ReadOnly<{|
+ touchActive: boolean,
+ startPageX: number,
+ startPageY: number,
+ startTimeStamp: number,
+ currentPageX: number,
+ currentPageY: number,
+ currentTimeStamp: number,
+ previousPageX: number,
+ previousPageY: number,
+ previousTimeStamp: number,
+ |}>,
+ >,
+ |}>,
+|}>;
+
export type Layout = $ReadOnly<{|
x: number,
y: number,
@@ -36,13 +61,28 @@
height: number,
|}>;
+export type TextLayout = $ReadOnly<{|
+ ...Layout,
+ ascender: number,
+ capHeight: number,
+ descender: number,
+ text: string,
+ xHeight: number,
+|}>;
+
export type LayoutEvent = SyntheticEvent<
$ReadOnly<{|
layout: Layout,
|}>,
>;
-export type PressEvent = SyntheticEvent<
+export type TextLayoutEvent = SyntheticEvent<
+ $ReadOnly<{|
+ lines: Array<TextLayout>,
+ |}>,
+>;
+
+export type PressEvent = ResponderSyntheticEvent<
$ReadOnly<{|
changedTouches: $ReadOnlyArray<$PropertyType<PressEvent, 'nativeEvent'>>,
force: number,
@@ -77,6 +117,14 @@
height: number,
width: number,
|}>,
+ targetContentOffset?: $ReadOnly<{|
+ y: number,
+ x: number,
+ |}>,
+ velocity?: $ReadOnly<{|
+ y: number,
+ x: number,
+ |}>,
zoomScale: number,
|}>,
>;

Libraries/UTFSequence.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.

Libraries/Utilities/BackAndroid.js

@@ -1,54 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * BackAndroid has been moved to BackHandler. This stub calls BackHandler methods
- * after generating a warning to remind users to move to the new BackHandler module.
- *
- * @format
- */
-
-'use strict';
-
-const BackHandler = require('BackHandler');
-
-const warning = require('fbjs/lib/warning');
-
-/**
- * Deprecated. Use BackHandler instead.
- */
-const BackAndroid = {
- exitApp: function() {
- warning(
- false,
- 'BackAndroid is deprecated. Please use BackHandler instead.',
- );
- BackHandler.exitApp();
- },
-
- addEventListener: function(
- eventName: BackPressEventName,
- handler: Function,
- ): {remove: () => void} {
- warning(
- false,
- 'BackAndroid is deprecated. Please use BackHandler instead.',
- );
- return BackHandler.addEventListener(eventName, handler);
- },
-
- removeEventListener: function(
- eventName: BackPressEventName,
- handler: Function,
- ): void {
- warning(
- false,
- 'BackAndroid is deprecated. Please use BackHandler instead.',
- );
- BackHandler.removeEventListener(eventName, handler);
- },
-};
-
-module.exports = BackAndroid;

Libraries/Utilities/BackHandler.android.js

@@ -1,9 +1,10 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
*
+ * @flow
* @format
*/
@@ -14,26 +15,18 @@
const DEVICE_BACK_EVENT = 'hardwareBackPress';
-type BackPressEventName = $Enum<{
- backPress: string,
-}>;
+type BackPressEventName = 'backPress' | 'hardwareBackPress';
-const _backPressSubscriptions = new Set();
+const _backPressSubscriptions = [];
RCTDeviceEventEmitter.addListener(DEVICE_BACK_EVENT, function() {
- let invokeDefault = true;
- const subscriptions = Array.from(_backPressSubscriptions.values()).reverse();
-
- for (let i = 0; i < subscriptions.length; ++i) {
- if (subscriptions[i]()) {
- invokeDefault = false;
- break;
+ for (let i = _backPressSubscriptions.length - 1; i >= 0; i--) {
+ if (_backPressSubscriptions[i]()) {
+ return;
}
}
- if (invokeDefault) {
BackHandler.exitApp();
- }
});
/**
@@ -66,8 +59,19 @@
* });
* ```
*/
-const BackHandler = {
- exitApp: function() {
+type TBackHandler = {|
+ +exitApp: () => void,
+ +addEventListener: (
+ eventName: BackPressEventName,
+ handler: Function,
+ ) => {remove: () => void},
+ +removeEventListener: (
+ eventName: BackPressEventName,
+ handler: Function,
+ ) => void,
+|};
+const BackHandler: TBackHandler = {
+ exitApp: function(): void {
DeviceEventManager.invokeDefaultBackPressHandler();
},
@@ -81,9 +85,11 @@
eventName: BackPressEventName,
handler: Function,
): {remove: () => void} {
- _backPressSubscriptions.add(handler);
+ if (_backPressSubscriptions.indexOf(handler) === -1) {
+ _backPressSubscriptions.push(handler);
+ }
return {
- remove: () => BackHandler.removeEventListener(eventName, handler),
+ remove: (): void => BackHandler.removeEventListener(eventName, handler),
};
},
@@ -94,7 +100,12 @@
eventName: BackPressEventName,
handler: Function,
): void {
- _backPressSubscriptions.delete(handler);
+ if (_backPressSubscriptions.indexOf(handler) !== -1) {
+ _backPressSubscriptions.splice(
+ _backPressSubscriptions.indexOf(handler),
+ 1,
+ );
+ }
},
};

Libraries/Utilities/BackHandler.ios.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,6 +7,7 @@
* On Apple TV, this implements back navigation using the TV remote's menu button.
* On iOS, this just implements a stub.
*
+ * @flow
* @format
*/
@@ -15,11 +16,9 @@
const Platform = require('Platform');
const TVEventHandler = require('TVEventHandler');
-type BackPressEventName = $Enum<{
- backPress: string,
-}>;
+type BackPressEventName = 'backPress' | 'hardwareBackPress';
-function emptyFunction() {}
+function emptyFunction(): void {}
/**
* Detect hardware button presses for back navigation.
@@ -51,7 +50,19 @@
* });
* ```
*/
-let BackHandler;
+type TBackHandler = {|
+ +exitApp: () => void,
+ +addEventListener: (
+ eventName: BackPressEventName,
+ handler: Function,
+ ) => {remove: () => void},
+ +removeEventListener: (
+ eventName: BackPressEventName,
+ handler: Function,
+ ) => void,
+|};
+
+let BackHandler: TBackHandler;
if (Platform.isTV) {
const _tvEventHandler = new TVEventHandler();
@@ -100,12 +111,12 @@
} else {
BackHandler = {
exitApp: emptyFunction,
- addEventListener() {
+ addEventListener(_eventName: BackPressEventName, _handler: Function) {
return {
remove: emptyFunction,
};
},
- removeEventListener: emptyFunction,
+ removeEventListener(_eventName: BackPressEventName, _handler: Function) {},
};
}

Libraries/Utilities/binaryToBase64.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Utilities/buildStyleInterpolator.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -54,6 +54,9 @@
if (hasRoundRatio) {
nextVal = Math.round(roundRatio * nextVal) / roundRatio;
}
+ if (!isFinite(nextVal)) {
+ nextVal = null;
+ }
return nextVal;
};
@@ -186,17 +189,17 @@
);
didMatrix = true;
} else {
- var next = computeNextValLinearScalar(anim, value);
+ const next = computeNextValLinearScalar(anim, value);
didChange = setNextValAndDetectChange(result, name, next, didChange);
}
} else if (anim.type === 'constant') {
- var next = anim.value;
+ const next = anim.value;
didChange = setNextValAndDetectChange(result, name, next, didChange);
} else if (anim.type === 'step') {
- var next = value >= anim.threshold ? anim.to : anim.from;
+ const next = value >= anim.threshold ? anim.to : anim.from;
didChange = setNextValAndDetectChange(result, name, next, didChange);
} else if (anim.type === 'identity') {
- var next = value;
+ const next = value;
didChange = setNextValAndDetectChange(result, name, next, didChange);
}
}

Libraries/Utilities/clamp.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Utilities/createStrictShapeTypeChecker.js

@@ -1,86 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow
- */
-
-'use strict';
-
-const invariant = require('fbjs/lib/invariant');
-const merge = require('merge');
-
-function createStrictShapeTypeChecker(shapeTypes: {
- [key: string]: ReactPropsCheckType,
-}): ReactPropsChainableTypeChecker {
- function checkType(
- isRequired,
- props,
- propName,
- componentName,
- location?,
- ...rest
- ) {
- if (!props[propName]) {
- if (isRequired) {
- invariant(
- false,
- `Required object \`${propName}\` was not specified in ` +
- `\`${componentName}\`.`,
- );
- }
- return;
- }
- const propValue = props[propName];
- const propType = typeof propValue;
- const locationName = location || '(unknown)';
- if (propType !== 'object') {
- invariant(
- false,
- `Invalid ${locationName} \`${propName}\` of type \`${propType}\` ` +
- `supplied to \`${componentName}\`, expected \`object\`.`,
- );
- }
- // We need to check all keys in case some are required but missing from
- // props.
- const allKeys = merge(props[propName], shapeTypes);
- for (const key in allKeys) {
- const checker = shapeTypes[key];
- if (!checker) {
- invariant(
- false,
- `Invalid props.${propName} key \`${key}\` supplied to \`${componentName}\`.` +
- '\nBad object: ' +
- JSON.stringify(props[propName], null, ' ') +
- '\nValid keys: ' +
- JSON.stringify(Object.keys(shapeTypes), null, ' '),
- );
- }
- const error = checker(propValue, key, componentName, location, ...rest);
- if (error) {
- invariant(
- false,
- error.message +
- '\nBad object: ' +
- JSON.stringify(props[propName], null, ' '),
- );
- }
- }
- }
- function chainedCheckType(
- props: {[key: string]: any},
- propName: string,
- componentName: string,
- location?: string,
- ...rest
- ): ?Error {
- return checkType(false, props, propName, componentName, location, ...rest);
- }
- chainedCheckType.isRequired = checkType.bind(null, true);
- return chainedCheckType;
-}
-
-module.exports = createStrictShapeTypeChecker;

Libraries/Utilities/deepFreezeAndThrowOnMutationInDev.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -41,8 +41,8 @@
const keys = Object.keys(object);
const hasOwnProperty = Object.prototype.hasOwnProperty;
- for (var i = 0; i < keys.length; i++) {
- var key = keys[i];
+ for (let i = 0; i < keys.length; i++) {
+ const key = keys[i];
if (hasOwnProperty.call(object, key)) {
Object.defineProperty(object, key, {
get: identity.bind(null, object[key]),
@@ -56,8 +56,8 @@
Object.freeze(object);
Object.seal(object);
- for (var i = 0; i < keys.length; i++) {
- var key = keys[i];
+ for (let i = 0; i < keys.length; i++) {
+ const key = keys[i];
if (hasOwnProperty.call(object, key)) {
deepFreezeAndThrowOnMutationInDev(object[key]);
}

Libraries/Utilities/defineLazyObjectProperty.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

Libraries/Utilities/deprecatedPropType.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -21,7 +21,10 @@
): ReactPropsCheckType {
return function validate(props, propName, componentName, ...rest) {
// Don't warn for native components.
- if (!UIManager[componentName] && props[propName] !== undefined) {
+ if (
+ !UIManager.getViewManagerConfig(componentName) &&
+ props[propName] !== undefined
+ ) {
console.warn(
`\`${propName}\` supplied to \`${componentName}\` has been deprecated. ${explanation}`,
);

Libraries/Utilities/DeviceInfo.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -12,7 +12,7 @@
const DeviceInfo = require('NativeModules').DeviceInfo;
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
invariant(DeviceInfo, 'DeviceInfo native module is not installed correctly');

Libraries/Utilities/differ/deepDiffer.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Utilities/differ/insetsDiffer.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Utilities/differ/matricesDiffer.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Utilities/differ/pointsDiffer.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Utilities/differ/sizesDiffer.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Utilities/Dimensions.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -14,7 +14,7 @@
const Platform = require('Platform');
const RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
const eventEmitter = new EventEmitter();
let dimensionsInitialized = false;

Libraries/Utilities/dismissKeyboard.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Utilities/groupByEveryN.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Utilities/HeapCapture.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Utilities/HMRClient.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,7 +10,7 @@
'use strict';
const Platform = require('Platform');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
const MetroHMRClient = require('metro/src/lib/bundle-modules/HMRClient');
@@ -27,6 +27,9 @@
// Moving to top gives errors due to NativeModules not being initialized
const HMRLoadingView = require('HMRLoadingView');
+ /* $FlowFixMe(>=0.84.0 site=react_native_fb) This comment suppresses an
+ * error found when Flow v0.84 was deployed. To see the error, delete this
+ * comment and run Flow. */
const wsHostPort = port !== null && port !== '' ? `${host}:${port}` : host;
bundleEntry = bundleEntry.replace(/\.(bundle|delta)/, '.js');
@@ -86,7 +89,27 @@
hmrClient.on('error', data => {
HMRLoadingView.hide();
+
+ if (data.type === 'GraphNotFoundError') {
+ hmrClient.disable();
+ throw new Error(
+ 'The packager server has restarted since the last Hot update. Hot Reloading will be disabled until you reload the application.',
+ );
+ } else if (data.type === 'RevisionNotFoundError') {
+ hmrClient.disable();
+ throw new Error(
+ 'The packager server and the client are out of sync. Hot Reloading will be disabled until you reload the application.',
+ );
+ } else {
throw new Error(`${data.type} ${data.message}`);
+ }
+ });
+
+ hmrClient.on('close', data => {
+ HMRLoadingView.hide();
+ throw new Error(
+ 'Disconnected from the packager server. Hot Reloading will be disabled until you reload the application.',
+ );
});
hmrClient.enable();

Libraries/Utilities/HMRLoadingView.android.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Utilities/HMRLoadingView.ios.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Utilities/infoLog.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

Libraries/Utilities/JSDevSupportModule.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Utilities/logError.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Utilities/mapWithSeparator.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Utilities/MatrixMath.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,7 +11,7 @@
/* eslint-disable space-infix-ops */
'use strict';
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
/**
* Memory conservative (mutative) matrix math utilities. Uses "command"
@@ -577,7 +577,7 @@
);
// output values
- var perspective = [];
+ let perspective = [];
const quaternion = [];
const scale = [];
const skew = [];
@@ -590,7 +590,7 @@
}
const matrix = [];
const perspectiveMatrix = [];
- for (var i = 0; i < 4; i++) {
+ for (let i = 0; i < 4; i++) {
matrix.push([]);
for (let j = 0; j < 4; j++) {
const value = transformMatrix[i * 4 + j] / transformMatrix[15];
@@ -622,7 +622,7 @@
const transposedInversePerspectiveMatrix = MatrixMath.transpose(
inversePerspectiveMatrix,
);
- var perspective = MatrixMath.multiplyVectorByMatrix(
+ perspective = MatrixMath.multiplyVectorByMatrix(
rightHandSide,
transposedInversePerspectiveMatrix,
);
@@ -633,14 +633,14 @@
}
// translation is simple
- for (var i = 0; i < 3; i++) {
+ for (let i = 0; i < 3; i++) {
translation[i] = matrix[3][i];
}
// Now get scale and shear.
// 'row' is a 3 element array of 3 component vectors
const row = [];
- for (i = 0; i < 3; i++) {
+ for (let i = 0; i < 3; i++) {
row[i] = [matrix[i][0], matrix[i][1], matrix[i][2]];
}
@@ -678,7 +678,7 @@
// is -1, then negate the matrix and the scaling factors.
const pdum3 = MatrixMath.v3Cross(row[1], row[2]);
if (MatrixMath.v3Dot(row[0], pdum3) < 0) {
- for (i = 0; i < 3; i++) {
+ for (let i = 0; i < 3; i++) {
scale[i] *= -1;
row[i][0] *= -1;
row[i][1] *= -1;

Libraries/Utilities/mergeIntoFast.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Utilities/__mocks__/BackHandler.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

Libraries/Utilities/__mocks__/PixelRatio.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2004-present, Facebook, Inc.
+ * 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.

Libraries/Utilities/PerformanceLogger.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -26,6 +26,7 @@
let timespans: {[key: string]: Timespan} = {};
let extras: {[key: string]: any} = {};
+let points: {[key: string]: number} = {};
const cookies: {[key: string]: number} = {};
const PRINT_TO_CONSOLE: false = false; // Type as false to prevent accidentally committing `true`;
@@ -107,6 +108,7 @@
clear() {
timespans = {};
extras = {};
+ points = {};
if (PRINT_TO_CONSOLE) {
infoLog('PerformanceLogger.js', 'clear');
}
@@ -119,6 +121,7 @@
}
}
extras = {};
+ points = {};
if (PRINT_TO_CONSOLE) {
infoLog('PerformanceLogger.js', 'clearCompleted');
}
@@ -132,6 +135,7 @@
return previous;
}, {});
extras = {};
+ points = {};
if (PRINT_TO_CONSOLE) {
infoLog('PerformanceLogger.js', 'clearExceptTimespans', keys);
}
@@ -188,6 +192,29 @@
logExtras() {
infoLog(extras);
},
+
+ markPoint(key: string, timestamp?: number) {
+ if (points[key]) {
+ if (__DEV__) {
+ infoLog(
+ 'PerformanceLogger: Attempting to mark a point that has been already logged ',
+ key,
+ );
+ }
+ return;
+ }
+ points[key] = timestamp ?? performanceNow();
+ },
+
+ getPoints() {
+ return points;
+ },
+
+ logPoints() {
+ for (const key in points) {
+ infoLog(key + ': ' + points[key] + 'ms');
+ }
+ },
};
module.exports = PerformanceLogger;

Libraries/Utilities/PixelRatio.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -68,9 +68,15 @@
* - iPhone 4, 4S
* - iPhone 5, 5c, 5s
* - iPhone 6
+ * - iPhone 7
+ * - iPhone 8
+ * - iPhone SE
* - xhdpi Android devices (320 dpi)
* - PixelRatio.get() === 3
- * - iPhone 6 plus
+ * - iPhone 6 Plus
+ * - iPhone 7 Plus
+ * - iPhone 8 Plus
+ * - iPhone X
* - xxhdpi Android devices (480 dpi)
* - PixelRatio.get() === 3.5
* - Nexus 6

Libraries/Utilities/Platform.android.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -12,6 +12,11 @@
const NativeModules = require('NativeModules');
+export type PlatformSelectSpec<A, D> = {
+ android?: A,
+ default?: D,
+};
+
const Platform = {
OS: 'android',
get Version() {
@@ -19,14 +24,18 @@
return constants && constants.Version;
},
get isTesting(): boolean {
+ if (__DEV__) {
const constants = NativeModules.PlatformConstants;
return constants && constants.isTesting;
+ }
+ return false;
},
get isTV(): boolean {
const constants = NativeModules.PlatformConstants;
return constants && constants.uiMode === 'tv';
},
- select: (obj: Object) => ('android' in obj ? obj.android : obj.default),
+ select: <A, D>(spec: PlatformSelectSpec<A, D>): A | D =>
+ 'android' in spec ? spec.android : spec.default,
};
module.exports = Platform;

Libraries/Utilities/Platform.ios.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -12,6 +12,11 @@
const NativeModules = require('NativeModules');
+export type PlatformSelectSpec<D, I> = {
+ default?: D,
+ ios?: I,
+};
+
const Platform = {
OS: 'ios',
get Version() {
@@ -33,10 +38,14 @@
return constants ? constants.interfaceIdiom === 'tv' : false;
},
get isTesting(): boolean {
+ if (__DEV__) {
const constants = NativeModules.PlatformConstants;
return constants && constants.isTesting;
+ }
+ return false;
},
- select: (obj: Object) => ('ios' in obj ? obj.ios : obj.default),
+ select: <D, I>(spec: PlatformSelectSpec<D, I>): D | I =>
+ 'ios' in spec ? spec.ios : spec.default,
};
module.exports = Platform;

Libraries/Utilities/PlatformOS.android.js

@@ -1,23 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow
- */
-
-'use strict';
-
-export type PlatformSelectSpec<A, I> = {|
- android: A,
- ios: I,
-|};
-
-const PlatformOS = {
- OS: 'android',
- select: <A, I>(spec: PlatformSelectSpec<A, I>): A | I => spec.android,
-};
-
-module.exports = PlatformOS;

Libraries/Utilities/PlatformOS.ios.js

@@ -1,23 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow strict
- */
-
-'use strict';
-
-export type PlatformSelectSpec<A, I> = {|
- android: A,
- ios: I,
-|};
-
-const PlatformOS = {
- OS: 'ios',
- select: <A, I>(spec: PlatformSelectSpec<A, I>): A | I => spec.ios,
-};
-
-module.exports = PlatformOS;

Libraries/Utilities/Platform.web.js

@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow
+ */
+
+'use strict';
+
+export type PlatformSelectSpec<D, I> = {
+ default?: D,
+ web?: I,
+};
+
+const Platform = {
+ OS: 'web',
+ select: <D, I>(spec: PlatformSelectSpec<D, I>): D | I =>
+ 'web' in spec ? spec.web : spec.default,
+};
+
+module.exports = Platform;

Libraries/Utilities/PolyfillFunctions.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -33,10 +33,7 @@
const descriptor = Object.getOwnPropertyDescriptor(object, name);
if (__DEV__ && descriptor) {
const backupName = `original${name[0].toUpperCase()}${name.substr(1)}`;
- Object.defineProperty(object, backupName, {
- ...descriptor,
- value: object[name],
- });
+ Object.defineProperty(object, backupName, descriptor);
}
const {enumerable, writable, configurable} = descriptor || {};

Libraries/Utilities/RCTLog.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,7 +10,7 @@
'use strict';
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
const levelsMap = {
log: 'log',

Libraries/Utilities/ReactNativeTestTools.js

@@ -0,0 +1,167 @@
+/**
+ * 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.
+ *
+ * @flow
+ * @format
+ */
+
+/* eslint-env jest */
+
+'use strict';
+
+const React = require('React');
+const ReactTestRenderer = require('react-test-renderer');
+
+const {Switch, Text, TextInput, VirtualizedList} = require('react-native');
+
+import type {
+ ReactTestInstance,
+ ReactTestRendererNode,
+ Predicate,
+} from 'react-test-renderer';
+
+function byClickable(): Predicate {
+ return withMessage(
+ node =>
+ // note: <Text /> lazy-mounts press handlers after the first press,
+ // so this is a workaround for targeting text nodes.
+ (node.type === Text &&
+ node.props &&
+ typeof node.props.onPress === 'function') ||
+ // note: Special casing <Switch /> since it doesn't use touchable
+ (node.type === Switch && node.props && node.props.disabled !== true) ||
+ (node.instance &&
+ typeof node.instance.touchableHandlePress === 'function'),
+ 'is clickable',
+ );
+}
+
+function byTestID(testID: string): Predicate {
+ return withMessage(
+ node => node.props && node.props.testID === testID,
+ `testID prop equals ${testID}`,
+ );
+}
+
+function byTextMatching(regex: RegExp): Predicate {
+ return withMessage(
+ node => node.props && regex.exec(node.props.children),
+ `text content matches ${regex.toString()}`,
+ );
+}
+
+function enter(instance: ReactTestInstance, text: string) {
+ const input = instance.findByType(TextInput);
+ input.instance._onChange({nativeEvent: {text}});
+}
+
+// Returns null if there is no error, otherwise returns an error message string.
+function maximumDepthError(
+ tree: {toJSON: () => ReactTestRendererNode},
+ maxDepthLimit: number,
+): ?string {
+ const maxDepth = maximumDepthOfJSON(tree.toJSON());
+ if (maxDepth > maxDepthLimit) {
+ return (
+ `maximumDepth of ${maxDepth} exceeded limit of ${maxDepthLimit} - this is a proxy ` +
+ 'metric to protect against stack overflow errors:\n\n' +
+ 'https://fburl.com/rn-view-stack-overflow.\n\n' +
+ 'To fix, you need to remove native layers from your hierarchy, such as unnecessary View ' +
+ 'wrappers.'
+ );
+ } else {
+ return null;
+ }
+}
+
+function expectNoConsoleWarn() {
+ (jest: $FlowFixMe).spyOn(console, 'warn').mockImplementation((...args) => {
+ expect(args).toBeFalsy();
+ });
+}
+
+function expectNoConsoleError() {
+ let hasNotFailed = true;
+ (jest: $FlowFixMe).spyOn(console, 'error').mockImplementation((...args) => {
+ if (hasNotFailed) {
+ hasNotFailed = false; // set false to prevent infinite recursion
+ expect(args).toBeFalsy();
+ }
+ });
+}
+
+// Takes a node from toJSON()
+function maximumDepthOfJSON(node: ReactTestRendererNode): number {
+ if (node == null) {
+ return 0;
+ } else if (typeof node === 'string' || node.children == null) {
+ return 1;
+ } else {
+ let maxDepth = 0;
+ node.children.forEach(child => {
+ maxDepth = Math.max(maximumDepthOfJSON(child) + 1, maxDepth);
+ });
+ return maxDepth;
+ }
+}
+
+function renderAndEnforceStrictMode(element: React.Node) {
+ expectNoConsoleError();
+ return renderWithStrictMode(element);
+}
+
+function renderWithStrictMode(element: React.Node) {
+ const WorkAroundBugWithStrictModeInTestRenderer = prps => prps.children;
+ const StrictMode = (React: $FlowFixMe).StrictMode;
+ return ReactTestRenderer.create(
+ <WorkAroundBugWithStrictModeInTestRenderer>
+ <StrictMode>{element}</StrictMode>
+ </WorkAroundBugWithStrictModeInTestRenderer>,
+ );
+}
+
+function tap(instance: ReactTestInstance) {
+ const touchable = instance.find(byClickable());
+ if (touchable.type === Text && touchable.props && touchable.props.onPress) {
+ touchable.props.onPress();
+ } else if (touchable.type === Switch && touchable.props) {
+ const value = !touchable.props.value;
+ const {onChange, onValueChange} = touchable.props;
+ onChange && onChange({nativeEvent: {value}});
+ onValueChange && onValueChange(value);
+ } else {
+ // Only tap when props.disabled isn't set (or there aren't any props)
+ if (!touchable.props || !touchable.props.disabled) {
+ touchable.instance.touchableHandlePress({nativeEvent: {}});
+ }
+ }
+}
+
+function scrollToBottom(instance: ReactTestInstance) {
+ const list = instance.findByType(VirtualizedList);
+ list.props && list.props.onEndReached();
+}
+
+// To make error messages a little bit better, we attach a custom toString
+// implementation to a predicate
+function withMessage(fn: Predicate, message: string): Predicate {
+ (fn: any).toString = () => message;
+ return fn;
+}
+
+export {byClickable};
+export {byTestID};
+export {byTextMatching};
+export {enter};
+export {expectNoConsoleWarn};
+export {expectNoConsoleError};
+export {maximumDepthError};
+export {maximumDepthOfJSON};
+export {renderAndEnforceStrictMode};
+export {renderWithStrictMode};
+export {scrollToBottom};
+export {tap};
+export {withMessage};

Libraries/Utilities/SceneTracker.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Utilities/setAndForwardRef.js

@@ -0,0 +1,68 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow
+ */
+
+'use strict';
+
+import type React from 'React';
+
+type Args = $ReadOnly<{|
+ getForwardedRef: () => ?React.Ref<any>,
+ setLocalRef: (ref: React.ElementRef<any>) => mixed,
+|}>;
+
+/**
+ * This is a helper function for when a component needs to be able to forward a ref
+ * to a child component, but still needs to have access to that component as part of
+ * its implementation.
+ *
+ * Its main use case is in wrappers for native components.
+ *
+ * Usage:
+ *
+ * class MyView extends React.Component {
+ * _nativeRef = null;
+ *
+ * _setNativeRef = setAndForwardRef({
+ * getForwardedRef: () => this.props.forwardedRef,
+ * setLocalRef: ref => {
+ * this._nativeRef = ref;
+ * },
+ * });
+ *
+ * render() {
+ * return <View ref={this._setNativeRef} />;
+ * }
+ * }
+ *
+ * const MyViewWithRef = React.forwardRef((props, ref) => (
+ * <MyView {...props} forwardedRef={ref} />
+ * ));
+ *
+ * module.exports = MyViewWithRef;
+ */
+
+function setAndForwardRef({getForwardedRef, setLocalRef}: Args) {
+ return function forwardRef(ref: React.ElementRef<any>) {
+ const forwardedRef = getForwardedRef();
+
+ setLocalRef(ref);
+
+ // Forward to user ref prop (if one has been specified)
+ if (typeof forwardedRef === 'function') {
+ // Handle function-based refs. String-based refs are handled as functions.
+ forwardedRef(ref);
+ } else if (typeof forwardedRef === 'object' && forwardedRef != null) {
+ // Handle createRef-based refs
+ forwardedRef.current = ref;
+ }
+ };
+}
+
+module.exports = setAndForwardRef;

Libraries/Utilities/stringifySafe.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Utilities/truncate.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Utilities/warnOnce.js

@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ * @flow
+ */
+
+'use strict';
+
+const warning = require('fbjs/lib/warning');
+
+const warnedKeys: {[string]: boolean} = {};
+
+/**
+ * A simple function that prints a warning message once per session.
+ *
+ * @param {string} key - The key used to ensure the message is printed once.
+ * This should be unique to the callsite.
+ * @param {string} message - The message to print
+ */
+function warnOnce(key: string, message: string) {
+ if (warnedKeys[key]) {
+ return;
+ }
+
+ warning(false, message);
+
+ warnedKeys[key] = true;
+}
+
+module.exports = warnOnce;

Libraries/vendor/core/ErrorUtils.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/vendor/core/getObjectValues.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/vendor/core/guid.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/vendor/core/guid.js.flow

@@ -1,5 +1,8 @@
/**
- * Copyright 2004-present Facebook. All Rights Reserved.
+ * 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.
*
* @flow strict
* @format

Libraries/vendor/core/isEmpty.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/vendor/core/Map.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -15,7 +15,6 @@
const _shouldPolyfillES6Collection = require('_shouldPolyfillES6Collection');
const guid = require('guid');
-const isNode = require('fbjs/lib/isNode');
const toIterator = require('toIterator');
module.exports = (function(global, undefined) {
@@ -27,6 +26,11 @@
return global.Map;
}
+ // In case this module has not already been evaluated, import it now.
+ require('./_wrapObjectFreezeAndFriends');
+
+ const hasOwn = Object.prototype.hasOwnProperty;
+
/**
* == ES6 Map Collection ==
*
@@ -39,15 +43,17 @@
*
* https://people.mozilla.org/~jorendorff/es6-draft.html#sec-map-objects
*
- * There only two -- rather small -- diviations from the spec:
+ * There only two -- rather small -- deviations from the spec:
*
- * 1. The use of frozen objects as keys.
- * We decided not to allow and simply throw an error. The reason being is
- * we store a "hash" on the object for fast access to it's place in the
- * internal map entries.
- * If this turns out to be a popular use case it's possible to implement by
- * overiding `Object.freeze` to store a "hash" property on the object
- * for later use with the map.
+ * 1. The use of untagged frozen objects as keys.
+ * We decided not to allow and simply throw an error, because this
+ * implementation of Map works by tagging objects used as Map keys
+ * with a secret hash property for fast access to the object's place
+ * in the internal _mapData array. However, to limit the impact of
+ * this spec deviation, Libraries/Core/InitializeCore.js also wraps
+ * Object.freeze, Object.seal, and Object.preventExtensions so that
+ * they tag objects before making them non-extensible, by inserting
+ * each object into a Map and then immediately removing it.
*
* 2. The `size` property on a map object is a regular property and not a
* computed property on the prototype as described by the spec.
@@ -97,9 +103,6 @@
SECRET_SIZE_PROP = '$size' + guid();
}
- // In oldIE we use the DOM Node `uniqueID` property to get create the hash.
- const OLD_IE_HASH_PREFIX = 'IE_HASH_';
-
class Map {
/**
* 23.1.1.1
@@ -449,7 +452,7 @@
// If the `SECRET_SIZE_PROP` property is already defined then we're not
// in the first call to `initMap` (e.g. coming from `map.clear()`) so
// all we need to do is reset the size without defining the properties.
- if (map.hasOwnProperty(SECRET_SIZE_PROP)) {
+ if (hasOwn.call(map, SECRET_SIZE_PROP)) {
map[SECRET_SIZE_PROP] = 0;
} else {
Object.defineProperty(map, SECRET_SIZE_PROP, {
@@ -523,39 +526,14 @@
}
}
- /**
- * IE has a `uniqueID` set on every DOM node. So we construct the hash from
- * this uniqueID to avoid memory leaks and the IE cloneNode bug where it
- * clones properties in addition to the attributes.
- *
- * @param {object} node
- * @return {?string}
- */
- function getIENodeHash(node) {
- let uniqueID;
- switch (node.nodeType) {
- case 1: // Element
- uniqueID = node.uniqueID;
- break;
- case 9: // Document
- uniqueID = node.documentElement.uniqueID;
- break;
- default:
- return null;
- }
-
- if (uniqueID) {
- return OLD_IE_HASH_PREFIX + uniqueID;
- } else {
- return null;
- }
- }
-
const getHash = (function() {
const propIsEnumerable = Object.prototype.propertyIsEnumerable;
- const hashProperty = guid();
+ const hashProperty = '__MAP_POLYFILL_INTERNAL_HASH__';
let hashCounter = 0;
+ const nonExtensibleObjects = [];
+ const nonExtensibleHashes = [];
+
/**
* Get the "hash" associated with an object.
*
@@ -563,52 +541,51 @@
* @return {number}
*/
return function getHash(o) {
- // eslint-disable-line no-shadow
- if (o[hashProperty]) {
+ if (hasOwn.call(o, hashProperty)) {
return o[hashProperty];
- } else if (
- !isES5 &&
- o.propertyIsEnumerable &&
- o.propertyIsEnumerable[hashProperty]
+ }
+
+ if (!isES5) {
+ if (
+ hasOwn.call(o, 'propertyIsEnumerable') &&
+ hasOwn.call(o.propertyIsEnumerable, hashProperty)
) {
return o.propertyIsEnumerable[hashProperty];
- } else if (!isES5 && isNode(o) && getIENodeHash(o)) {
- return getIENodeHash(o);
- } else if (!isES5 && o[hashProperty]) {
- return o[hashProperty];
+ }
}
if (isExtensible(o)) {
- hashCounter += 1;
if (isES5) {
Object.defineProperty(o, hashProperty, {
enumerable: false,
writable: false,
configurable: false,
- value: hashCounter,
+ value: ++hashCounter,
});
- } else if (o.propertyIsEnumerable) {
+ return hashCounter;
+ }
+
+ if (o.propertyIsEnumerable) {
// Since we can't define a non-enumerable property on the object
// we'll hijack one of the less-used non-enumerable properties to
- // save our hash on it. Addiotionally, since this is a function it
+ // save our hash on it. Additionally, since this is a function it
// will not show up in `JSON.stringify` which is what we want.
o.propertyIsEnumerable = function() {
return propIsEnumerable.apply(this, arguments);
};
- o.propertyIsEnumerable[hashProperty] = hashCounter;
- } else if (isNode(o)) {
- // At this point we couldn't get the IE `uniqueID` to use as a hash
- // and we couldn't use a non-enumerable property to exploit the
- // dontEnum bug so we simply add the `hashProperty` on the node
- // itself.
- o[hashProperty] = hashCounter;
- } else {
- throw new Error('Unable to set a non-enumerable property on object.');
+ return (o.propertyIsEnumerable[hashProperty] = ++hashCounter);
}
- return hashCounter;
- } else {
- throw new Error('Non-extensible objects are not allowed as keys.');
}
+
+ // If the object is not extensible, fall back to storing it in an
+ // array and using Array.prototype.indexOf to find it.
+ let index = nonExtensibleObjects.indexOf(o);
+ if (index < 0) {
+ index = nonExtensibleObjects.length;
+ nonExtensibleObjects[index] = o;
+ nonExtensibleHashes[index] = ++hashCounter;
+ }
+ return nonExtensibleHashes[index];
};
})();

Libraries/vendor/core/mergeHelpers.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -12,7 +12,7 @@
'use strict';
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
/**
* Maximum number of levels to traverse. Will catch circular structures.

Libraries/vendor/core/mergeInto.js

@@ -1,32 +1,8 @@
/**
- * @generated SignedSource<<f2a1f14b3c1d2b563e2a0619ef427c6d>>
+ * Copyright (c) Facebook, Inc. and its affiliates.
*
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !! This file is a check-in of a static_upstream project! !!
- * !! !!
- * !! You should not modify this file directly. Instead: !!
- * !! 1) Use `fjs use-upstream` to temporarily replace this with !!
- * !! the latest version from upstream. !!
- * !! 2) Make your changes, test them, etc. !!
- * !! 3) Use `fjs push-upstream` to copy your changes back to !!
- * !! static_upstream. !!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- *
- * Copyright 2013-2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * @typechecks static-only
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
*/
"use strict";

Libraries/vendor/core/merge.js

@@ -1,36 +1,13 @@
/**
- * @generated SignedSource<<148d1974f94f5c9597e86f946bdf0d4e>>
- *
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !! This file is a check-in of a static_upstream project! !!
- * !! !!
- * !! You should not modify this file directly. Instead: !!
- * !! 1) Use `fjs use-upstream` to temporarily replace this with !!
- * !! the latest version from upstream. !!
- * !! 2) Make your changes, test them, etc. !!
- * !! 3) Use `fjs push-upstream` to copy your changes back to !!
- * !! static_upstream. !!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- *
- * Copyright 2013-2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * 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.
*/
"use strict";
-var mergeInto = require('mergeInto');
+const mergeInto = require('mergeInto');
/**
* Shallow merges two structures into a return value, without mutating either.
@@ -39,8 +16,8 @@
* @param {?object} two Optional object with properties to merge from.
* @return {object} The shallow extension of one by two.
*/
-var merge = function(one, two) {
- var result = {};
+const merge = function(one, two) {
+ const result = {};
mergeInto(result, one);
mergeInto(result, two);
return result;

Libraries/vendor/core/Set.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/vendor/core/_shouldPolyfillES6Collection.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/vendor/core/toIterator.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/vendor/core/whatwg-fetch.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -516,6 +516,10 @@
xhr.withCredentials = false;
}
+ if ('responseType' in xhr && support.blob) {
+ xhr.responseType = 'blob';
+ }
+
request.headers.forEach(function(value, name) {
xhr.setRequestHeader(name, value);
});

Libraries/vendor/core/_wrapObjectFreezeAndFriends.js

@@ -0,0 +1,39 @@
+/**
+ * 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);
+ }
+ };
+ }
+});

Libraries/vendor/document/selection/DocumentSelectionState.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/vendor/emitter/EmitterSubscription.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/vendor/emitter/EventEmitter.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -14,8 +14,7 @@
const EmitterSubscription = require('EmitterSubscription');
const EventSubscriptionVendor = require('EventSubscriptionVendor');
-const emptyFunction = require('fbjs/lib/emptyFunction');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
/**
* @class EventEmitter
@@ -150,15 +149,9 @@
* @returns {array}
*/
listeners(eventType: string): [EmitterSubscription] {
- const subscriptions: ?[
- EmitterSubscription,
- ] = (this._subscriber.getSubscriptionsForType(eventType): any);
+ const subscriptions = this._subscriber.getSubscriptionsForType(eventType);
return subscriptions
- ? subscriptions
- .filter(emptyFunction.thatReturnsTrue)
- .map(function(subscription) {
- return subscription.listener;
- })
+ ? subscriptions.map(subscription => subscription.listener)
: [];
}
@@ -177,15 +170,13 @@
* emitter.emit('someEvent', 'abc'); // logs 'abc'
*/
emit(eventType: string) {
- const subscriptions: ?[
- EmitterSubscription,
- ] = (this._subscriber.getSubscriptionsForType(eventType): any);
+ const subscriptions = this._subscriber.getSubscriptionsForType(eventType);
if (subscriptions) {
for (let i = 0, l = subscriptions.length; i < l; i++) {
const subscription = subscriptions[i];
// The subscription may have been removed during this event loop.
- if (subscription) {
+ if (subscription && subscription.listener) {
this._currentSubscription = subscription;
subscription.listener.apply(
subscription.context,
@@ -211,9 +202,7 @@
*
*/
removeListener(eventType: String, listener) {
- const subscriptions: ?[
- EmitterSubscription,
- ] = (this._subscriber.getSubscriptionsForType(eventType): any);
+ const subscriptions = this._subscriber.getSubscriptionsForType(eventType);
if (subscriptions) {
for (let i = 0, l = subscriptions.length; i < l; i++) {
const subscription = subscriptions[i];

Libraries/vendor/emitter/EventEmitterWithHolding.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/vendor/emitter/EventHolder.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,7 +10,7 @@
'use strict';
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
class EventHolder {
_heldEvents: Object;

Libraries/vendor/emitter/EventSubscription.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/vendor/emitter/EventSubscriptionVendor.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,7 +10,7 @@
'use strict';
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
import type EventSubscription from 'EventSubscription';

Libraries/vendor/emitter/EventValidator.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -71,21 +71,21 @@
}
};
- var closestTypeFor = function(type, allowedTypes) {
+ const closestTypeFor = function(type, allowedTypes) {
const typeRecommendations = allowedTypes.map(
typeRecommendationFor.bind(this, type),
);
return typeRecommendations.sort(recommendationSort)[0];
};
- var typeRecommendationFor = function(type, recommendedType) {
+ const typeRecommendationFor = function(type, recommendedType) {
return {
type: recommendedType,
distance: damerauLevenshteinDistance(type, recommendedType),
};
};
- var recommendationSort = function(recommendationA, recommendationB) {
+ const recommendationSort = function(recommendationA, recommendationB) {
if (recommendationA.distance < recommendationB.distance) {
return -1;
} else if (recommendationA.distance > recommendationB.distance) {
@@ -95,11 +95,11 @@
}
};
- var isCloseEnough = function(closestType, actualType) {
+ const isCloseEnough = function(closestType, actualType) {
return closestType.distance / actualType.length < 0.334;
};
- var damerauLevenshteinDistance = function(a, b) {
+ const damerauLevenshteinDistance = function(a, b) {
let i, j;
const d = [];

Libraries/vendor/emitter/mixInEventEmitter.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -14,7 +14,7 @@
const EventEmitterWithHolding = require('EventEmitterWithHolding');
const EventHolder = require('EventHolder');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
* found when Flow v0.54 was deployed. To see the error delete this comment and
* run Flow. */

Libraries/Vibration/RCTVibration.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Vibration/RCTVibration.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/Vibration/VibrationIOS.android.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -15,7 +15,10 @@
const VibrationIOS = {
vibrate: function() {
- warning('VibrationIOS is not supported on this platform!');
+ warning(
+ false,
+ 'VibrationIOS is deprecated, and will be removed. Use Vibration instead.',
+ );
},
};

Libraries/Vibration/VibrationIOS.ios.js

@@ -1,18 +1,18 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
- * @flow strict-local
*/
'use strict';
const RCTVibration = require('NativeModules').Vibration;
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
+const warning = require('fbjs/lib/warning');
/**
* NOTE: `VibrationIOS` is being deprecated. Use `Vibration` instead.
@@ -32,6 +32,10 @@
* @deprecated
*/
vibrate: function() {
+ warning(
+ false,
+ 'VibrationIOS is deprecated and will be removed. Please use Vibration instead.',
+ );
invariant(arguments[0] === undefined, 'Vibration patterns not supported.');
RCTVibration.vibrate();
},

Libraries/Vibration/Vibration.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/WebSocket/__mocks__/event-target-shim.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/WebSocket/RCTReconnectingWebSocket.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/WebSocket/RCTReconnectingWebSocket.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/WebSocket/RCTSRWebSocket.m

@@ -218,6 +218,8 @@
BOOL _isPumping;
+ BOOL _cleanupScheduled;
+
NSMutableSet<NSArray *> *_scheduledRunloops;
// We use this to retain ourselves.
@@ -325,16 +327,10 @@
[_inputStream close];
[_outputStream close];
- _workQueue = NULL;
-
if (_receivedHTTPHeaders) {
CFRelease(_receivedHTTPHeaders);
_receivedHTTPHeaders = NULL;
}
-
- if (_delegateDispatchQueue) {
- _delegateDispatchQueue = NULL;
- }
}
#ifndef NDEBUG
@@ -626,11 +622,11 @@
}];
self.readyState = RCTSR_CLOSED;
- self->_selfRetain = nil;
RCTSRLog(@"Failing with error %@", error.localizedDescription);
[self _disconnect];
+ [self _scheduleCleanup];
}
});
}
@@ -1036,12 +1032,7 @@
!_sentClose) {
_sentClose = YES;
- [_outputStream close];
- [_inputStream close];
-
- for (NSArray *runLoop in [_scheduledRunloops copy]) {
- [self unscheduleFromRunLoop:runLoop[0] forMode:runLoop[1]];
- }
+ [self _scheduleCleanup];
if (!_failed) {
[self _performDelegateBlock:^{
@@ -1050,8 +1041,6 @@
}
}];
}
-
- _selfRetain = nil;
}
}
@@ -1346,8 +1335,22 @@
}
}
- assert(_workQueue != NULL);
+ // _workQueue cannot be NULL
+ if (!_workQueue) {
+ return;
+ }
+ __weak typeof(self) weakSelf = self;
dispatch_async(_workQueue, ^{
+ typeof(self) strongSelf = weakSelf;
+ if (!strongSelf) {
+ return;
+ }
+ [strongSelf safeHandleEvent:eventCode stream:aStream];
+ });
+}
+
+- (void)safeHandleEvent:(NSStreamEvent)eventCode stream:(NSStream *)aStream
+{
switch (eventCode) {
case NSStreamEventOpenCompleted: {
RCTSRLog(@"NSStreamEventOpenCompleted %@", aStream);
@@ -1383,7 +1386,7 @@
dispatch_async(self->_workQueue, ^{
if (self.readyState != RCTSR_CLOSED) {
self.readyState = RCTSR_CLOSED;
- self->_selfRetain = nil;
+ [self _scheduleCleanup];
}
if (!self->_sentClose && !self->_failed) {
@@ -1433,6 +1436,40 @@
RCTSRLog(@"(default) %@", aStream);
break;
}
+}
+
+- (void)_scheduleCleanup
+{
+ if (_cleanupScheduled) {
+ return;
+ }
+
+ _cleanupScheduled = YES;
+
+ // Cleanup NSStream's delegate in the same RunLoop used by the streams themselves:
+ // This way we'll prevent race conditions between handleEvent and SRWebsocket's dealloc
+ NSTimer *timer = [NSTimer timerWithTimeInterval:(0.0f) target:self selector:@selector(_cleanupSelfReference:) userInfo:nil repeats:NO];
+ [[NSRunLoop RCTSR_networkRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
+}
+
+- (void)_cleanupSelfReference:(NSTimer *)timer
+{
+ // Remove the streams, right now, from the networkRunLoop
+ [_inputStream close];
+ [_outputStream close];
+
+ // Unschedule from RunLoop
+ for (NSArray *runLoop in [_scheduledRunloops copy]) {
+ [self unscheduleFromRunLoop:runLoop[0] forMode:runLoop[1]];
+ }
+
+ // Nuke NSStream's delegate
+ _inputStream.delegate = nil;
+ _outputStream.delegate = nil;
+
+ // Cleanup selfRetain in the same GCD queue as usual
+ dispatch_async(_workQueue, ^{
+ self->_selfRetain = nil;
});
}

Libraries/WebSocket/RCTWebSocketExecutor.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/WebSocket/RCTWebSocketExecutor.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/WebSocket/RCTWebSocketModule.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/WebSocket/RCTWebSocketModule.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/WebSocket/RCTWebSocket.xcodeproj/project.pbxproj

@@ -13,7 +13,6 @@
2D3B5F3D1D9B165B00451313 /* RCTSRWebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 1338BBDD1B04ACC80064A9C9 /* RCTSRWebSocket.m */; };
2D3B5F3E1D9B165B00451313 /* RCTWebSocketExecutor.m in Sources */ = {isa = PBXBuildFile; fileRef = 1338BBDF1B04ACC80064A9C9 /* RCTWebSocketExecutor.m */; };
2D3B5F401D9B165B00451313 /* RCTWebSocketModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C86DF7B1ADF695F0047B81A /* RCTWebSocketModule.m */; };
- 2DC5E5281F3A6CFD000EE84B /* libfishhook-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DC5E5271F3A6CFD000EE84B /* libfishhook-tvOS.a */; };
3C86DF7C1ADF695F0047B81A /* RCTWebSocketModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C86DF7B1ADF695F0047B81A /* RCTWebSocketModule.m */; };
3DBE0D141F3B185A0099AA32 /* fishhook.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DBE0D121F3B185A0099AA32 /* fishhook.c */; };
3DBE0D151F3B185A0099AA32 /* fishhook.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DBE0D121F3B185A0099AA32 /* fishhook.c */; };
@@ -21,6 +20,7 @@
3DBE0D821F3B1B0C0099AA32 /* fishhook.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3DBE0D131F3B185A0099AA32 /* fishhook.h */; };
A12E9E2E1E5DEC4E0029001B /* RCTReconnectingWebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = A12E9E2D1E5DEC4E0029001B /* RCTReconnectingWebSocket.m */; };
A12E9E2F1E5DEC550029001B /* RCTReconnectingWebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = A12E9E2D1E5DEC4E0029001B /* RCTReconnectingWebSocket.m */; };
+ ED297176215062BA00B7C4FE /* libfishhook-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DBE0D0D1F3B181C0099AA32 /* libfishhook-tvOS.a */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -95,7 +95,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 2DC5E5281F3A6CFD000EE84B /* libfishhook-tvOS.a in Frameworks */,
+ ED297176215062BA00B7C4FE /* libfishhook-tvOS.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};

Libraries/WebSocket/WebSocketEvent.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/WebSocket/WebSocketInterceptor.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/WebSocket/WebSocket.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -23,7 +23,7 @@
* run Flow. */
const base64 = require('base64-js');
const binaryToBase64 = require('binaryToBase64');
-const invariant = require('fbjs/lib/invariant');
+const invariant = require('invariant');
const {WebSocketModule} = NativeModules;
@@ -175,10 +175,6 @@
this._binaryType = binaryType;
}
- get binaryType(): ?BinaryType {
- return this._binaryType;
- }
-
close(code?: number, reason?: string): void {
if (this.readyState === this.CLOSING || this.readyState === this.CLOSED) {
return;

Libraries/Wrapper/Example/RCTWrapperExampleViewController.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the license found in the
// LICENSE-examples file in the root directory of this source tree.

Libraries/Wrapper/Example/RCTWrapperExampleViewController.m

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the license found in the
// LICENSE-examples file in the root directory of this source tree.

Libraries/Wrapper/Example/RCTWrapperExampleView.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the license found in the
// LICENSE-examples file in the root directory of this source tree.

Libraries/Wrapper/Example/RCTWrapperExampleView.m

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the license found in the
// LICENSE-examples file in the root directory of this source tree.

Libraries/Wrapper/Example/RCTWrapperReactRootViewController.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the license found in the
// LICENSE-examples file in the root directory of this source tree.

Libraries/Wrapper/Example/RCTWrapperReactRootViewController.m

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the license found in the
// LICENSE-examples file in the root directory of this source tree.

Libraries/Wrapper/Example/RCTWrapperReactRootViewManager.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the license found in the
// LICENSE-examples file in the root directory of this source tree.

Libraries/Wrapper/Example/RCTWrapperReactRootViewManager.m

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the license found in the
// LICENSE-examples file in the root directory of this source tree.

Libraries/Wrapper/RCTWrapper.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

Libraries/Wrapper/RCTWrapperShadowView.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

Libraries/Wrapper/RCTWrapperShadowView.m

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

Libraries/Wrapper/RCTWrapperViewControllerHostingView.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

Libraries/Wrapper/RCTWrapperViewControllerHostingView.m

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

Libraries/Wrapper/RCTWrapperView.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

Libraries/Wrapper/RCTWrapperView.m

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

Libraries/Wrapper/RCTWrapperViewManager.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

Libraries/Wrapper/RCTWrapperViewManager.m

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

Libraries/YellowBox/Data/YellowBoxCategory.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/YellowBox/Data/YellowBoxRegistry.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/YellowBox/Data/YellowBoxSymbolication.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -21,6 +21,10 @@
const cache: Map<CacheKey, Promise<Stack>> = new Map();
const YellowBoxSymbolication = {
+ delete(stack: Stack): void {
+ cache.delete(getCacheKey(stack));
+ },
+
symbolicate(stack: Stack): Promise<Stack> {
const key = getCacheKey(stack);

Libraries/YellowBox/Data/YellowBoxWarning.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -63,6 +63,11 @@
: this.stack;
}
+ retrySymbolicate(callback: () => void): SymbolicationRequest {
+ YellowBoxSymbolication.delete(this.stack);
+ return this.symbolicate(callback);
+ }
+
symbolicate(callback: () => void): SymbolicationRequest {
let aborted = false;

Libraries/YellowBox/UI/YellowBoxButton.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/YellowBox/UI/YellowBoxImageSource.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -41,6 +41,18 @@
: scale > 1
? 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAf0lEQVRYhe2UvQ2AIBQGL3EBR3AESkv3bxxFN8DmWUgwvkI+En1X0cBd+IMg+DuDyDMCs413kfMiX4EMbD3l8oCaPIU85B4mYLEF5XJscrYFPRGvb/sZ4IlocubJGdH0wj1FSG77XYT0qdUi5O+8jOjyyZQRUnkZ0UUeBMF3OQC/0VsyGlxligAAAABJRU5ErkJggg=='
: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAASElEQVQ4jWNgGJHAgIGBIYESze8ZGBjWU6L5PAMDgwBNNCdAFZJt83qoQmRDSHK2AFQhzBCy/IxsCNkBJsDAwLAfiknWPBIBAETPFeuA4fr6AAAAAElFTkSuQmCC',
+ chevronLeft:
+ scale > 2
+ ? 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAgElEQVRoge3YMQ6DQBAEwRYvnf8nPAECbAnkyATsrt0lXUyPdAE6kCRJ/yXA+jopLbkhwHY6a2nNl8I1ftSA8Bm/MeQKBeNrBONrBONrBONrhMHxcPwOlMUvT32oszD8CoEj+giO6CE4oofgiB7Cj44Y86zyFoYPgOFPi5Ik6WwHji+QVIOyhqgAAAAASUVORK5CYII='
+ : scale > 1
+ ? 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAAaUlEQVRYhe3WsQ2AMAwAwRcs5LEYg3HpYANoQKKgcEEUI/6adM5LbgySfmZsNDeACdiApdEfaQGswH6+Xd1jugc9xYQxxhjz9RhaxwxvDuul3MrAqDyjsozKKnWgXUqdsJcAZgqsTFJ5B7gjUNw0n0HHAAAAAElFTkSuQmCC'
+ : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAARklEQVQ4jWNgGPKAmUh1AQwMDBIMDAwPyLEkgYGB4T/UELI1J9BdcwCxmpnIMZ1YkECsK+hmCNZoZCHCgAUMDAwfoHg4AgDJuQ/bcLyV+QAAAABJRU5ErkJggg==',
+ chevronRight:
+ scale > 2
+ ? 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAeElEQVRoge3YMQ6AIBQE0Ykn3fs3HEEbC6MdFp+v8xJaspNQAZIkqbcA4zwpXTJpAPvlpHTNhHtAu4jwDDCiQjBiDcGINQQj1hCMWEN4Boy3l25vL/iL0PgJBcfXCI6vERxfIzi+Rmg8Hj7wrdL+Yys0/1qUJEmzDvSAkFQ8EOdJAAAAAElFTkSuQmCC'
+ : scale > 1
+ ? 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAAZElEQVRYhe3WsQmAQAxA0Y8ulLEcw3HtdANtBNvzCJjD/5pUgQ9pApJ+Zu7YCWABDmDLzemzA+c94+MW4AkqExUY1caoVka1GibqlSm7qJJSJzPGGGMylYqBgi9sACtFYiQN7wKC6VDcJ7tlpQAAAABJRU5ErkJggg=='
+ : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAANUlEQVQ4jWNgGLbAgYGBIYASAwIYGBj+MzAwJFBiSMLQMISJEpMptp2mmimORgcGChPSEAIAHGENPH8gqdYAAAAASUVORK5CYII=',
loader:
scale > 2
? 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAABXElEQVRoge2a3W3DMAyEr+0CHkGjaISOcKN4k6zQETpCR+gGzgbpQ10kcamIpKQ6avQBBPxg3pHwL2UDg/8LASxrcNdKnCwATmssrUyeWgnju/DmXs8tRP+Sh2kgAJga1rFlWj2rcMD5YqQh77QJLbzIORjyRIJQCJW5ngYo5AVlrsgkCGqbsDbAhFfxqZsSZibP0oDXQ43HQPsg82i7sBoR+VcJq2YxKcPo0IoJLRZXmYGC6ezQmQUdVqhPBVH/CNBTSMkLVlzjA8Bbocb7GoPBoADi+umZilYzbrG/JrnljOvy734iu4To/BQaDB6Rl4LciPPF9Lmjhgvi+s7w6tCIGw3WKS0P8fvWNjt0ZkGHFeq7CQXTbkZKGg2JOxrqPUZ3s6ziNdju38IjS/dLi0EQpDLX2gDQYHEX6Hx5/YcA+6H0NgAYPnCMj3x7Mxq4wTGx3Q1E578aDDR8AX0mOGD6BEN/AAAAAElFTkSuQmCC'

Libraries/YellowBox/UI/YellowBoxInspectorFooter.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/YellowBox/UI/YellowBoxInspectorHeader.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,13 +10,14 @@
'use strict';
+const Image = require('Image');
const Platform = require('Platform');
const React = require('React');
const SafeAreaView = require('SafeAreaView');
const StyleSheet = require('StyleSheet');
const Text = require('Text');
-const UTFSequence = require('UTFSequence');
const View = require('View');
+const YellowBoxImageSource = require('YellowBoxImageSource');
const YellowBoxPressable = require('YellowBoxPressable');
const YellowBoxStyle = require('YellowBoxStyle');
@@ -42,7 +43,7 @@
<View style={styles.header}>
<YellowBoxInspectorHeaderButton
disabled={props.warnings[prevIndex] == null}
- label={UTFSequence.TRIANGLE_LEFT}
+ image={YellowBoxImageSource.chevronLeft}
onPress={() => props.onSelectIndex(prevIndex)}
/>
<View style={styles.headerTitle}>
@@ -50,7 +51,7 @@
</View>
<YellowBoxInspectorHeaderButton
disabled={props.warnings[nextIndex] == null}
- label={UTFSequence.TRIANGLE_RIGHT}
+ image={YellowBoxImageSource.chevronRight}
onPress={() => props.onSelectIndex(nextIndex)}
/>
</View>
@@ -61,7 +62,7 @@
const YellowBoxInspectorHeaderButton = (
props: $ReadOnly<{|
disabled: boolean,
- label: React.Node,
+ image: string,
onPress?: ?() => void,
|}>,
): React.Node => (
@@ -73,7 +74,10 @@
onPress={props.disabled ? null : props.onPress}
style={styles.headerButton}>
{props.disabled ? null : (
- <Text style={styles.headerButtonText}>{props.label}</Text>
+ <Image
+ source={{height: 16, uri: props.image, width: 16}}
+ style={styles.headerButtonImage}
+ />
)}
</YellowBoxPressable>
);
@@ -94,11 +98,8 @@
aspectRatio: 1,
justifyContent: 'center',
},
- headerButtonText: {
- color: YellowBoxStyle.getTextColor(1),
- fontSize: 16,
- includeFontPadding: false,
- lineHeight: 20,
+ headerButtonImage: {
+ tintColor: YellowBoxStyle.getTextColor(1),
},
headerTitle: {
alignItems: 'center',

Libraries/YellowBox/UI/YellowBoxInspector.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -77,6 +77,11 @@
<View style={styles.bodyHeading}>
<Text style={styles.bodyHeadingText}>Stack</Text>
<YellowBoxInspectorSourceMapStatus
+ onPress={
+ warning.symbolicated.status === 'FAILED'
+ ? this._handleRetrySymbolication
+ : null
+ }
status={warning.symbolicated.status}
/>
</View>
@@ -121,6 +126,16 @@
this._cancelSymbolication();
}
+ _handleRetrySymbolication = () => {
+ this._cancelSymbolication();
+ this.forceUpdate(() => {
+ const warning = this.props.warnings[this.state.selectedIndex];
+ this._symbolication = warning.retrySymbolicate(() => {
+ this.forceUpdate();
+ });
+ });
+ };
+
_handleSymbolication(): void {
const warning = this.props.warnings[this.state.selectedIndex];
if (warning.symbolicated.status !== 'COMPLETE') {

Libraries/YellowBox/UI/YellowBoxInspectorSourceMapStatus.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -15,14 +15,16 @@
const React = require('React');
const StyleSheet = require('StyleSheet');
const Text = require('Text');
-const View = require('View');
const YellowBoxImageSource = require('YellowBoxImageSource');
+const YellowBoxPressable = require('YellowBoxPressable');
const YellowBoxStyle = require('YellowBoxStyle');
import type {CompositeAnimation} from 'AnimatedImplementation';
import type AnimatedInterpolation from 'AnimatedInterpolation';
+import type {PressEvent} from 'CoreEventTypes';
type Props = $ReadOnly<{|
+ onPress?: ?(event: PressEvent) => void,
status: 'COMPLETE' | 'FAILED' | 'NONE' | 'PENDING',
|}>;
@@ -52,7 +54,13 @@
}
return image == null ? null : (
- <View
+ <YellowBoxPressable
+ backgroundColor={{
+ default: YellowBoxStyle.getTextColor(0.8),
+ pressed: YellowBoxStyle.getTextColor(0.6),
+ }}
+ hitSlop={{bottom: 8, left: 8, right: 8, top: 8}}
+ onPress={this.props.onPress}
style={StyleSheet.compose(
styles.root,
this.props.status === 'PENDING' ? styles.pending : null,
@@ -67,7 +75,7 @@
)}
/>
<Text style={styles.text}>Source Map</Text>
- </View>
+ </YellowBoxPressable>
);
}
@@ -125,7 +133,6 @@
const styles = StyleSheet.create({
root: {
alignItems: 'center',
- backgroundColor: YellowBoxStyle.getTextColor(0.8),
borderRadius: 12,
flexDirection: 'row',
height: 24,

Libraries/YellowBox/UI/YellowBoxInspectorStackFrame.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/YellowBox/UI/YellowBoxList.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/YellowBox/UI/YellowBoxListRow.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/YellowBox/UI/YellowBoxPressable.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/YellowBox/UI/YellowBoxStyle.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

Libraries/YellowBox/YellowBox.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

LICENSE

@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2015-present, Facebook, Inc.
+Copyright (c) Facebook, Inc. and its affiliates.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

local-cli/bundle/assetPathUtils.js

@@ -1,85 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow strict
- */
-
-'use strict';
-
-import type {PackagerAsset} from '../../Libraries/Image/AssetRegistry';
-
-/**
- * FIXME: using number to represent discrete scale numbers is fragile in essence because of
- * floating point numbers imprecision.
- */
-function getAndroidAssetSuffix(scale: number): string {
- switch (scale) {
- case 0.75:
- return 'ldpi';
- case 1:
- return 'mdpi';
- case 1.5:
- return 'hdpi';
- case 2:
- return 'xhdpi';
- case 3:
- return 'xxhdpi';
- case 4:
- return 'xxxhdpi';
- }
- throw new Error('no such scale');
-}
-
-// See https://developer.android.com/guide/topics/resources/drawable-resource.html
-const drawableFileTypes = new Set([
- 'gif',
- 'jpeg',
- 'jpg',
- 'png',
- 'svg',
- 'webp',
- 'xml',
-]);
-
-function getAndroidResourceFolderName(asset: PackagerAsset, scale: number) {
- if (!drawableFileTypes.has(asset.type)) {
- return 'raw';
- }
- var suffix = getAndroidAssetSuffix(scale);
- if (!suffix) {
- throw new Error(
- "Don't know which android drawable suffix to use for asset: " +
- JSON.stringify(asset),
- );
- }
- const androidFolder = 'drawable-' + suffix;
- return androidFolder;
-}
-
-function getAndroidResourceIdentifier(asset: PackagerAsset) {
- var folderPath = getBasePath(asset);
- return (folderPath + '/' + asset.name)
- .toLowerCase()
- .replace(/\//g, '_') // Encode folder structure in file name
- .replace(/([^a-z0-9_])/g, '') // Remove illegal chars
- .replace(/^assets_/, ''); // Remove "assets_" prefix
-}
-
-function getBasePath(asset: PackagerAsset) {
- var basePath = asset.httpServerLocation;
- if (basePath[0] === '/') {
- basePath = basePath.substr(1);
- }
- return basePath;
-}
-
-module.exports = {
- getAndroidAssetSuffix: getAndroidAssetSuffix,
- getAndroidResourceFolderName: getAndroidResourceFolderName,
- getAndroidResourceIdentifier: getAndroidResourceIdentifier,
- getBasePath: getBasePath,
-};

local-cli/bundle/buildBundle.js

@@ -1,77 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow
- */
-
-'use strict';
-
-const log = require('../util/log').out('bundle');
-/* $FlowFixMe(site=react_native_oss) */
-const Server = require('metro/src/Server');
-
-/* $FlowFixMe(site=react_native_oss) */
-const outputBundle = require('metro/src/shared/output/bundle');
-const path = require('path');
-const saveAssets = require('./saveAssets');
-
-import type {RequestOptions, OutputOptions} from './types.flow';
-/* $FlowFixMe(site=react_native_oss) */
-import type {ConfigT} from 'metro-config/src/configTypes.flow';
-
-async function buildBundle(
- args: OutputOptions & {
- assetsDest: mixed,
- entryFile: string,
- maxWorkers: number,
- resetCache: boolean,
- transformer: string,
- minify: boolean,
- },
- configPromise: Promise<ConfigT>,
- output = outputBundle,
-) {
- // This is used by a bazillion of npm modules we don't control so we don't
- // have other choice than defining it as an env variable here.
- process.env.NODE_ENV = args.dev ? 'development' : 'production';
- const config = await configPromise;
-
- let sourceMapUrl = args.sourcemapOutput;
- if (sourceMapUrl && !args.sourcemapUseAbsolutePath) {
- sourceMapUrl = path.basename(sourceMapUrl);
- }
-
- const requestOpts: RequestOptions = {
- entryFile: args.entryFile,
- sourceMapUrl,
- dev: args.dev,
- minify: args.minify !== undefined ? args.minify : !args.dev,
- platform: args.platform,
- };
-
- const server = new Server({...config, resetCache: args.resetCache});
-
- try {
- const bundle = await output.build(server, requestOpts);
-
- await output.save(bundle, args, log);
-
- // Save the assets of the bundle
- const outputAssets = await server.getAssets({
- ...Server.DEFAULT_BUNDLE_OPTIONS,
- ...requestOpts,
- bundleType: 'todo',
- });
-
- // When we're done saving bundle output and the assets, we're done.
- return await saveAssets(outputAssets, args.platform, args.assetsDest);
- } finally {
- server.end();
- }
-}
-
-module.exports = buildBundle;

local-cli/bundle/bundleCommandLineArgs.js

@@ -1,96 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-module.exports = [
- {
- command: '--entry-file <path>',
- description:
- 'Path to the root JS file, either absolute or relative to JS root',
- },
- {
- command: '--platform [string]',
- description: 'Either "ios" or "android"',
- default: 'ios',
- },
- {
- command: '--transformer [string]',
- description: 'Specify a custom transformer to be used',
- },
- {
- command: '--dev [boolean]',
- description: 'If false, warnings are disabled and the bundle is minified',
- parse: val => (val === 'false' ? false : true),
- default: true,
- },
- {
- command: '--minify [boolean]',
- description:
- 'Allows overriding whether bundle is minified. This defaults to ' +
- 'false if dev is true, and true if dev is false. Disabling minification ' +
- 'can be useful for speeding up production builds for testing purposes.',
- parse: val => (val === 'false' ? false : true),
- },
- {
- command: '--bundle-output <string>',
- description:
- 'File name where to store the resulting bundle, ex. /tmp/groups.bundle',
- },
- {
- command: '--bundle-encoding [string]',
- description:
- 'Encoding the bundle should be written in (https://nodejs.org/api/buffer.html#buffer_buffer).',
- default: 'utf8',
- },
- {
- command: '--max-workers [number]',
- description:
- 'Specifies the maximum number of workers the worker-pool ' +
- 'will spawn for transforming files. This defaults to the number of the ' +
- 'cores available on your machine.',
- parse: (workers: string) => Number(workers),
- },
- {
- command: '--sourcemap-output [string]',
- description:
- 'File name where to store the sourcemap file for resulting bundle, ex. /tmp/groups.map',
- },
- {
- command: '--sourcemap-sources-root [string]',
- description:
- "Path to make sourcemap's sources entries relative to, ex. /root/dir",
- },
- {
- command: '--sourcemap-use-absolute-path',
- description: 'Report SourceMapURL using its full path',
- default: false,
- },
- {
- command: '--assets-dest [string]',
- description:
- 'Directory name where to store assets referenced in the bundle',
- },
- {
- command: '--verbose',
- description: 'Enables logging',
- default: false,
- },
- {
- command: '--reset-cache',
- description: 'Removes cached files',
- default: false,
- },
- {
- command: '--read-global-cache',
- description:
- 'Try to fetch transformed JS code from the global cache, if configured.',
- default: false,
- },
-];

local-cli/bundle/bundle.js

@@ -1,34 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const buildBundle = require('./buildBundle');
-const bundleCommandLineArgs = require('./bundleCommandLineArgs');
-const outputBundle = require('metro/src/shared/output/bundle');
-
-/**
- * Builds the bundle starting to look for dependencies at the given entry path.
- */
-function bundleWithOutput(argv, configPromise, args, output) {
- if (!output) {
- output = outputBundle;
- }
- return buildBundle(args, configPromise, output);
-}
-
-module.exports = {
- name: 'bundle',
- description: 'builds the javascript bundle for offline use',
- func: bundleWithOutput,
- options: bundleCommandLineArgs,
-
- // not used by the CLI itself
- withOutput: bundleWithOutput,
-};

local-cli/bundle/filterPlatformAssetScales.js

@@ -1,46 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @flow strict
- * @format
- */
-
-'use strict';
-
-const ALLOWED_SCALES = {
- ios: [1, 2, 3],
-};
-
-function filterPlatformAssetScales(
- platform: string,
- scales: $ReadOnlyArray<number>,
-): $ReadOnlyArray<number> {
- const whitelist = ALLOWED_SCALES[platform];
- if (!whitelist) {
- return scales;
- }
- const result = scales.filter(scale => whitelist.indexOf(scale) > -1);
- if (result.length === 0 && scales.length > 0) {
- // No matching scale found, but there are some available. Ideally we don't
- // want to be in this situation and should throw, but for now as a fallback
- // let's just use the closest larger image
- const maxScale = whitelist[whitelist.length - 1];
- for (const scale of scales) {
- if (scale > maxScale) {
- result.push(scale);
- break;
- }
- }
-
- // There is no larger scales available, use the largest we have
- if (result.length === 0) {
- result.push(scales[scales.length - 1]);
- }
- }
- return result;
-}
-
-module.exports = filterPlatformAssetScales;

local-cli/bundle/getAssetDestPathAndroid.js

@@ -1,27 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow strict
- */
-
-'use strict';
-
-const assetPathUtils = require('./assetPathUtils');
-const path = require('path');
-
-import type {PackagerAsset} from '../../Libraries/Image/AssetRegistry';
-
-function getAssetDestPathAndroid(asset: PackagerAsset, scale: number): string {
- const androidFolder = assetPathUtils.getAndroidResourceFolderName(
- asset,
- scale,
- );
- const fileName = assetPathUtils.getAndroidResourceIdentifier(asset);
- return path.join(androidFolder, fileName + '.' + asset.type);
-}
-
-module.exports = getAssetDestPathAndroid;

local-cli/bundle/getAssetDestPathIOS.js

@@ -1,23 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow strict
- */
-
-'use strict';
-
-const path = require('path');
-
-import type {PackagerAsset} from '../../Libraries/Image/AssetRegistry';
-
-function getAssetDestPathIOS(asset: PackagerAsset, scale: number): string {
- const suffix = scale === 1 ? '' : '@' + scale + 'x';
- const fileName = asset.name + suffix + '.' + asset.type;
- return path.join(asset.httpServerLocation.substr(1), fileName);
-}
-
-module.exports = getAssetDestPathIOS;

local-cli/bundle/__mocks__/sign.js

@@ -1,16 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-function sign(source) {
- return source;
-}
-
-module.exports = sign;

local-cli/bundle/ramBundle.js

@@ -1,34 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const bundleWithOutput = require('./bundle').withOutput;
-const bundleCommandLineArgs = require('./bundleCommandLineArgs');
-const outputUnbundle = require('metro/src/shared/output/unbundle');
-
-/**
- * Builds the bundle starting to look for dependencies at the given entry path.
- */
-function ramBundle(argv, config, args) {
- return bundleWithOutput(argv, config, args, outputUnbundle);
-}
-
-module.exports = {
- name: 'ram-bundle',
- description:
- 'builds javascript as a "Random Access Module" bundle for offline use',
- func: ramBundle,
- options: bundleCommandLineArgs.concat({
- command: '--indexed-ram-bundle',
- description:
- 'Force the "Indexed RAM" bundle file format, even when building for android',
- default: false,
- }),
-};

local-cli/bundle/saveAssets.js

@@ -1,84 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const filterPlatformAssetScales = require('./filterPlatformAssetScales');
-const fs = require('fs');
-const getAssetDestPathAndroid = require('./getAssetDestPathAndroid');
-const getAssetDestPathIOS = require('./getAssetDestPathIOS');
-const log = require('../util/log').out('bundle');
-const mkdirp = require('mkdirp');
-const path = require('path');
-
-function saveAssets(assets, platform, assetsDest) {
- if (!assetsDest) {
- console.warn('Assets destination folder is not set, skipping...');
- return Promise.resolve();
- }
-
- const getAssetDestPath =
- platform === 'android' ? getAssetDestPathAndroid : getAssetDestPathIOS;
-
- const filesToCopy = Object.create(null); // Map src -> dest
- assets.forEach(asset => {
- const validScales = new Set(
- filterPlatformAssetScales(platform, asset.scales),
- );
- asset.scales.forEach((scale, idx) => {
- if (!validScales.has(scale)) {
- return;
- }
- const src = asset.files[idx];
- const dest = path.join(assetsDest, getAssetDestPath(asset, scale));
- filesToCopy[src] = dest;
- });
- });
-
- return copyAll(filesToCopy);
-}
-
-function copyAll(filesToCopy) {
- const queue = Object.keys(filesToCopy);
- if (queue.length === 0) {
- return Promise.resolve();
- }
-
- log('Copying ' + queue.length + ' asset files');
- return new Promise((resolve, reject) => {
- const copyNext = error => {
- if (error) {
- return reject(error);
- }
- if (queue.length === 0) {
- log('Done copying assets');
- resolve();
- } else {
- const src = queue.shift();
- const dest = filesToCopy[src];
- copy(src, dest, copyNext);
- }
- };
- copyNext();
- });
-}
-
-function copy(src, dest, callback) {
- const destDir = path.dirname(dest);
- mkdirp(destDir, err => {
- if (err) {
- return callback(err);
- }
- fs.createReadStream(src)
- .pipe(fs.createWriteStream(dest))
- .on('finish', callback);
- });
-}
-
-module.exports = saveAssets;

local-cli/bundle/types.flow.js

@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow
- */
-
-'use strict';
-
-/* $FlowFixMe(site=react_native_oss) */
-export type {OutputOptions, RequestOptions} from 'metro/src/shared/types.flow';

local-cli/bundle/unbundle.js

@@ -1,30 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const bundleCommandLineArgs = require('./bundleCommandLineArgs');
-
-module.exports = {
- name: 'unbundle',
- description: 'Deprecated. Renamed to `ram-bundle`.',
- func: () => {
- throw new Error(
- 'The `unbundle` command has been renamed `ram-bundle` to better ' +
- 'represent the actual functionality. `ram` mean "Random Access ' +
- 'Module", this particular format of bundle. Functionality remained ' +
- 'unchanged.',
- );
- },
- options: bundleCommandLineArgs.concat({
- command: '--indexed-unbundle',
- description: 'Deprecated. Renamed to `--indexed-ram-bundle`.',
- default: false,
- }),
-};

local-cli/cliEntry.js

@@ -1,169 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow
- */
-
-'use strict';
-
-const {configPromise} = require('./core');
-
-const assertRequiredOptions = require('./util/assertRequiredOptions');
-/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
- * found when Flow v0.54 was deployed. To see the error delete this comment and
- * run Flow. */
-const chalk = require('chalk');
-const childProcess = require('child_process');
-/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
- * found when Flow v0.54 was deployed. To see the error delete this comment and
- * run Flow. */
-const commander = require('commander');
-const commands = require('./commands');
-const init = require('./init/init');
-const path = require('path');
-const pkg = require('../package.json');
-
-import type {CommandT} from './commands';
-import type {RNConfig} from './core';
-
-commander.version(pkg.version);
-
-const defaultOptParser = val => val;
-
-const handleError = err => {
- console.error();
- console.error(err.message || err);
- console.error();
- if (err.stack) {
- console.error(err.stack);
- console.error();
- }
- process.exit(1);
-};
-
-// Custom printHelpInformation command inspired by internal Commander.js
-// one modified to suit our needs
-function printHelpInformation() {
- let cmdName = this._name;
- if (this._alias) {
- cmdName = cmdName + '|' + this._alias;
- }
-
- const sourceInformation = this.pkg
- ? [` ${chalk.bold('Source:')} ${this.pkg.name}@${this.pkg.version}`, '']
- : [];
-
- let output = [
- '',
- chalk.bold(chalk.cyan(` react-native ${cmdName} ${this.usage()}`)),
- this._description ? ` ${this._description}` : '',
- '',
- ...sourceInformation,
- ` ${chalk.bold('Options:')}`,
- '',
- this.optionHelp().replace(/^/gm, ' '),
- '',
- ];
-
- if (this.examples && this.examples.length > 0) {
- const formattedUsage = this.examples
- .map(example => ` ${example.desc}: \n ${chalk.cyan(example.cmd)}`)
- .join('\n\n');
-
- output = output.concat([
- chalk.bold(' Example usage:'),
- '',
- formattedUsage,
- ]);
- }
-
- return output.concat(['', '']).join('\n');
-}
-
-function printUnknownCommand(cmdName) {
- console.log(
- [
- '',
- cmdName
- ? chalk.red(` Unrecognized command '${cmdName}'`)
- : chalk.red(" You didn't pass any command"),
- ` Run ${chalk.cyan(
- 'react-native --help',
- )} to see list of all available commands`,
- '',
- ].join('\n'),
- );
-}
-
-const addCommand = (command: CommandT, cfg: RNConfig) => {
- const options = command.options || [];
-
- const cmd = commander
- .command(command.name, undefined, {
- noHelp: !command.description,
- })
- .description(command.description)
- .action(function runAction() {
- const passedOptions = this.opts();
- const argv: Array<string> = Array.from(arguments).slice(0, -1);
-
- Promise.resolve()
- .then(() => {
- assertRequiredOptions(options, passedOptions);
- return command.func(argv, cfg, passedOptions);
- })
- .catch(handleError);
- });
-
- cmd.helpInformation = printHelpInformation.bind(cmd);
- cmd.examples = command.examples;
- cmd.pkg = command.pkg;
-
- options.forEach(opt =>
- cmd.option(
- opt.command,
- opt.description,
- opt.parse || defaultOptParser,
- typeof opt.default === 'function' ? opt.default(cfg) : opt.default,
- ),
- );
-
- // Placeholder option for --config, which is parsed before any other option,
- // but needs to be here to avoid "unknown option" errors when specified
- cmd.option('--config [string]', 'Path to the CLI configuration file');
-};
-
-async function run() {
- const config = await configPromise;
- const setupEnvScript = /^win/.test(process.platform)
- ? 'setup_env.bat'
- : 'setup_env.sh';
-
- childProcess.execFileSync(path.join(__dirname, setupEnvScript));
-
- commands.forEach(cmd => addCommand(cmd, config));
-
- commander.parse(process.argv);
-
- const isValidCommand = commands.find(
- cmd => cmd.name.split(' ')[0] === process.argv[2],
- );
-
- if (!isValidCommand) {
- printUnknownCommand(process.argv[2]);
- return;
- }
-
- if (!commander.args.length) {
- commander.help();
- }
-}
-
-module.exports = {
- run: run,
- init: init,
-};

local-cli/cli.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,19 +9,10 @@
'use strict';
-// gracefulify() has to be called before anything else runs
-require('graceful-fs').gracefulify(require('fs'));
-
-// This file must be able to run in node 0.12 without babel so we can show that
-// it is not supported. This is why the rest of the cli code is in `cliEntry.js`.
-require('./server/checkNodeVersion')();
-
-require('../setupBabel')();
-
-var cliEntry = require('./cliEntry');
+var cli = require('@react-native-community/cli');
if (require.main === module) {
- cliEntry.run();
+ cli.run();
}
-module.exports = cliEntry;
+module.exports = cli;

local-cli/commands.js

@@ -1,80 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow
- */
-
-'use strict';
-
-const {getProjectCommands} = require('./core');
-
-import type {RNConfig} from './core';
-
-export type CommandT = {
- name: string,
- description?: string,
- usage?: string,
- func: (argv: Array<string>, config: RNConfig, args: Object) => ?Promise<void>,
- options?: Array<{
- command: string,
- description?: string,
- parse?: (val: string) => any,
- default?: ((config: RNConfig) => mixed) | mixed,
- }>,
- examples?: Array<{
- desc: string,
- cmd: string,
- }>,
- pkg?: {
- version: string,
- name: string,
- },
-};
-
-const documentedCommands = [
- require('./server/server'),
- require('./runIOS/runIOS'),
- require('./runAndroid/runAndroid'),
- require('./library/library'),
- require('./bundle/bundle'),
- require('./bundle/unbundle'),
- require('./bundle/ramBundle'),
- require('./eject/eject'),
- require('./link/link'),
- require('./link/unlink'),
- require('./install/install'),
- require('./install/uninstall'),
- require('./upgrade/upgrade'),
- require('./logAndroid/logAndroid'),
- require('./logIOS/logIOS'),
- require('./dependencies/dependencies'),
- require('./info/info'),
-];
-
-// The user should never get here because projects are inited by
-// using `react-native-cli` from outside a project directory.
-const undocumentedCommands = [
- {
- name: 'init',
- func: () => {
- console.log(
- [
- 'Looks like React Native project already exists in the current',
- 'folder. Run this command from a different folder or remove node_modules/react-native',
- ].join('\n'),
- );
- },
- },
-];
-
-const commands: Array<CommandT> = [
- ...documentedCommands,
- ...undocumentedCommands,
- ...getProjectCommands(),
-];
-
-module.exports = commands;

local-cli/core/android/findAndroidAppFolder.js

@@ -1,32 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const fs = require('fs');
-const path = require('path');
-
-/**
- * @param {String} folder Folder to seek in
- * @return {String}
- */
-module.exports = function findAndroidAppFolder(folder) {
- const flat = 'android';
- const nested = path.join('android', 'app');
-
- if (fs.existsSync(path.join(folder, nested))) {
- return nested;
- }
-
- if (fs.existsSync(path.join(folder, flat))) {
- return flat;
- }
-
- return null;
-};

local-cli/core/android/findManifest.js

@@ -1,28 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const glob = require('glob');
-const path = require('path');
-
-/**
- * Find an android application path in the folder
- *
- * @param {String} folder Name of the folder where to seek
- * @return {String}
- */
-module.exports = function findManifest(folder) {
- const manifestPath = glob.sync(path.join('**', 'AndroidManifest.xml'), {
- cwd: folder,
- ignore: ['node_modules/**', '**/build/**', 'Examples/**', 'examples/**'],
- })[0];
-
- return manifestPath ? path.join(folder, manifestPath) : null;
-};

local-cli/core/android/findPackageClassName.js

@@ -1,31 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const fs = require('fs');
-const glob = require('glob');
-const path = require('path');
-
-/**
- * Gets package's class name (class that implements ReactPackage)
- * by searching for its declaration in all Java/Kotlin files present in the folder
- *
- * @param {String} folder Folder to find java/kt files
- */
-module.exports = function getPackageClassName(folder) {
- const files = glob.sync('**/+(*.java|*.kt)', {cwd: folder});
-
- const packages = files
- .map(filePath => fs.readFileSync(path.join(folder, filePath), 'utf8'))
- .map(file => file.match(/class (.*) +(implements|:) ReactPackage/))
- .filter(match => match);
-
- return packages.length ? packages[0][1] : null;
-};

local-cli/core/android/index.js

@@ -1,136 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const findAndroidAppFolder = require('./findAndroidAppFolder');
-const findManifest = require('./findManifest');
-const findPackageClassName = require('./findPackageClassName');
-const path = require('path');
-const readManifest = require('./readManifest');
-
-const getPackageName = manifest => manifest.attr.package;
-
-/**
- * Gets android project config by analyzing given folder and taking some
- * defaults specified by user into consideration
- */
-exports.projectConfig = function projectConfigAndroid(folder, userConfig = {}) {
- const src = userConfig.sourceDir || findAndroidAppFolder(folder);
-
- if (!src) {
- return null;
- }
-
- const sourceDir = path.join(folder, src);
- const isFlat = sourceDir.indexOf('app') === -1;
- const manifestPath = userConfig.manifestPath
- ? path.join(sourceDir, userConfig.manifestPath)
- : findManifest(sourceDir);
-
- if (!manifestPath) {
- return null;
- }
-
- const manifest = readManifest(manifestPath);
-
- const packageName = userConfig.packageName || getPackageName(manifest);
-
- if (!packageName) {
- throw new Error(`Package name not found in ${manifestPath}`);
- }
-
- const packageFolder =
- userConfig.packageFolder || packageName.replace(/\./g, path.sep);
-
- const mainFilePath = path.join(
- sourceDir,
- userConfig.mainFilePath ||
- `src/main/java/${packageFolder}/MainApplication.java`,
- );
-
- const stringsPath = path.join(
- sourceDir,
- userConfig.stringsPath || 'src/main/res/values/strings.xml',
- );
-
- const settingsGradlePath = path.join(
- folder,
- 'android',
- userConfig.settingsGradlePath || 'settings.gradle',
- );
-
- const assetsPath = path.join(
- sourceDir,
- userConfig.assetsPath || 'src/main/assets',
- );
-
- const buildGradlePath = path.join(
- sourceDir,
- userConfig.buildGradlePath || 'build.gradle',
- );
-
- return {
- sourceDir,
- isFlat,
- folder,
- stringsPath,
- manifestPath,
- buildGradlePath,
- settingsGradlePath,
- assetsPath,
- mainFilePath,
- };
-};
-
-/**
- * Same as projectConfigAndroid except it returns
- * different config that applies to packages only
- */
-exports.dependencyConfig = function dependencyConfigAndroid(
- folder,
- userConfig = {},
-) {
- const src = userConfig.sourceDir || findAndroidAppFolder(folder);
-
- if (!src) {
- return null;
- }
-
- const sourceDir = path.join(folder, src);
- const manifestPath = userConfig.manifestPath
- ? path.join(sourceDir, userConfig.manifestPath)
- : findManifest(sourceDir);
-
- if (!manifestPath) {
- return null;
- }
-
- const manifest = readManifest(manifestPath);
- const packageName = userConfig.packageName || getPackageName(manifest);
- const packageClassName = findPackageClassName(sourceDir);
-
- /**
- * This module has no package to export
- */
- if (!packageClassName) {
- return null;
- }
-
- const packageImportPath =
- userConfig.packageImportPath ||
- `import ${packageName}.${packageClassName};`;
-
- const packageInstance =
- userConfig.packageInstance || `new ${packageClassName}()`;
-
- return {sourceDir, folder, manifest, packageImportPath, packageInstance};
-};
-
-exports.linkConfig = require('../../link/android');

local-cli/core/android/readManifest.js

@@ -1,21 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const fs = require('fs');
-const xml = require('xmldoc');
-
-/**
- * @param {String} manifestPath
- * @return {XMLDocument} Parsed manifest's content
- */
-module.exports = function readManifest(manifestPath) {
- return new xml.XmlDocument(fs.readFileSync(manifestPath, 'utf8'));
-};

local-cli/core/Constants.js

@@ -1,20 +0,0 @@
-/**
- * Copyright (c) 2016-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @flow strict
- * @format
- */
-
-'use strict';
-
-const ASSET_REGISTRY_PATH = 'react-native/Libraries/Image/AssetRegistry';
-const ASSET_SOURCE_RESOLVER_PATH =
- 'react-native/Libraries/Image/AssetSourceResolver';
-
-module.exports = {
- ASSET_REGISTRY_PATH,
- ASSET_SOURCE_RESOLVER_PATH,
-};

local-cli/core/findAssets.js

@@ -1,32 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const glob = require('glob');
-const path = require('path');
-
-const findAssetsInFolder = folder =>
- glob.sync(path.join(folder, '**'), {nodir: true});
-
-/**
- * Given an array of assets folders, e.g. ['Fonts', 'Images'],
- * it globs in them to find all files that can be copied.
- *
- * It returns an array of absolute paths to files found.
- */
-module.exports = function findAssets(folder, assets) {
- return (assets || [])
- .map(assetsFolder => path.join(folder, assetsFolder))
- .reduce(
- (_assets, assetsFolder) =>
- _assets.concat(findAssetsInFolder(assetsFolder)),
- [],
- );
-};

local-cli/core/findPlugins.js

@@ -1,133 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const path = require('path');
-const union = require('lodash').union;
-const uniq = require('lodash').uniq;
-const flatten = require('lodash').flatten;
-
-const RNPM_PLUGIN_PATTERNS = [/^rnpm-plugin-/, /^@(.*)\/rnpm-plugin-/];
-
-const REACT_NATIVE_PLUGIN_PATTERNS = [
- /^react-native-/,
- /^@(.*)\/react-native-/,
- /^@react-native(.*)\/(?!rnpm-plugin-)/,
-];
-
-/**
- * Filter dependencies by name pattern
- * @param {String} dependency Name of the dependency
- * @return {Boolean} If dependency is a rnpm plugin
- */
-const isRNPMPlugin = dependency =>
- RNPM_PLUGIN_PATTERNS.some(pattern => pattern.test(dependency));
-const isReactNativePlugin = dependency =>
- REACT_NATIVE_PLUGIN_PATTERNS.some(pattern => pattern.test(dependency));
-
-const readPackage = folder => {
- try {
- return require(path.join(folder, 'package.json'));
- } catch (e) {
- return null;
- }
-};
-
-const findPluginsInReactNativePackage = pjson => {
- if (!pjson.rnpm || !pjson.rnpm.plugin) {
- return [];
- }
-
- return path.join(pjson.name, pjson.rnpm.plugin);
-};
-
-const findPlatformsInPackage = pjson => {
- if (!pjson.rnpm || !pjson.rnpm.platform) {
- return [];
- }
-
- return path.join(pjson.name, pjson.rnpm.platform);
-};
-
-const getEmptyPluginConfig = () => ({
- commands: [],
- platforms: [],
- haste: {
- platforms: [],
- providesModuleNodeModules: [],
- },
-});
-
-const findHasteConfigInPackageAndConcat = (pjson, haste) => {
- if (!pjson.rnpm || !pjson.rnpm.haste) {
- return;
- }
- let pkgHaste = pjson.rnpm.haste;
-
- if (pkgHaste.platforms) {
- haste.platforms = haste.platforms.concat(pkgHaste.platforms);
- }
-
- if (pkgHaste.providesModuleNodeModules) {
- haste.providesModuleNodeModules = haste.providesModuleNodeModules.concat(
- pkgHaste.providesModuleNodeModules,
- );
- }
-};
-
-const findPluginInFolder = folder => {
- const pjson = readPackage(folder);
-
- if (!pjson) {
- return getEmptyPluginConfig();
- }
-
- const deps = union(
- Object.keys(pjson.dependencies || {}),
- Object.keys(pjson.devDependencies || {}),
- );
-
- return deps.reduce((acc, pkg) => {
- let commands = acc.commands;
- let platforms = acc.platforms;
- let haste = acc.haste;
- if (isRNPMPlugin(pkg)) {
- commands = commands.concat(pkg);
- }
- if (isReactNativePlugin(pkg)) {
- const pkgJson = readPackage(path.join(folder, 'node_modules', pkg));
- if (pkgJson) {
- commands = commands.concat(findPluginsInReactNativePackage(pkgJson));
- platforms = platforms.concat(findPlatformsInPackage(pkgJson));
- findHasteConfigInPackageAndConcat(pkgJson, haste);
- }
- }
- return {commands: commands, platforms: platforms, haste: haste};
- }, getEmptyPluginConfig());
-};
-
-/**
- * Find plugins in package.json of the given folder
- * @param {String} folder Path to the folder to get the package.json from
- * @type {Object} Object of commands and platform plugins
- */
-module.exports = function findPlugins(folders) {
- const plugins = folders.map(findPluginInFolder);
- return {
- commands: uniq(flatten(plugins.map(p => p.commands))),
- platforms: uniq(flatten(plugins.map(p => p.platforms))),
- haste: {
- platforms: uniq(flatten(plugins.map(p => p.haste.platforms))),
- providesModuleNodeModules: uniq(
- flatten(plugins.map(p => p.haste.providesModuleNodeModules)),
- ),
- },
- };
-};

local-cli/core/index.js

@@ -1,178 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow
- */
-
-'use strict';
-
-const android = require('./android');
-const Config = require('../util/Config');
-const findPlugins = require('./findPlugins');
-const findAssets = require('./findAssets');
-const ios = require('./ios');
-const wrapCommands = require('./wrapCommands');
-const {ASSET_REGISTRY_PATH} = require('./Constants');
-
-/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
- * found when Flow v0.54 was deployed. To see the error delete this comment and
- * run Flow. */
-const flatten = require('lodash').flatten;
-/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
- * found when Flow v0.54 was deployed. To see the error delete this comment and
- * run Flow. */
-const minimist = require('minimist');
-const path = require('path');
-
-import type {CommandT} from '../commands';
-/* $FlowFixMe(site=react_native_oss) */
-import type {ConfigT} from 'metro-config/src/configTypes.flow';
-
-export type RNConfig = {
- ...ConfigT,
- /**
- * Returns an object with all platform configurations.
- */
- getPlatformConfig(): Object,
- /**
- * Returns project config from the current working directory
- */
- getProjectConfig(): Object,
- /**
- * Returns dependency config from <node_modules>/packageName
- */
- getDependencyConfig(pkgName: string): Object,
-};
-
-const getRNPMConfig = folder =>
- // $FlowFixMe non-literal require
- require(path.join(folder, './package.json')).rnpm || {};
-
-const attachPackage = (command, pkg) =>
- Array.isArray(command)
- ? command.map(cmd => attachPackage(cmd, pkg))
- : {...command, pkg};
-
-const appRoot = process.cwd();
-const plugins = findPlugins([appRoot]);
-const pluginPlatforms = plugins.platforms.reduce((acc, pathToPlatforms) => {
- return Object.assign(
- acc,
- // $FlowFixMe non-literal require
- require(path.join(appRoot, 'node_modules', pathToPlatforms)),
- );
-}, {});
-
-const defaultConfig = {
- hasteImplModulePath: require.resolve('../../jest/hasteImpl'),
-
- getPlatforms(): Array<string> {
- return ['ios', 'android', 'native', ...plugins.haste.platforms];
- },
-
- getProvidesModuleNodeModules(): Array<string> {
- return ['react-native', ...plugins.haste.providesModuleNodeModules];
- },
-};
-
-const defaultRNConfig = {
- getPlatformConfig(): Object {
- return {
- ios,
- android,
- ...pluginPlatforms,
- };
- },
-
- getProjectConfig(): Object {
- const platforms = this.getPlatformConfig();
- const folder = process.cwd();
- const rnpm = getRNPMConfig(folder);
-
- let config = Object.assign({}, rnpm, {
- assets: findAssets(folder, rnpm.assets),
- });
-
- Object.keys(platforms).forEach(key => {
- config[key] = platforms[key].projectConfig(folder, rnpm[key] || {});
- });
-
- return config;
- },
-
- getDependencyConfig(packageName: string) {
- const platforms = this.getPlatformConfig();
- const folder = path.join(process.cwd(), 'node_modules', packageName);
- const rnpm = getRNPMConfig(folder);
-
- let config = Object.assign({}, rnpm, {
- assets: findAssets(folder, rnpm.assets),
- commands: wrapCommands(rnpm.commands),
- params: rnpm.params || [],
- });
-
- Object.keys(platforms).forEach(key => {
- config[key] = platforms[key].dependencyConfig(folder, rnpm[key] || {});
- });
-
- return config;
- },
-};
-
-/**
- * Loads the CLI configuration
- */
-async function getCliConfig(): Promise<RNConfig> {
- const cliArgs = minimist(process.argv.slice(2));
- const config = await Config.load(
- cliArgs.config != null ? path.resolve(__dirname, cliArgs.config) : null,
- );
-
- // $FlowFixMe Metro configuration is immutable.
- config.transformer.assetRegistryPath = ASSET_REGISTRY_PATH;
- // $FlowFixMe Metro configuration is immutable.
- config.resolver.hasteImplModulePath =
- config.resolver.hasteImplModulePath || defaultConfig.hasteImplModulePath;
- // $FlowFixMe Metro configuration is immutable.
- config.resolver.platforms = config.resolver.platforms
- ? config.resolver.platforms.concat(defaultConfig.getPlatforms())
- : defaultConfig.getPlatforms();
- // $FlowFixMe Metro configuration is immutable.
- config.resolver.providesModuleNodeModules = config.resolver
- .providesModuleNodeModules
- ? config.resolver.providesModuleNodeModules.concat(
- defaultConfig.getProvidesModuleNodeModules(),
- )
- : defaultConfig.getProvidesModuleNodeModules();
-
- return {...defaultRNConfig, ...config};
-}
-
-/**
- * Returns an array of project commands used by the CLI to load
- */
-function getProjectCommands(): Array<CommandT> {
- const commands = plugins.commands.map(pathToCommands => {
- const name =
- pathToCommands[0] === '@'
- ? pathToCommands
- .split(path.sep)
- .slice(0, 2)
- .join(path.sep)
- : pathToCommands.split(path.sep)[0];
-
- return attachPackage(
- require(path.join(appRoot, 'node_modules', pathToCommands)),
- require(path.join(appRoot, 'node_modules', name, 'package.json')),
- );
- });
-
- return flatten(commands);
-}
-
-module.exports.configPromise = getCliConfig();
-module.exports.getProjectCommands = getProjectCommands;

local-cli/core/ios/findPodfilePath.js

@@ -1,13 +0,0 @@
-/** @format */
-
-'use strict';
-
-const fs = require('fs');
-const path = require('path');
-
-module.exports = function findPodfilePath(projectFolder) {
- const podFilePath = path.join(projectFolder, '..', 'Podfile');
- const podFileExists = fs.existsSync(podFilePath);
-
- return podFileExists ? podFilePath : null;
-};

local-cli/core/ios/findPodspecName.js

@@ -1,27 +0,0 @@
-/** @format */
-
-'use strict';
-
-const glob = require('glob');
-const path = require('path');
-
-module.exports = function findPodspecName(folder) {
- const podspecs = glob.sync('*.podspec', {cwd: folder});
- let podspecFile = null;
- if (podspecs.length === 0) {
- return null;
- } else if (podspecs.length === 1) {
- podspecFile = podspecs[0];
- } else {
- const folderParts = folder.split(path.sep);
- const currentFolder = folderParts[folderParts.length - 1];
- const toSelect = podspecs.indexOf(currentFolder + '.podspec');
- if (toSelect === -1) {
- podspecFile = podspecs[0];
- } else {
- podspecFile = podspecs[toSelect];
- }
- }
-
- return podspecFile.replace('.podspec', '');
-};

local-cli/core/ios/findProject.js

@@ -1,61 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const glob = require('glob');
-const path = require('path');
-
-/**
- * Glob pattern to look for xcodeproj
- */
-const GLOB_PATTERN = '**/*.xcodeproj';
-
-/**
- * Regexp matching all test projects
- */
-const TEST_PROJECTS = /test|example|sample/i;
-
-/**
- * Base iOS folder
- */
-const IOS_BASE = 'ios';
-
-/**
- * These folders will be excluded from search to speed it up
- */
-const GLOB_EXCLUDE_PATTERN = ['**/@(Pods|node_modules)/**'];
-
-/**
- * Finds iOS project by looking for all .xcodeproj files
- * in given folder.
- *
- * Returns first match if files are found or null
- *
- * Note: `./ios/*.xcodeproj` are returned regardless of the name
- */
-module.exports = function findProject(folder) {
- const projects = glob
- .sync(GLOB_PATTERN, {
- cwd: folder,
- ignore: GLOB_EXCLUDE_PATTERN,
- })
- .filter(project => {
- return path.dirname(project) === IOS_BASE || !TEST_PROJECTS.test(project);
- })
- .sort((projectA, projectB) => {
- return path.dirname(projectA) === IOS_BASE ? -1 : 1;
- });
-
- if (projects.length === 0) {
- return null;
- }
-
- return projects[0];
-};

local-cli/core/ios/index.js

@@ -1,62 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const findProject = require('./findProject');
-const findPodfilePath = require('./findPodfilePath');
-const findPodspecName = require('./findPodspecName');
-const path = require('path');
-
-/**
- * For libraries specified without an extension, add '.tbd' for those that
- * start with 'lib' and '.framework' to the rest.
- */
-const mapSharedLibaries = libraries => {
- return libraries.map(name => {
- if (path.extname(name)) {
- return name;
- }
- return name + (name.indexOf('lib') === 0 ? '.tbd' : '.framework');
- });
-};
-
-/**
- * Returns project config by analyzing given folder and applying some user defaults
- * when constructing final object
- */
-exports.projectConfig = function projectConfigIOS(folder, userConfig) {
- const project = userConfig.project || findProject(folder);
-
- /**
- * No iOS config found here
- */
- if (!project) {
- return null;
- }
-
- const projectPath = path.join(folder, project);
-
- return {
- sourceDir: path.dirname(projectPath),
- folder: folder,
- pbxprojPath: path.join(projectPath, 'project.pbxproj'),
- podfile: findPodfilePath(projectPath),
- podspec: findPodspecName(folder),
- projectPath: projectPath,
- projectName: path.basename(projectPath),
- libraryFolder: userConfig.libraryFolder || 'Libraries',
- sharedLibraries: mapSharedLibaries(userConfig.sharedLibraries || []),
- plist: userConfig.plist || [],
- };
-};
-
-exports.dependencyConfig = exports.projectConfig;
-
-exports.linkConfig = require('../../link/ios');

local-cli/core/makeCommand.js

@@ -1,38 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const spawn = require('child_process').spawn;
-
-module.exports = function makeCommand(command) {
- return cb => {
- if (!cb) {
- throw new Error(
- `You missed a callback function for the ${command} command`,
- );
- }
-
- const args = command.split(' ');
- const cmd = args.shift();
-
- const commandProcess = spawn(cmd, args, {
- stdio: 'inherit',
- stdin: 'inherit',
- });
-
- commandProcess.on('close', function prelink(code) {
- if (code) {
- throw new Error(`Error occurred during executing "${command}" command`);
- }
-
- cb();
- });
- };
-};

local-cli/core/wrapCommands.js

@@ -1,20 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const makeCommand = require('./makeCommand');
-
-module.exports = function wrapCommands(commands) {
- const mappedCommands = {};
- Object.keys(commands || []).forEach(k => {
- mappedCommands[k] = makeCommand(commands[k]);
- });
- return mappedCommands;
-};

local-cli/dependencies/dependencies.js

@@ -1,111 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const Metro = require('metro');
-
-const denodeify = require('denodeify');
-const fs = require('fs');
-const path = require('path');
-
-async function dependencies(argv, configPromise, args, packagerInstance) {
- const rootModuleAbsolutePath = args.entryFile;
- const config = await configPromise;
- if (!fs.existsSync(rootModuleAbsolutePath)) {
- return Promise.reject(
- new Error(`File ${rootModuleAbsolutePath} does not exist`),
- );
- }
-
- config.cacheStores = [];
-
- const relativePath = path.relative(
- config.projectRoot,
- rootModuleAbsolutePath,
- );
-
- const options = {
- platform: args.platform,
- entryFile: relativePath,
- dev: args.dev,
- minify: false,
- generateSourceMaps: !args.dev,
- };
-
- const writeToFile = args.output;
- const outStream = writeToFile
- ? fs.createWriteStream(args.output)
- : process.stdout;
-
- const deps = packagerInstance
- ? await packagerInstance.getOrderedDependencyPaths(options)
- : await Metro.getOrderedDependencyPaths(config, options);
-
- deps.forEach(modulePath => {
- // Temporary hack to disable listing dependencies not under this directory.
- // Long term, we need either
- // (a) JS code to not depend on anything outside this directory, or
- // (b) Come up with a way to declare this dependency in Buck.
- const isInsideProjectRoots =
- config.watchFolders.filter(root => modulePath.startsWith(root)).length >
- 0;
-
- if (isInsideProjectRoots) {
- outStream.write(modulePath + '\n');
- }
- });
- return writeToFile
- ? denodeify(outStream.end).bind(outStream)()
- : Promise.resolve();
-}
-
-module.exports = {
- name: 'dependencies',
- description: 'lists dependencies',
- func: dependencies,
- options: [
- {
- command: '--entry-file <path>',
- description: 'Absolute path to the root JS file',
- },
- {
- command: '--output [path]',
- description:
- 'File name where to store the output, ex. /tmp/dependencies.txt',
- },
- {
- command: '--platform [extension]',
- description: 'The platform extension used for selecting modules',
- },
- {
- command: '--transformer [path]',
- description: 'Specify a custom transformer to be used',
- },
- {
- command: '--max-workers [number]',
- description:
- 'Specifies the maximum number of workers the worker-pool ' +
- 'will spawn for transforming files. This defaults to the number of the ' +
- 'cores available on your machine.',
- parse: (workers: string) => Number(workers),
- },
- {
- command: '--dev [boolean]',
- description: 'If false, skip all dev-only code path',
- parse: val => (val === 'false' ? false : true),
- default: true,
- },
- {
- command: '--verbose',
- description: 'Enables logging',
- default: false,
- },
- ],
-};

local-cli/eject/eject.js

@@ -1,111 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const copyProjectTemplateAndReplace = require('../generator/copyProjectTemplateAndReplace');
-const path = require('path');
-const fs = require('fs');
-
-/**
- * The eject command re-creates the `android` and `ios` native folders. Because native code can be
- * difficult to maintain, this new script allows an `app.json` to be defined for the project, which
- * is used to configure the native app.
- *
- * The `app.json` config may contain the following keys:
- *
- * - `name` - The short name used for the project, should be TitleCase
- * - `displayName` - The app's name on the home screen
- */
-
-function eject() {
- const doesIOSExist = fs.existsSync(path.resolve('ios'));
- const doesAndroidExist = fs.existsSync(path.resolve('android'));
- if (doesIOSExist && doesAndroidExist) {
- console.error(
- 'Both the iOS and Android folders already exist! Please delete `ios` and/or `android` ' +
- 'before ejecting.',
- );
- process.exit(1);
- }
-
- let appConfig = null;
- try {
- appConfig = require(path.resolve('app.json'));
- } catch (e) {
- console.error(
- 'Eject requires an `app.json` config file to be located at ' +
- `${path.resolve(
- 'app.json',
- )}, and it must at least specify a \`name\` for the project ` +
- "name, and a `displayName` for the app's home screen label.",
- );
- process.exit(1);
- }
-
- const appName = appConfig.name;
- if (!appName) {
- console.error(
- 'App `name` must be defined in the `app.json` config file to define the project name. ' +
- 'It must not contain any spaces or dashes.',
- );
- process.exit(1);
- }
- const displayName = appConfig.displayName;
- if (!displayName) {
- console.error(
- 'App `displayName` must be defined in the `app.json` config file, to define the label ' +
- 'of the app on the home screen.',
- );
- process.exit(1);
- }
-
- const templateOptions = {displayName};
-
- if (!doesIOSExist) {
- console.log('Generating the iOS folder.');
- copyProjectTemplateAndReplace(
- path.resolve(
- 'node_modules',
- 'react-native',
- 'local-cli',
- 'templates',
- 'HelloWorld',
- 'ios',
- ),
- path.resolve('ios'),
- appName,
- templateOptions,
- );
- }
-
- if (!doesAndroidExist) {
- console.log('Generating the Android folder.');
- copyProjectTemplateAndReplace(
- path.resolve(
- 'node_modules',
- 'react-native',
- 'local-cli',
- 'templates',
- 'HelloWorld',
- 'android',
- ),
- path.resolve('android'),
- appName,
- templateOptions,
- );
- }
-}
-
-module.exports = {
- name: 'eject',
- description: 'Re-create the iOS and Android folders and native code',
- func: eject,
- options: [],
-};

local-cli/generator/copyProjectTemplateAndReplace.js

@@ -1,177 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const chalk = require('chalk');
-const copyAndReplace = require('../util/copyAndReplace');
-const path = require('path');
-const prompt = require('./promptSync')();
-const walk = require('../util/walk');
-
-/**
- * Util for creating a new React Native project.
- * Copy the project from a template and use the correct project name in
- * all files.
- * @param srcPath e.g. '/Users/martin/AwesomeApp/node_modules/react-native/local-cli/templates/HelloWorld'
- * @param destPath e.g. '/Users/martin/AwesomeApp'
- * @param newProjectName e.g. 'AwesomeApp'
- * @param options e.g. {
- * upgrade: true,
- * force: false,
- * displayName: 'Hello World',
- * ignorePaths: ['template/file/to/ignore.md'],
- * }
- */
-function copyProjectTemplateAndReplace(
- srcPath,
- destPath,
- newProjectName,
- options,
-) {
- if (!srcPath) {
- throw new Error('Need a path to copy from');
- }
- if (!destPath) {
- throw new Error('Need a path to copy to');
- }
- if (!newProjectName) {
- throw new Error('Need a project name');
- }
-
- options = options || {};
-
- walk(srcPath).forEach(absoluteSrcFilePath => {
- // 'react-native upgrade'
- if (options.upgrade) {
- // Don't upgrade these files
- const fileName = path.basename(absoluteSrcFilePath);
- // This also includes __tests__/index.*.js
- if (fileName === 'index.ios.js') {
- return;
- }
- if (fileName === 'index.android.js') {
- return;
- }
- if (fileName === 'index.js') {
- return;
- }
- if (fileName === 'App.js') {
- return;
- }
- }
-
- const relativeFilePath = path.relative(srcPath, absoluteSrcFilePath);
- const relativeRenamedPath = dotFilePath(relativeFilePath)
- .replace(/HelloWorld/g, newProjectName)
- .replace(/helloworld/g, newProjectName.toLowerCase());
-
- // Templates may contain files that we don't want to copy.
- // Examples:
- // - Dummy package.json file included in the template only for publishing to npm
- // - Docs specific to the template (.md files)
- if (options.ignorePaths) {
- if (!Array.isArray(options.ignorePaths)) {
- throw new Error('options.ignorePaths must be an array');
- }
- if (
- options.ignorePaths.some(ignorePath => ignorePath === relativeFilePath)
- ) {
- // Skip copying this file
- return;
- }
- }
-
- let contentChangedCallback = null;
- if (options.upgrade && !options.force) {
- contentChangedCallback = (_, contentChanged) => {
- return upgradeFileContentChangedCallback(
- absoluteSrcFilePath,
- relativeRenamedPath,
- contentChanged,
- );
- };
- }
- copyAndReplace(
- absoluteSrcFilePath,
- path.resolve(destPath, relativeRenamedPath),
- {
- 'Hello App Display Name': options.displayName || newProjectName,
- HelloWorld: newProjectName,
- helloworld: newProjectName.toLowerCase(),
- },
- contentChangedCallback,
- );
- });
-}
-
-/**
- * There are various dotfiles in the templates folder in the RN repo. We want
- * these to be ignored by tools when working with React Native itself.
- * Example: _babelrc file is ignored by Babel, renamed to .babelrc inside
- * a real app folder.
- * This is especially important for .gitignore because npm has some special
- * behavior of automatically renaming .gitignore to .npmignore.
- */
-function dotFilePath(path) {
- if (!path) {
- return path;
- }
- return path
- .replace('_gitignore', '.gitignore')
- .replace('_gitattributes', '.gitattributes')
- .replace('_babelrc', '.babelrc')
- .replace('_flowconfig', '.flowconfig')
- .replace('_buckconfig', '.buckconfig')
- .replace('_watchmanconfig', '.watchmanconfig');
-}
-
-function upgradeFileContentChangedCallback(
- absoluteSrcFilePath,
- relativeDestPath,
- contentChanged,
-) {
- if (contentChanged === 'new') {
- console.log(chalk.bold('new') + ' ' + relativeDestPath);
- return 'overwrite';
- } else if (contentChanged === 'changed') {
- console.log(
- chalk.bold(relativeDestPath) +
- ' ' +
- 'has changed in the new version.\nDo you want to keep your ' +
- relativeDestPath +
- ' or replace it with the ' +
- 'latest version?\nIf you ever made any changes ' +
- "to this file, you'll probably want to keep it.\n" +
- 'You can see the new version here: ' +
- absoluteSrcFilePath +
- '\n' +
- 'Do you want to replace ' +
- relativeDestPath +
- '? ' +
- 'Answer y to replace, n to keep your version: ',
- );
- const answer = prompt();
- if (answer === 'y') {
- console.log('Replacing ' + relativeDestPath);
- return 'overwrite';
- } else {
- console.log('Keeping your ' + relativeDestPath);
- return 'keep';
- }
- } else if (contentChanged === 'identical') {
- return 'keep';
- } else {
- throw new Error(
- `Unknown file changed state: ${relativeDestPath}, ${contentChanged}`,
- );
- }
-}
-
-module.exports = copyProjectTemplateAndReplace;

local-cli/generator/printRunInstructions.js

@@ -1,39 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-var chalk = require('chalk');
-var path = require('path');
-
-function printRunInstructions(projectDir, projectName) {
- const absoluteProjectDir = path.resolve(projectDir);
- // iOS
- const xcodeProjectPath =
- path.resolve(projectDir, 'ios', projectName) + '.xcodeproj';
- const relativeXcodeProjectPath = path.relative(
- process.cwd(),
- xcodeProjectPath,
- );
- console.log(chalk.white.bold('To run your app on iOS:'));
- console.log(' cd ' + absoluteProjectDir);
- console.log(' react-native run-ios');
- console.log(' - or -');
- console.log(' Open ' + relativeXcodeProjectPath + ' in Xcode');
- console.log(' Hit the Run button');
- // Android
- console.log(chalk.white.bold('To run your app on Android:'));
- console.log(' cd ' + absoluteProjectDir);
- console.log(
- ' Have an Android emulator running (quickest way to get started), or a device connected',
- );
- console.log(' react-native run-android');
-}
-
-module.exports = printRunInstructions;

local-cli/generator/promptSync.js

@@ -1,143 +0,0 @@
-/** @format */
-
-// Simplified version of:
-// https://github.com/0x00A/prompt-sync/blob/master/index.js
-
-'use strict';
-
-var fs = require('fs');
-var term = 13; // carriage return
-
-function create() {
- return prompt;
-
- function prompt(ask, value, opts) {
- var insert = 0,
- savedinsert = 0,
- res,
- i,
- savedstr;
- opts = opts || {};
-
- if (Object(ask) === ask) {
- opts = ask;
- ask = opts.ask;
- } else if (Object(value) === value) {
- opts = value;
- value = opts.value;
- }
- ask = ask || '';
- var echo = opts.echo;
- var masked = 'echo' in opts;
-
- var fd =
- process.platform === 'win32'
- ? process.stdin.fd
- : fs.openSync('/dev/tty', 'rs');
-
- var wasRaw = process.stdin.isRaw;
- if (!wasRaw) {
- process.stdin.setRawMode(true);
- }
-
- var buf = new Buffer(3);
- var str = '',
- character,
- read;
-
- savedstr = '';
-
- if (ask) {
- process.stdout.write(ask);
- }
-
- var cycle = 0;
- var prevComplete;
-
- while (true) {
- read = fs.readSync(fd, buf, 0, 3);
- if (read > 1) {
- // received a control sequence
- if (buf.toString()) {
- str = str + buf.toString();
- str = str.replace(/\0/g, '');
- insert = str.length;
- process.stdout.write('\u001b[2K\u001b[0G' + ask + str);
- process.stdout.write('\u001b[' + (insert + ask.length + 1) + 'G');
- buf = new Buffer(3);
- }
- continue; // any other 3 character sequence is ignored
- }
-
- // if it is not a control character seq, assume only one character is read
- character = buf[read - 1];
-
- // catch a ^C and return null
- if (character == 3) {
- process.stdout.write('^C\n');
- fs.closeSync(fd);
- process.exit(130);
- process.stdin.setRawMode(wasRaw);
- return null;
- }
-
- // catch the terminating character
- if (character == term) {
- fs.closeSync(fd);
- break;
- }
-
- if (character == 127 || (process.platform == 'win32' && character == 8)) {
- //backspace
- if (!insert) {
- continue;
- }
- str = str.slice(0, insert - 1) + str.slice(insert);
- insert--;
- process.stdout.write('\u001b[2D');
- } else {
- if (character < 32 || character > 126) {
- continue;
- }
- str =
- str.slice(0, insert) +
- String.fromCharCode(character) +
- str.slice(insert);
- insert++;
- }
-
- if (masked) {
- process.stdout.write(
- '\u001b[2K\u001b[0G' + ask + Array(str.length + 1).join(echo),
- );
- } else {
- process.stdout.write('\u001b[s');
- if (insert == str.length) {
- process.stdout.write('\u001b[2K\u001b[0G' + ask + str);
- } else {
- if (ask) {
- process.stdout.write('\u001b[2K\u001b[0G' + ask + str);
- } else {
- process.stdout.write(
- '\u001b[2K\u001b[0G' +
- str +
- '\u001b[' +
- (str.length - insert) +
- 'D',
- );
- }
- }
- process.stdout.write('\u001b[u');
- process.stdout.write('\u001b[1C');
- }
- }
-
- process.stdout.write('\n');
-
- process.stdin.setRawMode(wasRaw);
-
- return str || value || '';
- }
-}
-
-module.exports = create;

local-cli/generator/templates.js

@@ -1,269 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const copyProjectTemplateAndReplace = require('./copyProjectTemplateAndReplace');
-const execSync = require('child_process').execSync;
-const fs = require('fs');
-const path = require('path');
-
-/**
- * Templates released as part of react-native in local-cli/templates.
- */
-const builtInTemplates = {
- navigation: 'HelloNavigation',
-};
-
-function listTemplatesAndExit(newProjectName, options) {
- if (options.template === true) {
- // Just listing templates using 'react-native init --template'.
- // Not creating a new app.
- // Print available templates and exit.
- const templateKeys = Object.keys(builtInTemplates);
- if (templateKeys.length === 0) {
- // Just a guard, should never happen as long builtInTemplates
- // above is defined correctly :)
- console.log(
- 'There are no templates available besides ' +
- 'the default "Hello World" one.',
- );
- } else {
- console.log(
- 'The available templates are:\n' +
- templateKeys.join('\n') +
- '\nYou can use these to create an app based on a template, for example: ' +
- 'you could run: ' +
- 'react-native init ' +
- newProjectName +
- ' --template ' +
- templateKeys[0],
- );
- }
- // Exit 'react-native init'
- return true;
- }
- // Continue 'react-native init'
- return false;
-}
-
-/**
- * @param destPath Create the new project at this path.
- * @param newProjectName For example 'AwesomeApp'.
- * @param template Template to use, for example 'navigation'.
- * @param yarnVersion Version of yarn available on the system, or null if
- * yarn is not available. For example '0.18.1'.
- */
-function createProjectFromTemplate(
- destPath,
- newProjectName,
- template,
- yarnVersion,
-) {
- // Expand the basic 'HelloWorld' template
- copyProjectTemplateAndReplace(
- path.resolve(
- 'node_modules',
- 'react-native',
- 'local-cli',
- 'templates',
- 'HelloWorld',
- ),
- destPath,
- newProjectName,
- );
-
- if (template === undefined) {
- // No specific template, use just the HelloWorld template above
- return;
- }
-
- // Keep the files from the 'HelloWorld' template, and overwrite some of them
- // with the specified project template.
- // The 'HelloWorld' template contains the native files (these are used by
- // all templates) and every other template only contains additional JS code.
- // Reason:
- // This way we don't have to duplicate the native files in every template.
- // If we duplicated them we'd make RN larger and risk that people would
- // forget to maintain all the copies so they would go out of sync.
- const builtInTemplateName = builtInTemplates[template];
- if (builtInTemplateName) {
- // template is e.g. 'navigation',
- // use the built-in local-cli/templates/HelloNavigation folder
- createFromBuiltInTemplate(
- builtInTemplateName,
- destPath,
- newProjectName,
- yarnVersion,
- );
- } else {
- // template is e.g. 'ignite',
- // use the template react-native-template-ignite from npm
- createFromRemoteTemplate(template, destPath, newProjectName, yarnVersion);
- }
-}
-
-// (We might want to get rid of built-in templates in the future -
-// publish them to npm and install from there.)
-function createFromBuiltInTemplate(
- templateName,
- destPath,
- newProjectName,
- yarnVersion,
-) {
- const templatePath = path.resolve(
- 'node_modules',
- 'react-native',
- 'local-cli',
- 'templates',
- templateName,
- );
- copyProjectTemplateAndReplace(templatePath, destPath, newProjectName);
- installTemplateDependencies(templatePath, yarnVersion);
- installTemplateDevDependencies(templatePath, yarnVersion);
-}
-
-/**
- * The following formats are supported for the template:
- * - 'demo' -> Fetch the package react-native-template-demo from npm
- * - git://..., http://..., file://... or any other URL supported by npm
- */
-function createFromRemoteTemplate(
- template,
- destPath,
- newProjectName,
- yarnVersion,
-) {
- let installPackage;
- let templateName;
- if (template.includes('://')) {
- // URL, e.g. git://, file://
- installPackage = template;
- templateName = template.substr(template.lastIndexOf('/') + 1);
- } else {
- // e.g 'demo'
- installPackage = 'react-native-template-' + template;
- templateName = installPackage;
- }
-
- // Check if the template exists
- console.log(`Fetching template ${installPackage}...`);
- try {
- if (yarnVersion) {
- execSync(`yarn add ${installPackage} --ignore-scripts`, {
- stdio: 'inherit',
- });
- } else {
- execSync(
- `npm install ${installPackage} --save --save-exact --ignore-scripts`,
- {stdio: 'inherit'},
- );
- }
- const templatePath = path.resolve('node_modules', templateName);
- copyProjectTemplateAndReplace(templatePath, destPath, newProjectName, {
- // Every template contains a dummy package.json file included
- // only for publishing the template to npm.
- // We want to ignore this dummy file, otherwise it would overwrite
- // our project's package.json file.
- ignorePaths: ['package.json', 'dependencies.json','devDependencies.json'],
- });
- installTemplateDependencies(templatePath, yarnVersion);
- installTemplateDevDependencies(templatePath, yarnVersion);
- } finally {
- // Clean up the temp files
- try {
- if (yarnVersion) {
- execSync(`yarn remove ${templateName} --ignore-scripts`);
- } else {
- execSync(`npm uninstall ${templateName} --ignore-scripts`);
- }
- } catch (err) {
- // Not critical but we still want people to know and report
- // if this the clean up fails.
- console.warn(
- `Failed to clean up template temp files in node_modules/${templateName}. ` +
- 'This is not a critical error, you can work on your app.',
- );
- }
- }
-}
-
-function installTemplateDependencies(templatePath, yarnVersion) {
- // dependencies.json is a special file that lists additional dependencies
- // that are required by this template
- const dependenciesJsonPath = path.resolve(templatePath, 'dependencies.json');
- console.log('Adding dependencies for the project...');
- if (!fs.existsSync(dependenciesJsonPath)) {
- console.log('No additional dependencies.');
- return;
- }
-
- let dependencies;
- try {
- dependencies = JSON.parse(fs.readFileSync(dependenciesJsonPath));
- } catch (err) {
- throw new Error(
- "Could not parse the template's dependencies.json: " + err.message,
- );
- }
- for (let depName in dependencies) {
- const depVersion = dependencies[depName];
- const depToInstall = depName + '@' + depVersion;
- console.log('Adding ' + depToInstall + '...');
- if (yarnVersion) {
- execSync(`yarn add ${depToInstall}`, {stdio: 'inherit'});
- } else {
- execSync(`npm install ${depToInstall} --save --save-exact`, {
- stdio: 'inherit',
- });
- }
- }
- console.log("Linking native dependencies into the project's build files...");
- execSync('react-native link', {stdio: 'inherit'});
-}
-
-function installTemplateDevDependencies(templatePath, yarnVersion) {
- // devDependencies.json is a special file that lists additional develop dependencies
- // that are required by this template
- const devDependenciesJsonPath = path.resolve(
- templatePath,
- 'devDependencies.json',
- );
- console.log('Adding develop dependencies for the project...');
- if (!fs.existsSync(devDependenciesJsonPath)) {
- console.log('No additional develop dependencies.');
- return;
- }
-
- let dependencies;
- try {
- dependencies = JSON.parse(fs.readFileSync(devDependenciesJsonPath));
- } catch (err) {
- throw new Error(
- "Could not parse the template's devDependencies.json: " + err.message,
- );
- }
- for (let depName in dependencies) {
- const depVersion = dependencies[depName];
- const depToInstall = depName + '@' + depVersion;
- console.log('Adding ' + depToInstall + '...');
- if (yarnVersion) {
- execSync(`yarn add ${depToInstall} -D`, {stdio: 'inherit'});
- } else {
- execSync(`npm install ${depToInstall} --save-dev --save-exact`, {
- stdio: 'inherit',
- });
- }
- }
-}
-
-module.exports = {
- listTemplatesAndExit,
- createProjectFromTemplate,
-};

local-cli/info/info.js

@@ -1,85 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const envinfo = require('envinfo');
-
-const info = function() {
- const args = Array.prototype.slice.call(arguments)[2];
-
- try {
- envinfo
- .run(
- {
- System: ['OS', 'CPU', 'Memory', 'Shell'],
- Binaries: ['Node', 'Yarn', 'npm', 'Watchman'],
- IDEs: ['Xcode', 'Android Studio'],
- SDKs: ['iOS SDK', 'Android SDK'],
- npmPackages:
- (typeof args.packages === 'string' &&
- !args.packages.includes('*')) ||
- !args.packages
- ? ['react', 'react-native'].concat(
- (args.packages || '').split(','),
- )
- : args.packages,
- npmGlobalPackages: '*react-native*',
- },
- {
- clipboard: !!args.clipboard,
- title: 'React Native Environment Info',
- },
- )
- .then(console.log)
- .catch(err => {
- console.log('Error: unable to print environment info');
- console.log(err);
- });
- } catch (err) {
- console.log('Error: unable to print environment info');
- console.log(err);
- }
-};
-
-module.exports = {
- name: 'info',
- description: 'Get relevant version info about OS, toolchain and libraries',
- options: [
- {
- command: '--packages [string]',
- description:
- 'Which packages from your package.json to include, in addition to the default React Native and React versions.',
- },
- {
- command: '--clipboard [boolean]',
- description:
- 'Automagically copy the environment report output to the clipboard',
- },
- ],
- examples: [
- {
- desc: 'Get standard version info',
- cmd: 'react-native info',
- },
- {
- desc: 'Get standard version info & specified package versions',
- cmd: 'react-native info --packages jest,eslint',
- },
- {
- desc: 'Get standard version info & globbed package versions',
- cmd: 'react-native info --packages "*react*"',
- },
- {
- desc: 'Get standard version info & all package versions',
- cmd: 'react-native info --packages',
- },
- ],
- func: info,
-};

local-cli/init/init.js

@@ -1,131 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const {
- listTemplatesAndExit,
- createProjectFromTemplate,
-} = require('../generator/templates');
-const execSync = require('child_process').execSync;
-const fs = require('fs');
-const minimist = require('minimist');
-const path = require('path');
-const printRunInstructions = require('../generator/printRunInstructions');
-const process = require('process');
-const yarn = require('../util/yarn');
-
-/**
- * Creates the template for a React Native project given the provided
- * parameters:
- * @param projectDir Templates will be copied here.
- * @param argsOrName Project name or full list of custom arguments
- * for the generator.
- * @param options Command line options passed from the react-native-cli directly.
- * E.g. `{ version: '0.43.0', template: 'navigation' }`
- */
-function init(projectDir, argsOrName) {
- const args = Array.isArray(argsOrName)
- ? argsOrName // argsOrName was e.g. ['AwesomeApp', '--verbose']
- : [argsOrName].concat(process.argv.slice(4)); // argsOrName was e.g. 'AwesomeApp'
-
- // args array is e.g. ['AwesomeApp', '--verbose', '--template', 'navigation']
- if (!args || args.length === 0) {
- console.error('react-native init requires a project name.');
- return;
- }
-
- const newProjectName = args[0];
- const options = minimist(args);
-
- if (listTemplatesAndExit(newProjectName, options)) {
- // Just listing templates using 'react-native init --template'
- // Not creating a new app.
- return;
- } else {
- console.log('Setting up new React Native app in ' + projectDir);
- generateProject(projectDir, newProjectName, options);
- }
-}
-
-/**
- * Generates a new React Native project based on the template.
- * @param Absolute path at which the project folder should be created.
- * @param options Command line arguments parsed by minimist.
- */
-function generateProject(destinationRoot, newProjectName, options) {
- var reactNativePackageJson = require('../../package.json');
- var {peerDependencies} = reactNativePackageJson;
- if (!peerDependencies) {
- console.error(
- "Missing React peer dependency in React Native's package.json. Aborting.",
- );
- return;
- }
-
- var reactVersion = peerDependencies.react;
- if (!reactVersion) {
- console.error(
- "Missing React peer dependency in React Native's package.json. Aborting.",
- );
- return;
- }
-
- const yarnVersion =
- !options.npm &&
- yarn.getYarnVersionIfAvailable() &&
- yarn.isGlobalCliUsingYarn(destinationRoot);
-
- createProjectFromTemplate(
- destinationRoot,
- newProjectName,
- options.template,
- yarnVersion,
- );
-
- if (yarnVersion) {
- console.log('Adding React...');
- execSync(`yarn add react@${reactVersion}`, {stdio: 'inherit'});
- } else {
- console.log('Installing React...');
- execSync(`npm install react@${reactVersion} --save --save-exact`, {
- stdio: 'inherit',
- });
- }
- if (!options['skip-jest']) {
- const jestDeps = `jest babel-jest metro-react-native-babel-preset react-test-renderer@${reactVersion}`;
- if (yarnVersion) {
- console.log('Adding Jest...');
- execSync(`yarn add ${jestDeps} --dev --exact`, {stdio: 'inherit'});
- } else {
- console.log('Installing Jest...');
- execSync(`npm install ${jestDeps} --save-dev --save-exact`, {
- stdio: 'inherit',
- });
- }
- addJestToPackageJson(destinationRoot);
- }
- printRunInstructions(destinationRoot, newProjectName);
-}
-
-/**
- * Add Jest-related stuff to package.json, which was created by the react-native-cli.
- */
-function addJestToPackageJson(destinationRoot) {
- var packageJSONPath = path.join(destinationRoot, 'package.json');
- var packageJSON = JSON.parse(fs.readFileSync(packageJSONPath));
-
- packageJSON.scripts.test = 'jest';
- packageJSON.jest = {
- preset: 'react-native',
- };
- fs.writeFileSync(packageJSONPath, JSON.stringify(packageJSON, null, 2));
-}
-
-module.exports = init;

local-cli/install/install.js

@@ -1,44 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const spawnSync = require('child_process').spawnSync;
-const log = require('npmlog');
-const PackageManager = require('../util/PackageManager');
-const spawnOpts = {
- stdio: 'inherit',
- stdin: 'inherit',
-};
-
-log.heading = 'rnpm-install';
-
-function install(args, config) {
- const name = args[0];
-
- let res = PackageManager.add(name);
-
- if (res.status) {
- process.exit(res.status);
- }
-
- res = spawnSync('react-native', ['link', name], spawnOpts);
-
- if (res.status) {
- process.exit(res.status);
- }
-
- log.info(`Module ${name} has been successfully installed & linked`);
-}
-
-module.exports = {
- func: install,
- description: 'install and link native dependencies',
- name: 'install <packageName>',
-};

local-cli/install/uninstall.js

@@ -1,44 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const spawnSync = require('child_process').spawnSync;
-const log = require('npmlog');
-const PackageManager = require('../util/PackageManager');
-const spawnOpts = {
- stdio: 'inherit',
- stdin: 'inherit',
-};
-
-log.heading = 'rnpm-install';
-
-function uninstall(args, config) {
- const name = args[0];
-
- var res = spawnSync('react-native', ['unlink', name], spawnOpts);
-
- if (res.status) {
- process.exit(res.status);
- }
-
- res = PackageManager.remove(name);
-
- if (res.status) {
- process.exit(res.status);
- }
-
- log.info(`Module ${name} has been successfully uninstalled & unlinked`);
-}
-
-module.exports = {
- func: uninstall,
- description: 'uninstall and unlink native dependencies',
- name: 'uninstall <packageName>',
-};

local-cli/library/library.js

@@ -1,87 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const copyAndReplace = require('../util/copyAndReplace');
-const fs = require('fs');
-const isValidPackageName = require('../util/isValidPackageName');
-const path = require('path');
-const walk = require('../util/walk');
-
-/**
- * Creates a new native library with the given name
- */
-function library(argv, config, args) {
- if (!isValidPackageName(args.name)) {
- return Promise.reject(
- args.name +
- ' is not a valid name for a project. Please use a valid ' +
- 'identifier name (alphanumeric).',
- );
- }
-
- const root = process.cwd();
- const libraries = path.resolve(root, 'Libraries');
- const libraryDest = path.resolve(libraries, args.name);
- const source = path.resolve(
- 'node_modules',
- 'react-native',
- 'Libraries',
- 'Sample',
- );
-
- if (!fs.existsSync(libraries)) {
- fs.mkdirSync(libraries);
- }
-
- if (fs.existsSync(libraryDest)) {
- return Promise.reject(
- new Error(`Library already exists in ${libraryDest}`),
- );
- }
-
- walk(source).forEach(f => {
- if (
- f.indexOf('project.xcworkspace') !== -1 ||
- f.indexOf('.xcodeproj/xcuserdata') !== -1
- ) {
- return;
- }
-
- const dest = path.relative(
- source,
- f.replace(/Sample/g, args.name).replace(/^_/, '.'),
- );
- copyAndReplace(path.resolve(source, f), path.resolve(libraryDest, dest), {
- Sample: args.name,
- });
- });
-
- console.log('Created library in', libraryDest);
- console.log('Next Steps:');
- console.log(' Link your library in Xcode:');
- console.log(
- ' https://facebook.github.io/react-native/docs/' +
- 'linking-libraries-ios.html#content\n',
- );
-}
-
-module.exports = {
- name: 'new-library',
- func: library,
- description: 'generates a native library bridge',
- options: [
- {
- command: '--name <string>',
- description: 'name of the library to generate',
- default: null,
- },
- ],
-};
@@ -1,29 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const fs = require('fs-extra');
-const path = require('path');
-const groupFilesByType = require('../groupFilesByType');
-
-/**
- * Copies each file from an array of assets provided to targetPath directory
- *
- * For now, the only types of files that are handled are:
- * - Fonts (otf, ttf) - copied to targetPath/fonts under original name
- */
-module.exports = function copyAssetsAndroid(files, project) {
- const assets = groupFilesByType(files);
-
- (assets.font || []).forEach(asset =>
- fs.copySync(
- asset,
- path.join(project.assetsPath, 'fonts', path.basename(asset)),
- ),
- );
-};
@@ -1,17 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const fs = require('fs-extra');
-
-exports.readFile = file => () => fs.readFileSync(file, 'utf8');
-
-exports.writeFile = (file, content) =>
- content
- ? fs.writeFileSync(file, content, 'utf8')
- : c => fs.writeFileSync(file, c, 'utf8');
@@ -1,11 +0,0 @@
-/** @format */
-
-module.exports = function() {
- return {
- isInstalled: require('./isInstalled'),
- register: require('./registerNativeModule'),
- unregister: require('./unregisterNativeModule'),
- copyAssets: require('./copyAssets'),
- unlinkAssets: require('./unlinkAssets'),
- };
-};
@@ -1,16 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const fs = require('fs');
-const makeBuildPatch = require('./patches/makeBuildPatch');
-
-module.exports = function isInstalled(config, name) {
- const buildGradle = fs.readFileSync(config.buildGradlePath);
- return makeBuildPatch(name).installPattern.test(buildGradle);
-};
@@ -1,18 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const toCamelCase = require('lodash').camelCase;
-
-module.exports = function applyParams(str, params, prefix) {
- return str.replace(/\$\{(\w+)\}/g, (pattern, param) => {
- const name = toCamelCase(prefix) + '_' + param;
-
- return params[param] ? `getResources().getString(R.string.${name})` : null;
- });
-};
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const fs = require('fs');
-
-module.exports = function applyPatch(file, patch) {
- fs.writeFileSync(
- file,
- fs
- .readFileSync(file, 'utf8')
- .replace(patch.pattern, match => `${match}${patch.patch}`),
- );
-};
@@ -1,23 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const normalizeProjectName = require('./normalizeProjectName');
-
-module.exports = function makeBuildPatch(name) {
- const normalizedProjectName = normalizeProjectName(name);
- const installPattern = new RegExp(
- `\\s{4}(compile)(\\(|\\s)(project)\\(\\\':${normalizedProjectName}\\\'\\)(\\)|\\s)`,
- );
-
- return {
- installPattern,
- pattern: /[^ \t]dependencies {(\r\n|\n)/,
- patch: ` compile project(':${normalizedProjectName}')\n`,
- };
-};
@@ -1,15 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-module.exports = function makeImportPatch(packageImportPath) {
- return {
- pattern: 'import com.facebook.react.ReactApplication;',
- patch: '\n' + packageImportPath,
- };
-};
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const applyParams = require('./applyParams');
-
-module.exports = function makePackagePatch(packageInstance, params, prefix) {
- const processedInstance = applyParams(packageInstance, params, prefix);
-
- return {
- pattern: 'new MainReactPackage()',
- patch: ',\n ' + processedInstance,
- };
-};
@@ -1,43 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const path = require('path');
-const normalizeProjectName = require('./normalizeProjectName');
-
-const isWin = process.platform === 'win32';
-
-module.exports = function makeSettingsPatch(
- name,
- androidConfig,
- projectConfig,
-) {
- var projectDir = path.relative(
- path.dirname(projectConfig.settingsGradlePath),
- androidConfig.sourceDir,
- );
- const normalizedProjectName = normalizeProjectName(name);
-
- /*
- * Fix for Windows
- * Backslashes is the escape character and will result in
- * an invalid path in settings.gradle
- * https://github.com/rnpm/rnpm/issues/113
- */
- if (isWin) {
- projectDir = projectDir.replace(/\\/g, '/');
- }
-
- return {
- pattern: '\n',
- patch:
- `include ':${normalizedProjectName}'\n` +
- `project(':${normalizedProjectName}').projectDir = ` +
- `new File(rootProject.projectDir, '${projectDir}')\n`,
- };
-};
@@ -1,27 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const toCamelCase = require('lodash').camelCase;
-
-module.exports = function makeStringsPatch(params, prefix) {
- const values = Object.keys(params).map(param => {
- const name = toCamelCase(prefix) + '_' + param;
- return (
- ' ' +
- `<string moduleConfig="true" name="${name}">${params[param]}</string>`
- );
- });
-
- const patch = values.length > 0 ? values.join('\n') + '\n' : '';
-
- return {
- pattern: '<resources>\n',
- patch,
- };
-};
@@ -1,5 +0,0 @@
-/** @format */
-
-module.exports = function normalizeProjectName(name) {
- return name.replace(/\//g, '_');
-};
@@ -1,17 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const fs = require('fs');
-
-module.exports = function revokePatch(file, patch) {
- fs.writeFileSync(
- file,
- fs.readFileSync(file, 'utf8').replace(patch.patch, ''),
- );
-};
@@ -1,42 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const applyPatch = require('./patches/applyPatch');
-const makeStringsPatch = require('./patches/makeStringsPatch');
-const makeSettingsPatch = require('./patches/makeSettingsPatch');
-const makeBuildPatch = require('./patches/makeBuildPatch');
-const makeImportPatch = require('./patches/makeImportPatch');
-const makePackagePatch = require('./patches/makePackagePatch');
-
-module.exports = function registerNativeAndroidModule(
- name,
- androidConfig,
- params,
- projectConfig,
-) {
- const buildPatch = makeBuildPatch(name);
-
- applyPatch(
- projectConfig.settingsGradlePath,
- makeSettingsPatch(name, androidConfig, projectConfig),
- );
-
- applyPatch(projectConfig.buildGradlePath, buildPatch);
- applyPatch(projectConfig.stringsPath, makeStringsPatch(params, name));
-
- applyPatch(
- projectConfig.mainFilePath,
- makePackagePatch(androidConfig.packageInstance, params, name),
- );
-
- applyPatch(
- projectConfig.mainFilePath,
- makeImportPatch(androidConfig.packageImportPath),
- );
-};
@@ -1,33 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const fs = require('fs-extra');
-const path = require('path');
-const groupFilesByType = require('../groupFilesByType');
-
-/**
- * Copies each file from an array of assets provided to targetPath directory
- *
- * For now, the only types of files that are handled are:
- * - Fonts (otf, ttf) - copied to targetPath/fonts under original name
- */
-module.exports = function unlinkAssetsAndroid(files, project) {
- const assets = groupFilesByType(files);
-
- (assets.font || []).forEach(file => {
- const filePath = path.join(
- project.assetsPath,
- 'fonts',
- path.basename(file),
- );
- if (fs.existsSync(filePath)) {
- fs.unlinkSync(filePath);
- }
- });
-};
@@ -1,53 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const fs = require('fs');
-const toCamelCase = require('lodash').camelCase;
-
-const revokePatch = require('./patches/revokePatch');
-const makeSettingsPatch = require('./patches/makeSettingsPatch');
-const makeBuildPatch = require('./patches/makeBuildPatch');
-const makeStringsPatch = require('./patches/makeStringsPatch');
-const makeImportPatch = require('./patches/makeImportPatch');
-const makePackagePatch = require('./patches/makePackagePatch');
-
-module.exports = function unregisterNativeAndroidModule(
- name,
- androidConfig,
- projectConfig,
-) {
- const buildPatch = makeBuildPatch(name);
- const strings = fs.readFileSync(projectConfig.stringsPath, 'utf8');
- var params = {};
-
- strings.replace(
- /moduleConfig="true" name="(\w+)">(.*)</g,
- (_, param, value) => {
- params[param.slice(toCamelCase(name).length + 1)] = value;
- },
- );
-
- revokePatch(
- projectConfig.settingsGradlePath,
- makeSettingsPatch(name, androidConfig, projectConfig),
- );
-
- revokePatch(projectConfig.buildGradlePath, buildPatch);
- revokePatch(projectConfig.stringsPath, makeStringsPatch(params, name));
-
- revokePatch(
- projectConfig.mainFilePath,
- makePackagePatch(androidConfig.packageInstance, params, name),
- );
-
- revokePatch(
- projectConfig.mainFilePath,
- makeImportPatch(androidConfig.packageImportPath),
- );
-};
@@ -1,10 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-module.exports = cb => cb();
@@ -1,26 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-/**
- * Given an array of dependencies - it returns their RNPM config
- * if they were valid.
- */
-module.exports = function getDependencyConfig(config, deps) {
- return deps.reduce((acc, name) => {
- try {
- return acc.concat({
- config: config.getDependencyConfig(name),
- name,
- });
- } catch (err) {
- console.log(err);
- return acc;
- }
- }, []);
-};
@@ -1,20 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const path = require('path');
-
-/**
- * Returns an array of dependencies that should be linked/checked.
- */
-module.exports = function getProjectDependencies(cwd) {
- const pjson = require(path.join(cwd || process.cwd(), './package.json'));
- return Object.keys(pjson.dependencies || {}).filter(
- name => name !== 'react-native',
- );
-};
@@ -1,36 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const groupBy = require('lodash').groupBy;
-const mime = require('mime');
-
-/**
- * Since there are no officially registered MIME types
- * for ttf/otf yet http://www.iana.org/assignments/media-types/media-types.xhtml,
- * we define two non-standard ones for the sake of parsing
- */
-mime.define({
- 'font/opentype': ['otf'],
- 'font/truetype': ['ttf'],
-});
-
-/**
- * Given an array of files, it groups it by it's type.
- * Type of the file is inferred from it's mimetype based on the extension
- * file ends up with. The returned value is an object with properties that
- * correspond to the first part of the mimetype, e.g. images will be grouped
- * under `image` key since the mimetype for them is `image/jpg` etc.
- *
- * Example:
- * Given an array ['fonts/a.ttf', 'images/b.jpg'],
- * the returned object will be: {font: ['fonts/a.ttf'], image: ['images/b.jpg']}
- */
-module.exports = function groupFilesByType(assets) {
- return groupBy(assets, type => mime.lookup(type).split('/')[0]);
-};
@@ -1,23 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const PbxFile = require('xcode/lib/pbxFile');
-
-/**
- * Given xcodeproj and filePath, it creates new file
- * from path provided, adds it to the project
- * and returns newly created instance of a file
- */
-module.exports = function addFileToProject(project, filePath) {
- const file = new PbxFile(filePath);
- file.uuid = project.generateUuid();
- file.fileRef = project.generateUuid();
- project.addToPbxFileReferenceSection(file);
- return file;
-};
@@ -1,22 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-/**
- * Given an array of xcodeproj libraries and pbxFile,
- * it appends it to that group
- *
- * Important: That function mutates `libraries` and it's not pure.
- * It's mainly due to limitations of `xcode` library.
- */
-module.exports = function addProjectToLibraries(libraries, file) {
- return libraries.children.push({
- value: file.fileRef,
- comment: file.basename,
- });
-};
@@ -1,25 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const createGroupWithMessage = require('./createGroupWithMessage');
-
-module.exports = function addSharedLibraries(project, libraries) {
- if (!libraries.length) {
- return;
- }
-
- // Create a Frameworks group if necessary.
- createGroupWithMessage(project, 'Frameworks');
-
- const target = project.getFirstTarget().uuid;
-
- for (var name of libraries) {
- project.addFramework(name, {target});
- }
-};
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const mapHeaderSearchPaths = require('./mapHeaderSearchPaths');
-
-module.exports = function addToHeaderSearchPaths(project, path) {
- mapHeaderSearchPaths(project, searchPaths => searchPaths.concat(path));
-};
@@ -1,11 +0,0 @@
-/** @format */
-
-const isInstalledIOS = require('../isInstalled');
-const isInstalledPods = require('../../pods/isInstalled');
-
-module.exports = function isInstalled(projectConfig, name, dependencyConfig) {
- return (
- isInstalledIOS(projectConfig, dependencyConfig) ||
- isInstalledPods(projectConfig, dependencyConfig)
- );
-};
@@ -1,17 +0,0 @@
-/** @format */
-
-const registerDependencyIOS = require('../registerNativeModule');
-const registerDependencyPods = require('../../pods/registerNativeModule');
-
-module.exports = function registerNativeModule(
- name,
- dependencyConfig,
- params,
- projectConfig,
-) {
- if (projectConfig.podfile && dependencyConfig.podspec) {
- registerDependencyPods(name, dependencyConfig, projectConfig);
- } else {
- registerDependencyIOS(dependencyConfig, projectConfig);
- }
-};
@@ -1,23 +0,0 @@
-/** @format */
-
-const compact = require('lodash').compact;
-const isInstalledIOS = require('../isInstalled');
-const isInstalledPods = require('../../pods/isInstalled');
-const unregisterDependencyIOS = require('../unregisterNativeModule');
-const unregisterDependencyPods = require('../../pods/unregisterNativeModule');
-
-module.exports = function unregisterNativeModule(
- name,
- dependencyConfig,
- projectConfig,
- otherDependencies,
-) {
- const isIosInstalled = isInstalledIOS(projectConfig, dependencyConfig);
- const isPodInstalled = isInstalledPods(projectConfig, dependencyConfig);
- if (isIosInstalled) {
- const iOSDependencies = compact(otherDependencies.map(d => d.config.ios));
- unregisterDependencyIOS(dependencyConfig, projectConfig, iOSDependencies);
- } else if (isPodInstalled) {
- unregisterDependencyPods(dependencyConfig, projectConfig);
- }
-};
@@ -1,52 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const fs = require('fs-extra');
-const path = require('path');
-const xcode = require('xcode');
-const log = require('npmlog');
-const groupFilesByType = require('../groupFilesByType');
-const createGroupWithMessage = require('./createGroupWithMessage');
-const getPlist = require('./getPlist');
-const writePlist = require('./writePlist');
-
-/**
- * This function works in a similar manner to its Android version,
- * except it does not copy fonts but creates Xcode Group references
- */
-module.exports = function linkAssetsIOS(files, projectConfig) {
- const project = xcode.project(projectConfig.pbxprojPath).parseSync();
- const assets = groupFilesByType(files);
- const plist = getPlist(project, projectConfig.sourceDir);
-
- createGroupWithMessage(project, 'Resources');
-
- function addResourceFile(f) {
- return (f || [])
- .map(asset =>
- project.addResourceFile(path.relative(projectConfig.sourceDir, asset), {
- target: project.getFirstTarget().uuid,
- }),
- )
- .filter(file => file) // xcode returns false if file is already there
- .map(file => file.basename);
- }
-
- addResourceFile(assets.image);
-
- const fonts = addResourceFile(assets.font);
-
- const existingFonts = plist.UIAppFonts || [];
- const allFonts = [...existingFonts, ...fonts];
- plist.UIAppFonts = Array.from(new Set(allFonts)); // use Set to dedupe w/existing
-
- fs.writeFileSync(projectConfig.pbxprojPath, project.writeSync());
-
- writePlist(project, projectConfig.sourceDir, plist);
-};
@@ -1,34 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const getGroup = require('./getGroup');
-
-const hasGroup = (pbxGroup, name) =>
- pbxGroup.children.find(group => group.comment === name);
-
-/**
- * Given project and path of the group, it deeply creates a given group
- * making all outer groups if necessary
- *
- * Returns newly created group
- */
-module.exports = function createGroup(project, path) {
- return path.split('/').reduce((group, name) => {
- if (!hasGroup(group, name)) {
- const uuid = project.pbxCreateGroup(name, '""');
-
- group.children.push({
- value: uuid,
- comment: name,
- });
- }
-
- return project.pbxGroupByName(name);
- }, getGroup(project));
-};
@@ -1,34 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const log = require('npmlog');
-
-const createGroup = require('./createGroup');
-const getGroup = require('./getGroup');
-
-/**
- * Given project and path of the group, it checks if a group exists at that path,
- * and deeply creates a group for that path if its does not already exist.
- *
- * Returns the existing or newly created group
- */
-module.exports = function createGroupWithMessage(project, path) {
- var group = getGroup(project, path);
-
- if (!group) {
- group = createGroup(project, path);
-
- log.warn(
- 'ERRGROUP',
- `Group '${path}' does not exist in your Xcode project. We have created it automatically for you.`,
- );
- }
-
- return group;
-};
@@ -1,31 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-/**
- * Gets build property from the main target build section
- *
- * It differs from the project.getBuildProperty exposed by xcode in the way that:
- * - it only checks for build property in the main target `Debug` section
- * - `xcode` library iterates over all build sections and because it misses
- * an early return when property is found, it will return undefined/wrong value
- * when there's another build section typically after the one you want to access
- * without the property defined (e.g. CocoaPods sections appended to project
- * miss INFOPLIST_FILE), see: https://github.com/alunny/node-xcode/blob/master/lib/pbxProject.js#L1765
- */
-module.exports = function getBuildProperty(project, prop) {
- const target = project.getFirstTarget().firstTarget;
- const config = project.pbxXCConfigurationList()[
- target.buildConfigurationList
- ];
- const buildSection = project.pbxXCBuildConfigurationSection()[
- config.buildConfigurations[0].value
- ];
-
- return buildSection.buildSettings[prop];
-};
@@ -1,44 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const getFirstProject = project => project.getFirstProject().firstProject;
-
-const findGroup = (group, name) =>
- group.children.find(group => group.comment === name);
-
-/**
- * Returns group from .xcodeproj if one exists, null otherwise
- *
- * Unlike node-xcode `pbxGroupByName` - it does not return `first-matching`
- * group if multiple groups with the same name exist
- *
- * If path is not provided, it returns top-level group
- */
-module.exports = function getGroup(project, path) {
- const firstProject = getFirstProject(project);
-
- var group = project.getPBXGroupByKey(firstProject.mainGroup);
-
- if (!path) {
- return group;
- }
-
- for (var name of path.split('/')) {
- var foundGroup = findGroup(group, name);
-
- if (foundGroup) {
- group = project.getPBXGroupByKey(foundGroup.value);
- } else {
- group = null;
- break;
- }
- }
-
- return group;
-};
@@ -1,62 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const path = require('path');
-const union = require('lodash').union;
-const last = require('lodash').last;
-
-/**
- * Given an array of directories, it returns the one that contains
- * all the other directories in a given array inside it.
- *
- * Example:
- * Given an array of directories: ['/Users/Kureev/a', '/Users/Kureev/b']
- * the returned folder is `/Users/Kureev`
- *
- * Check `getHeaderSearchPath.spec.js` for more use-cases.
- */
-const getOuterDirectory = directories =>
- directories.reduce((topDir, currentDir) => {
- const currentFolders = currentDir.split(path.sep);
- const topMostFolders = topDir.split(path.sep);
-
- if (
- currentFolders.length === topMostFolders.length &&
- last(currentFolders) !== last(topMostFolders)
- ) {
- return currentFolders.slice(0, -1).join(path.sep);
- }
-
- return currentFolders.length < topMostFolders.length ? currentDir : topDir;
- });
-
-/**
- * Given an array of headers it returns search path so Xcode can resolve
- * headers when referenced like below:
- * ```
- * #import "CodePush.h"
- * ```
- * If all files are located in one directory (directories.length === 1),
- * we simply return a relative path to that location.
- *
- * Otherwise, we loop through them all to find the outer one that contains
- * all the headers inside. That location is then returned with /** appended at
- * the end so Xcode marks that location as `recursive` and will look inside
- * every folder of it to locate correct headers.
- */
-module.exports = function getHeaderSearchPath(sourceDir, headers) {
- const directories = union(headers.map(path.dirname));
-
- return directories.length === 1
- ? `"$(SRCROOT)${path.sep}${path.relative(sourceDir, directories[0])}"`
- : `"$(SRCROOT)${path.sep}${path.relative(
- sourceDir,
- getOuterDirectory(directories),
- )}/**"`;
-};
@@ -1,32 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const glob = require('glob');
-const path = require('path');
-
-const GLOB_EXCLUDE_PATTERN = [
- 'node_modules/**',
- 'Pods/**',
- 'Examples/**',
- 'examples/**',
-];
-
-/**
- * Given folder, it returns an array of all header files
- * inside it, ignoring node_modules and examples
- */
-module.exports = function getHeadersInFolder(folder) {
- return glob
- .sync('**/*.h', {
- cwd: folder,
- nodir: true,
- ignore: GLOB_EXCLUDE_PATTERN,
- })
- .map(file => path.join(folder, file));
-};
@@ -1,27 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const plistParser = require('plist');
-const getPlistPath = require('./getPlistPath');
-const fs = require('fs');
-
-/**
- * Returns Info.plist located in the iOS project
- *
- * Returns `null` if INFOPLIST_FILE is not specified.
- */
-module.exports = function getPlist(project, sourceDir) {
- const plistPath = getPlistPath(project, sourceDir);
-
- if (!plistPath || !fs.existsSync(plistPath)) {
- return null;
- }
-
- return plistParser.parse(fs.readFileSync(plistPath, 'utf-8'));
-};
@@ -1,24 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const path = require('path');
-const getBuildProperty = require('./getBuildProperty');
-
-module.exports = function getPlistPath(project, sourceDir) {
- const plistFile = getBuildProperty(project, 'INFOPLIST_FILE');
-
- if (!plistFile) {
- return null;
- }
-
- return path.join(
- sourceDir,
- plistFile.replace(/"/g, '').replace('$(SRCROOT)', ''),
- );
-};
@@ -1,20 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-/**
- * Given xcodeproj it returns list of products ending with
- * .a extension, so that we know what elements add to target
- * project static library
- */
-module.exports = function getProducts(project) {
- return project
- .pbxGroupByName('Products')
- .children.map(c => c.comment)
- .filter(c => c.indexOf('.a') > -1);
-};
@@ -1,37 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-/**
- * Given xcodeproj it returns list of targets
- */
-module.exports = function getTargets(project) {
- let targets = project.getFirstProject().firstProject.targets;
- let nativeTargetSection = project.pbxNativeTargetSection();
- return targets.map(function(target) {
- let key = target.value;
- let configurationListId = project.pbxNativeTargetSection()[key]
- .buildConfigurationList;
- let configurationList = project.pbxXCConfigurationList()[
- configurationListId
- ];
- let buildConfigurationId = configurationList.buildConfigurations[0].value;
- let buildConfiguration = project.pbxXCBuildConfigurationSection()[
- buildConfigurationId
- ];
- return {
- uuid: key,
- target: nativeTargetSection[key],
- name: nativeTargetSection[key].productReference_comment,
- isTVOS:
- (buildConfiguration.buildSettings.SDKROOT &&
- buildConfiguration.buildSettings.SDKROOT.indexOf('appletv') !== -1) ||
- false,
- };
- });
-};
@@ -1,20 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-/**
- * Given an array of libraries already imported and packageName that will be
- * added, returns true or false depending on whether the library is already linked
- * or not
- */
-module.exports = function hasLibraryImported(libraries, packageName) {
- return (
- libraries.children.filter(library => library.comment === packageName)
- .length > 0
- );
-};
@@ -1,11 +0,0 @@
-/** @format */
-
-module.exports = function() {
- return {
- isInstalled: require('./common/isInstalled'),
- register: require('./common/registerNativeModule'),
- unregister: require('./common/unregisterNativeModule'),
- copyAssets: require('./copyAssets'),
- unlinkAssets: require('./unlinkAssets'),
- };
-};
@@ -1,27 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const xcode = require('xcode');
-const getGroup = require('./getGroup');
-const hasLibraryImported = require('./hasLibraryImported');
-
-/**
- * Returns true if `xcodeproj` specified by dependencyConfig is present
- * in a top level `libraryFolder`
- */
-module.exports = function isInstalled(projectConfig, dependencyConfig) {
- const project = xcode.project(projectConfig.pbxprojPath).parseSync();
- const libraries = getGroup(project, projectConfig.libraryFolder);
-
- if (!libraries) {
- return false;
- }
-
- return hasLibraryImported(libraries, dependencyConfig.projectName);
-};
@@ -1,48 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-/**
- * Given Xcode project and path, iterate over all build configurations
- * and execute func with HEADER_SEARCH_PATHS from current section
- *
- * We cannot use builtin addToHeaderSearchPaths method since react-native init does not
- * use $(TARGET_NAME) for PRODUCT_NAME, but sets it manually so that method will skip
- * that target.
- *
- * To workaround that issue and make it more bullet-proof for different names,
- * we iterate over all configurations and look for `lc++` linker flag to detect
- * React Native target.
- *
- * Important: That function mutates `buildSettings` and it's not pure thus you should
- * not rely on its return value
- */
-const defaultHeaderPaths = ['"$(inherited)"'];
-
-module.exports = function headerSearchPathIter(project, func) {
- const config = project.pbxXCBuildConfigurationSection();
-
- Object.keys(config)
- .filter(ref => ref.indexOf('_comment') === -1)
- .forEach(ref => {
- const buildSettings = config[ref].buildSettings;
- const shouldVisitBuildSettings =
- (Array.isArray(buildSettings.OTHER_LDFLAGS)
- ? buildSettings.OTHER_LDFLAGS
- : []
- ).indexOf('"-lc++"') >= 0;
-
- if (shouldVisitBuildSettings) {
- const searchPaths = buildSettings.HEADER_SEARCH_PATHS
- ? [].concat(buildSettings.HEADER_SEARCH_PATHS)
- : defaultHeaderPaths;
-
- buildSettings.HEADER_SEARCH_PATHS = func(searchPaths);
- }
- });
-};
@@ -1,90 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const xcode = require('xcode');
-const fs = require('fs');
-const path = require('path');
-const log = require('npmlog');
-
-const addToHeaderSearchPaths = require('./addToHeaderSearchPaths');
-const getHeadersInFolder = require('./getHeadersInFolder');
-const getHeaderSearchPath = require('./getHeaderSearchPath');
-const getProducts = require('./getProducts');
-const getTargets = require('./getTargets');
-const createGroupWithMessage = require('./createGroupWithMessage');
-const addFileToProject = require('./addFileToProject');
-const addProjectToLibraries = require('./addProjectToLibraries');
-const addSharedLibraries = require('./addSharedLibraries');
-const isEmpty = require('lodash').isEmpty;
-const getGroup = require('./getGroup');
-
-/**
- * Register native module IOS adds given dependency to project by adding
- * its xcodeproj to project libraries as well as attaching static library
- * to the first target (the main one)
- *
- * If library is already linked, this action is a no-op.
- */
-module.exports = function registerNativeModuleIOS(
- dependencyConfig,
- projectConfig,
-) {
- const project = xcode.project(projectConfig.pbxprojPath).parseSync();
- const dependencyProject = xcode
- .project(dependencyConfig.pbxprojPath)
- .parseSync();
-
- const libraries = createGroupWithMessage(
- project,
- projectConfig.libraryFolder,
- );
- const file = addFileToProject(
- project,
- path.relative(projectConfig.sourceDir, dependencyConfig.projectPath),
- );
-
- const targets = getTargets(project);
-
- addProjectToLibraries(libraries, file);
-
- getTargets(dependencyProject).forEach(product => {
- var i;
- if (!product.isTVOS) {
- for (i = 0; i < targets.length; i++) {
- if (!targets[i].isTVOS) {
- project.addStaticLibrary(product.name, {
- target: targets[i].uuid,
- });
- }
- }
- }
-
- if (product.isTVOS) {
- for (i = 0; i < targets.length; i++) {
- if (targets[i].isTVOS) {
- project.addStaticLibrary(product.name, {
- target: targets[i].uuid,
- });
- }
- }
- }
- });
-
- addSharedLibraries(project, dependencyConfig.sharedLibraries);
-
- const headers = getHeadersInFolder(dependencyConfig.folder);
- if (!isEmpty(headers)) {
- addToHeaderSearchPaths(
- project,
- getHeaderSearchPath(projectConfig.sourceDir, headers),
- );
- }
-
- fs.writeFileSync(projectConfig.pbxprojPath, project.writeSync());
-};
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const mapHeaderSearchPaths = require('./mapHeaderSearchPaths');
-
-/**
- * Given Xcode project and absolute path, it makes sure there are no headers referring to it
- */
-module.exports = function addToHeaderSearchPaths(project, path) {
- mapHeaderSearchPaths(project, searchPaths =>
- searchPaths.filter(searchPath => searchPath !== path),
- );
-};
@@ -1,28 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-/**
- * For all files that are created and referenced from another `.xcodeproj` -
- * a new PBXItemContainerProxy is created that contains `containerPortal` value
- * which equals to xcodeproj file.uuid from PBXFileReference section.
- */
-module.exports = function removeFromPbxItemContainerProxySection(
- project,
- file,
-) {
- const section = project.hash.project.objects.PBXContainerItemProxy;
-
- for (var key of Object.keys(section)) {
- if (section[key].containerPortal === file.uuid) {
- delete section[key];
- }
- }
-
- return;
-};
@@ -1,24 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-/**
- * Every file added to the project from another project is attached to
- * `PBXItemContainerProxy` through `PBXReferenceProxy`.
- */
-module.exports = function removeFromPbxReferenceProxySection(project, file) {
- const section = project.hash.project.objects.PBXReferenceProxy;
-
- for (var key of Object.keys(section)) {
- if (section[key].path === file.basename) {
- delete section[key];
- }
- }
-
- return;
-};
@@ -1,37 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-/**
- * For each file (.xcodeproj), there's an entry in `projectReferences` created
- * that has two entries - `ProjectRef` - reference to a file.uuid and
- * `ProductGroup` - uuid of a Products group.
- *
- * When projectReference is found - it's deleted and the removed value is returned
- * so that ProductGroup in PBXGroup section can be removed as well.
- *
- * Otherwise returns null
- */
-module.exports = function removeFromProjectReferences(project, file) {
- const firstProject = project.getFirstProject().firstProject;
-
- const projectRef = firstProject.projectReferences.find(
- item => item.ProjectRef === file.uuid,
- );
-
- if (!projectRef) {
- return null;
- }
-
- firstProject.projectReferences.splice(
- firstProject.projectReferences.indexOf(projectRef),
- 1,
- );
-
- return projectRef;
-};
@@ -1,30 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const PbxFile = require('xcode/lib/pbxFile');
-const removeFromPbxReferenceProxySection = require('./removeFromPbxReferenceProxySection');
-
-/**
- * Removes file from static libraries
- *
- * Similar to `node-xcode` addStaticLibrary
- */
-module.exports = function removeFromStaticLibraries(project, path, opts) {
- const file = new PbxFile(path);
-
- file.target = opts ? opts.target : undefined;
-
- project.removeFromPbxFileReferenceSection(file);
- project.removeFromPbxBuildFileSection(file);
- project.removeFromPbxFrameworksBuildPhase(file);
- project.removeFromLibrarySearchPaths(file);
- removeFromPbxReferenceProxySection(project, file);
-
- return file;
-};
@@ -1,20 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-module.exports = function removeProductGroup(project, productGroupId) {
- const section = project.hash.project.objects.PBXGroup;
-
- for (var key of Object.keys(section)) {
- if (key === productGroupId) {
- delete section[key];
- }
- }
-
- return;
-};
@@ -1,21 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-/**
- * Given an array of xcodeproj libraries and pbxFile,
- * it removes it from that group by comparing basenames
- *
- * Important: That function mutates `libraries` and it's not pure.
- * It's mainly due to limitations of `xcode` library.
- */
-module.exports = function removeProjectFromLibraries(libraries, file) {
- libraries.children = libraries.children.filter(
- library => library.comment !== file.basename,
- );
-};
@@ -1,35 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const PbxFile = require('xcode/lib/pbxFile');
-const removeFromPbxItemContainerProxySection = require('./removeFromPbxItemContainerProxySection');
-const removeFromProjectReferences = require('./removeFromProjectReferences');
-const removeProductGroup = require('./removeProductGroup');
-
-/**
- * Given xcodeproj and filePath, it creates new file
- * from path provided and removes it. That operation is required since
- * underlying method requires PbxFile instance to be passed (it does not
- * have to have uuid or fileRef defined since it will do equality check
- * by path)
- *
- * Returns removed file (that one will have UUID)
- */
-module.exports = function removeProjectFromProject(project, filePath) {
- const file = project.removeFromPbxFileReferenceSection(new PbxFile(filePath));
- const projectRef = removeFromProjectReferences(project, file);
-
- if (projectRef) {
- removeProductGroup(project, projectRef.ProductGroup);
- }
-
- removeFromPbxItemContainerProxySection(project, file);
-
- return file;
-};
@@ -1,20 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-module.exports = function removeSharedLibraries(project, libraries) {
- if (!libraries.length) {
- return;
- }
-
- const target = project.getFirstTarget().uuid;
-
- for (var name of libraries) {
- project.removeFramework(name, {target});
- }
-};
@@ -1,62 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const fs = require('fs-extra');
-const path = require('path');
-const xcode = require('xcode');
-const log = require('npmlog');
-const groupFilesByType = require('../groupFilesByType');
-const getPlist = require('./getPlist');
-const writePlist = require('./writePlist');
-const difference = require('lodash').difference;
-
-/**
- * Unlinks assets from iOS project. Removes references for fonts from `Info.plist`
- * fonts provided by application and from `Resources` group
- */
-module.exports = function unlinkAssetsIOS(files, projectConfig) {
- const project = xcode.project(projectConfig.pbxprojPath).parseSync();
- const assets = groupFilesByType(files);
- const plist = getPlist(project, projectConfig.sourceDir);
-
- if (!plist) {
- return log.error(
- 'ERRPLIST',
- "Could not locate Info.plist file. Check if your project has 'INFOPLIST_FILE' set properly",
- );
- }
-
- if (!project.pbxGroupByName('Resources')) {
- return log.error(
- 'ERRGROUP',
- "Group 'Resources' does not exist in your Xcode project. There is nothing to unlink.",
- );
- }
-
- const removeResourceFile = function(f) {
- (f || [])
- .map(asset =>
- project.removeResourceFile(
- path.relative(projectConfig.sourceDir, asset),
- {target: project.getFirstTarget().uuid},
- ),
- )
- .map(file => file.basename);
- };
-
- removeResourceFile(assets.image);
-
- const fonts = removeResourceFile(assets.font);
-
- plist.UIAppFonts = difference(plist.UIAppFonts || [], fonts);
-
- fs.writeFileSync(projectConfig.pbxprojPath, project.writeSync());
-
- writePlist(project, projectConfig.sourceDir, plist);
-};
@@ -1,76 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const xcode = require('xcode');
-const path = require('path');
-const fs = require('fs');
-const difference = require('lodash').difference;
-const isEmpty = require('lodash').isEmpty;
-
-const getGroup = require('./getGroup');
-const getProducts = require('./getProducts');
-const getTargets = require('./getTargets');
-const getHeadersInFolder = require('./getHeadersInFolder');
-const getHeaderSearchPath = require('./getHeaderSearchPath');
-const removeProjectFromProject = require('./removeProjectFromProject');
-const removeProjectFromLibraries = require('./removeProjectFromLibraries');
-const removeFromStaticLibraries = require('./removeFromStaticLibraries');
-const removeFromHeaderSearchPaths = require('./removeFromHeaderSearchPaths');
-const removeSharedLibraries = require('./removeSharedLibraries');
-
-/**
- * Unregister native module IOS
- *
- * If library is already unlinked, this action is a no-op.
- */
-module.exports = function unregisterNativeModule(
- dependencyConfig,
- projectConfig,
- iOSDependencies,
-) {
- const project = xcode.project(projectConfig.pbxprojPath).parseSync();
- const dependencyProject = xcode
- .project(dependencyConfig.pbxprojPath)
- .parseSync();
-
- const libraries = getGroup(project, projectConfig.libraryFolder);
-
- const file = removeProjectFromProject(
- project,
- path.relative(projectConfig.sourceDir, dependencyConfig.projectPath),
- );
-
- removeProjectFromLibraries(libraries, file);
-
- getTargets(dependencyProject).forEach(target => {
- removeFromStaticLibraries(project, target.name, {
- target: project.getFirstTarget().uuid,
- });
- });
-
- const sharedLibraries = difference(
- dependencyConfig.sharedLibraries,
- iOSDependencies.reduce(
- (libs, dependency) => libs.concat(dependency.sharedLibraries),
- projectConfig.sharedLibraries,
- ),
- );
-
- removeSharedLibraries(project, sharedLibraries);
-
- const headers = getHeadersInFolder(dependencyConfig.folder);
- if (!isEmpty(headers)) {
- removeFromHeaderSearchPaths(
- project,
- getHeaderSearchPath(projectConfig.sourceDir, headers),
- );
- }
-
- fs.writeFileSync(projectConfig.pbxprojPath, project.writeSync());
-};
@@ -1,33 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const plistParser = require('plist');
-const getPlistPath = require('./getPlistPath');
-const fs = require('fs');
-
-/**
- * Writes to Info.plist located in the iOS project
- *
- * Returns `null` if INFOPLIST_FILE is not specified or file is non-existent.
- */
-module.exports = function writePlist(project, sourceDir, plist) {
- const plistPath = getPlistPath(project, sourceDir);
-
- if (!plistPath) {
- return null;
- }
-
- // We start with an offset of -1, because Xcode maintains a custom
- // indentation of the plist.
- // Ref: https://github.com/facebook/react-native/issues/11668
- return fs.writeFileSync(
- plistPath,
- plistParser.build(plist, {indent: '\t', offset: -1}) + '\n',
- );
-};
@@ -1,186 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow
- */
-
-/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
- * found when Flow v0.54 was deployed. To see the error delete this comment and
- * run Flow. */
-const log = require('npmlog');
-const path = require('path');
-const uniqBy = require('lodash').uniqBy;
-const flatten = require('lodash').flatten;
-/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
- * found when Flow v0.54 was deployed. To see the error delete this comment and
- * run Flow. */
-const chalk = require('chalk');
-
-/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
- * found when Flow v0.54 was deployed. To see the error delete this comment and
- * run Flow. */
-const isEmpty = require('lodash').isEmpty;
-const promiseWaterfall = require('./promiseWaterfall');
-const getProjectDependencies = require('./getProjectDependencies');
-const getDependencyConfig = require('./getDependencyConfig');
-const pollParams = require('./pollParams');
-const commandStub = require('./commandStub');
-const promisify = require('./promisify');
-const findReactNativeScripts = require('../util/findReactNativeScripts');
-
-import type {RNConfig} from '../core';
-
-log.heading = 'rnpm-link';
-
-const dedupeAssets = assets => uniqBy(assets, asset => path.basename(asset));
-
-const linkDependency = async (platforms, project, dependency) => {
- const params = await pollParams(dependency.config.params);
-
- Object.keys(platforms || {}).forEach(platform => {
- if (!project[platform] || !dependency.config[platform]) {
- return null;
- }
-
- const linkConfig =
- platforms[platform] &&
- platforms[platform].linkConfig &&
- platforms[platform].linkConfig();
- if (!linkConfig || !linkConfig.isInstalled || !linkConfig.register) {
- return null;
- }
-
- const isInstalled = linkConfig.isInstalled(
- project[platform],
- dependency.name,
- dependency.config[platform],
- );
-
- if (isInstalled) {
- log.info(
- chalk.grey(
- `Platform '${platform}' module ${dependency.name} is already linked`,
- ),
- );
- return null;
- }
-
- log.info(`Linking ${dependency.name} ${platform} dependency`);
-
- linkConfig.register(
- dependency.name,
- dependency.config[platform],
- params,
- project[platform],
- );
-
- log.info(
- `Platform '${platform}' module ${
- dependency.name
- } has been successfully linked`,
- );
- });
-};
-
-const linkAssets = (platforms, project, assets) => {
- if (isEmpty(assets)) {
- return;
- }
-
- Object.keys(platforms || {}).forEach(platform => {
- const linkConfig =
- platforms[platform] &&
- platforms[platform].linkConfig &&
- platforms[platform].linkConfig();
- if (!linkConfig || !linkConfig.copyAssets) {
- return;
- }
-
- log.info(`Linking assets to ${platform} project`);
- linkConfig.copyAssets(assets, project[platform]);
- });
-
- log.info('Assets have been successfully linked to your project');
-};
-
-/**
- * Updates project and links all dependencies to it.
- *
- * @param args If optional argument [packageName] is provided,
- * only that package is processed.
- * @param config CLI config, see local-cli/core/index.js
- */
-function link(args: Array<string>, config: RNConfig) {
- let project;
- let platforms;
- try {
- project = config.getProjectConfig();
- platforms = config.getPlatformConfig();
- } catch (err) {
- log.error(
- 'ERRPACKAGEJSON',
- 'No package found. Are you sure this is a React Native project?',
- );
- return Promise.reject(err);
- }
-
- const hasProjectConfig = Object.keys(platforms).reduce(
- (acc, key) => acc || key in project,
- false,
- );
- if (!hasProjectConfig && findReactNativeScripts()) {
- throw new Error(
- '`react-native link` can not be used in Create React Native App projects. ' +
- 'If you need to include a library that relies on custom native code, ' +
- 'you might have to eject first. ' +
- 'See https://github.com/react-community/create-react-native-app/blob/master/EJECTING.md ' +
- 'for more information.',
- );
- }
-
- let packageName = args[0];
- // Trim the version / tag out of the package name (eg. package@latest)
- if (packageName !== undefined) {
- packageName = packageName.replace(/^(.+?)(@.+?)$/gi, '$1');
- }
-
- const dependencies = getDependencyConfig(
- config,
- packageName ? [packageName] : getProjectDependencies(),
- );
-
- const assets = dedupeAssets(
- dependencies.reduce(
- (acc, dependency) => acc.concat(dependency.config.assets),
- project.assets,
- ),
- );
-
- const tasks = flatten(
- dependencies.map(dependency => [
- () => promisify(dependency.config.commands.prelink || commandStub),
- () => linkDependency(platforms, project, dependency),
- () => promisify(dependency.config.commands.postlink || commandStub),
- ]),
- );
-
- tasks.push(() => linkAssets(platforms, project, assets));
-
- return promiseWaterfall(tasks).catch(err => {
- log.error(
- `Something went wrong while linking. Error: ${err.message} \n` +
- 'Please file an issue here: https://github.com/facebook/react-native/issues',
- );
- throw err;
- });
-}
-
-module.exports = {
- func: link,
- description: 'links all native dependencies (updates native build files)',
- name: 'link [packageName]',
-};
@@ -1,35 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-module.exports = function addPodEntry(
- podLines,
- linesToAddEntry,
- podName,
- nodePath,
-) {
- const newEntry = `pod '${podName}', :path => '../node_modules/${nodePath}'\n`;
-
- if (!linesToAddEntry) {
- return;
- } else if (Array.isArray(linesToAddEntry)) {
- linesToAddEntry.map(({line, indentation}, idx) =>
- podLines.splice(line + idx, 0, getLineToAdd(newEntry, indentation)),
- );
- } else {
- const {line, indentation} = linesToAddEntry;
- podLines.splice(line, 0, getLineToAdd(newEntry, indentation));
- }
-};
-
-function getLineToAdd(newEntry, indentation) {
- const spaces = Array(indentation + 1).join(' ');
- return spaces + newEntry;
-}
@@ -1,34 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-module.exports = function findLineToAddPod(podLines, firstTargetLine) {
- // match line with new target: target 'project_name' do (most likely target inside podfile main target)
- const nextTarget = /target (\'|\")\w+(\'|\") do/g;
- // match line that has only 'end' (if we don't catch new target or function, this would mean this is end of current target)
- const endOfCurrentTarget = /^\s*end\s*$/g;
- // match function definition, like: post_install do |installer| (some Podfiles have function defined inside main target
- const functionDefinition = /^\s*[a-z_]+\s+do(\s+\|[a-z]+\|)?/g;
-
- for (let i = firstTargetLine, len = podLines.length; i < len; i++) {
- const matchNextConstruct =
- podLines[i].match(nextTarget) || podLines[i].match(functionDefinition);
- const matchEnd = podLines[i].match(endOfCurrentTarget);
-
- if (matchNextConstruct || matchEnd) {
- const firstNonSpaceCharacter = podLines[i].search(/\S/);
- return {
- indentation: firstNonSpaceCharacter + (matchEnd ? 2 : 0),
- line: i,
- };
- }
- }
- return null;
-};
@@ -1,21 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-const MARKER_TEXT = '# Add new pods below this line';
-
-module.exports = function findMarkedLinesInPodfile(podLines) {
- const result = [];
- for (let i = 0, len = podLines.length; i < len; i++) {
- if (podLines[i].includes(MARKER_TEXT)) {
- result.push({line: i + 1, indentation: podLines[i].indexOf('#')});
- }
- }
- return result;
-};
@@ -1,26 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-module.exports = function findPodTargetLine(podLines, projectName) {
- const targetName = projectName.replace('.xcodeproj', '');
- //match first target definition in file: target 'target_name' do
- const targetRegex = new RegExp(
- 'target (\'|")' + targetName + '(\'|") do',
- 'g',
- );
- for (let i = 0, len = podLines.length; i < len; i++) {
- const match = podLines[i].match(targetRegex);
- if (match) {
- return i + 1;
- }
- }
- return null;
-};
@@ -1,31 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const readPodfile = require('./readPodfile');
-
-module.exports = function isInstalled(iOSProject, dependencyConfig) {
- if (!iOSProject.podfile) {
- return false;
- }
- // match line with pod declaration: pod 'dependencyPodName' (other possible parameters of pod are ignored)
- const dependencyRegExp = new RegExp(
- 'pod\\s+(\'|")' + dependencyConfig.podspec + '(\'|")',
- 'g',
- );
- const podLines = readPodfile(iOSProject.podfile);
- for (let i = 0, len = podLines.length; i < len; i++) {
- const match = podLines[i].match(dependencyRegExp);
- if (match) {
- return true;
- }
- }
- return false;
-};
@@ -1,17 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const fs = require('fs');
-
-module.exports = function readPodfile(podfilePath) {
- const podContent = fs.readFileSync(podfilePath, 'utf8');
- return podContent.split(/\r?\n/g);
-};
@@ -1,38 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const readPodfile = require('./readPodfile');
-const findPodTargetLine = require('./findPodTargetLine');
-const findLineToAddPod = require('./findLineToAddPod');
-const findMarkedLinesInPodfile = require('./findMarkedLinesInPodfile');
-const addPodEntry = require('./addPodEntry');
-const savePodFile = require('./savePodFile');
-
-module.exports = function registerNativeModulePods(
- name,
- dependencyConfig,
- iOSProject,
-) {
- const podLines = readPodfile(iOSProject.podfile);
- const linesToAddEntry = getLinesToAddEntry(podLines, iOSProject);
- addPodEntry(podLines, linesToAddEntry, dependencyConfig.podspec, name);
- savePodFile(iOSProject.podfile, podLines);
-};
-
-function getLinesToAddEntry(podLines, {projectName}) {
- const linesToAddPodWithMarker = findMarkedLinesInPodfile(podLines);
- if (linesToAddPodWithMarker.length > 0) {
- return linesToAddPodWithMarker;
- } else {
- const firstTargetLined = findPodTargetLine(podLines, projectName);
- return findLineToAddPod(podLines, firstTargetLined);
- }
-}
@@ -1,21 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-module.exports = function removePodEntry(podfileContent, podName) {
- // this regex should catch line(s) with full pod definition, like: pod 'podname', :path => '../node_modules/podname', :subspecs => ['Sub2', 'Sub1']
- const podRegex = new RegExp(
- '\\n( |\\t)*pod\\s+("|\')' +
- podName +
- '("|\')(,\\s*(:[a-z]+\\s*=>)?\\s*(("|\').*?("|\')|\\[[\\s\\S]*?\\]))*\\n',
- 'g',
- );
- return podfileContent.replace(podRegex, '\n');
-};
@@ -1,17 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const fs = require('fs');
-
-module.exports = function savePodFile(podfilePath, podLines) {
- const newPodfile = podLines.join('\n');
- fs.writeFileSync(podfilePath, newPodfile);
-};
@@ -1,22 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const fs = require('fs');
-const removePodEntry = require('./removePodEntry');
-
-/**
- * Unregister native module IOS with CocoaPods
- */
-module.exports = function unregisterNativeModule(dependencyConfig, iOSProject) {
- const podContent = fs.readFileSync(iOSProject.podfile, 'utf8');
- const removed = removePodEntry(podContent, dependencyConfig.podspec);
- fs.writeFileSync(iOSProject.podfile, removed);
-};
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-var inquirer = require('inquirer');
-
-module.exports = questions =>
- new Promise((resolve, reject) => {
- if (!questions) {
- return resolve({});
- }
-
- inquirer.prompt(questions).then(resolve, reject);
- });
@@ -1,23 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-/**
- * Given an array of promise creators, executes them in a sequence.
- *
- * If any of the promises in the chain fails, all subsequent promises
- * will be skipped
- *
- * Returns the value last promise from a sequence resolved
- */
-module.exports = function promiseWaterfall(tasks) {
- return tasks.reduce(
- (prevTaskPromise, task) => prevTaskPromise.then(task),
- Promise.resolve(),
- );
-};
@@ -1,13 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-module.exports = func =>
- new Promise((resolve, reject) =>
- func((err, res) => (err ? reject(err) : resolve(res))),
- );
@@ -1,167 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const log = require('npmlog');
-
-const getProjectDependencies = require('./getProjectDependencies');
-const getDependencyConfig = require('./getDependencyConfig');
-const difference = require('lodash').difference;
-const filter = require('lodash').filter;
-const flatten = require('lodash').flatten;
-const isEmpty = require('lodash').isEmpty;
-const promiseWaterfall = require('./promiseWaterfall');
-const commandStub = require('./commandStub');
-const promisify = require('./promisify');
-
-log.heading = 'rnpm-link';
-
-const unlinkDependency = (
- platforms,
- project,
- dependency,
- packageName,
- otherDependencies,
-) => {
- Object.keys(platforms || {}).forEach(platform => {
- if (!project[platform] || !dependency[platform]) {
- return;
- }
-
- const linkConfig =
- platforms[platform] &&
- platforms[platform].linkConfig &&
- platforms[platform].linkConfig();
- if (!linkConfig || !linkConfig.isInstalled || !linkConfig.unregister) {
- return;
- }
-
- const isInstalled = linkConfig.isInstalled(
- project[platform],
- packageName,
- dependency[platform],
- );
-
- if (!isInstalled) {
- log.info(`Platform '${platform}' module ${packageName} is not installed`);
- return;
- }
-
- log.info(`Unlinking ${packageName} ${platform} dependency`);
-
- linkConfig.unregister(
- packageName,
- dependency[platform],
- project[platform],
- otherDependencies,
- );
-
- log.info(
- `Platform '${platform}' module ${
- dependency.name
- } has been successfully unlinked`,
- );
- });
-};
-
-/**
- * Updates project and unlink specific dependency
- *
- * If optional argument [packageName] is provided, it's the only one
- * that's checked
- */
-function unlink(args, config) {
- const packageName = args[0];
-
- let platforms;
- let project;
- let dependency;
-
- try {
- platforms = config.getPlatformConfig();
- project = config.getProjectConfig();
- } catch (err) {
- log.error(
- 'ERRPACKAGEJSON',
- "No package found. Are you sure it's a React Native project?",
- );
- return Promise.reject(err);
- }
-
- try {
- dependency = config.getDependencyConfig(packageName);
- } catch (err) {
- log.warn(
- 'ERRINVALIDPROJ',
- `Project ${packageName} is not a react-native library`,
- );
- return Promise.reject(err);
- }
-
- const allDependencies = getDependencyConfig(config, getProjectDependencies());
- const otherDependencies = filter(
- allDependencies,
- d => d.name !== packageName,
- );
-
- const tasks = [
- () => promisify(dependency.commands.preunlink || commandStub),
- () =>
- unlinkDependency(
- platforms,
- project,
- dependency,
- packageName,
- otherDependencies,
- ),
- () => promisify(dependency.commands.postunlink || commandStub),
- ];
-
- return promiseWaterfall(tasks)
- .then(() => {
- // @todo move all these to `tasks` array, just like in
- // link
- const assets = difference(
- dependency.assets,
- flatten(allDependencies, d => d.assets),
- );
-
- if (isEmpty(assets)) {
- return Promise.resolve();
- }
-
- Object.keys(platforms || {}).forEach(platform => {
- const linkConfig =
- platforms[platform] &&
- platforms[platform].linkConfig &&
- platforms[platform].linkConfig();
- if (!linkConfig || !linkConfig.unlinkAssets) {
- return;
- }
-
- log.info(`Unlinking assets from ${platform} project`);
- linkConfig.unlinkAssets(assets, project[platform]);
- });
-
- log.info(
- `${packageName} assets has been successfully unlinked from your project`,
- );
- })
- .catch(err => {
- log.error(
- `It seems something went wrong while unlinking. Error: ${err.message}`,
- );
- throw err;
- });
-}
-
-module.exports = {
- func: unlink,
- description: 'unlink native dependency',
- name: 'unlink <packageName>',
-};

local-cli/logAndroid/logAndroid.js

@@ -1,53 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const chalk = require('chalk');
-const child_process = require('child_process');
-
-/**
- * Starts adb logcat
- */
-function logAndroid() {
- return new Promise((resolve, reject) => {
- _logAndroid(resolve, reject);
- });
-}
-
-function _logAndroid() {
- try {
- const adbPath = process.env.ANDROID_HOME
- ? process.env.ANDROID_HOME + '/platform-tools/adb'
- : 'adb';
-
- const adbArgs = ['logcat', '*:S', 'ReactNative:V', 'ReactNativeJS:V'];
-
- console.log(
- chalk.bold(`Starting the logger (${adbPath} ${adbArgs.join(' ')})...`),
- );
-
- const log = child_process.spawnSync(adbPath, adbArgs, {stdio: 'inherit'});
-
- if (log.error !== null) {
- throw log.error;
- }
- } catch (e) {
- console.log(
- chalk.red('adb invocation failed. Do you have adb in your PATH?'),
- );
- return Promise.reject();
- }
-}
-
-module.exports = {
- name: 'log-android',
- description: 'starts adb logcat',
- func: logAndroid,
-};

local-cli/logIOS/logIOS.js

@@ -1,91 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const chalk = require('chalk');
-const child_process = require('child_process');
-const os = require('os');
-const path = require('path');
-
-/**
- * Starts iOS device syslog tail
- */
-function logIOS() {
- return new Promise((resolve, reject) => {
- _logIOS(resolve, reject);
- });
-}
-
-function _logIOS() {
- let rawDevices;
-
- try {
- rawDevices = child_process.execFileSync(
- 'xcrun',
- ['simctl', 'list', 'devices', '--json'],
- {encoding: 'utf8'},
- );
- } catch (e) {
- console.log(
- chalk.red(
- 'xcrun invocation failed. Please check that Xcode is installed.',
- ),
- );
- return Promise.reject(e);
- }
-
- const {devices} = JSON.parse(rawDevices);
-
- const device = _findAvailableDevice(devices);
- if (device === undefined) {
- console.log(chalk.red('No active iOS device found'));
- return Promise.reject();
- }
-
- return tailDeviceLogs(device.udid);
-}
-
-function _findAvailableDevice(devices) {
- for (const key of Object.keys(devices)) {
- for (const device of devices[key]) {
- if (device.availability === '(available)' && device.state === 'Booted') {
- return device;
- }
- }
- }
-}
-
-function tailDeviceLogs(udid) {
- const logDir = path.join(
- os.homedir(),
- 'Library',
- 'Logs',
- 'CoreSimulator',
- udid,
- 'asl',
- );
-
- const log = child_process.spawnSync(
- 'syslog',
- ['-w', '-F', 'std', '-d', logDir],
- {stdio: 'inherit'},
- );
-
- if (log.error !== null) {
- console.log(chalk.red('syslog invocation failed.'));
- return Promise.reject(log.error);
- }
-}
-
-module.exports = {
- name: 'log-ios',
- description: 'starts iOS device syslog tail',
- func: logIOS,
-};

local-cli/__mocks__/beeper.js

@@ -1,15 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-// beeper@1.1.0 has a return statement outside of a function
-// and therefore doesn't parse. Let's mock it so that we can
-// run the tests.
-module.exports = function() {};

local-cli/__mocks__/fs.js

@@ -1,43 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const fs = new (require('metro-memory-fs'))({cwd: process.cwd});
-
-function setMockFilesystem(object) {
- fs.reset();
- const root = process.platform === 'win32' ? 'c:\\' : '/';
- mockDir(root, {...object});
-}
-
-function mockDir(dirPath, desc) {
- for (const entName in desc) {
- const ent = desc[entName];
- const entPath = require('path').join(dirPath, entName);
- if (typeof ent === 'string' || ent instanceof Buffer) {
- fs.writeFileSync(entPath, ent);
- continue;
- }
- if (typeof ent !== 'object') {
- throw new Error(require('util').format('invalid entity:', ent));
- }
- if (ent.SYMLINK != null) {
- fs.symlinkSync(ent.SYMLINK, entPath);
- continue;
- }
- fs.mkdirSync(entPath);
- mockDir(entPath, ent);
- }
-}
-
-fs.__setMockFilesystem = setMockFilesystem;
-fs.mock = {clear: () => fs.reset()};
-
-module.exports = fs;

local-cli/.npmignore

@@ -1,2 +0,0 @@
-__fixtures__
-__tests__

local-cli/runAndroid/adb.js

@@ -1,49 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow strict
- */
-
-const child_process = require('child_process');
-
-/**
- * Parses the output of the 'adb devices' command
- */
-function parseDevicesResult(result: string): Array<string> {
- if (!result) {
- return [];
- }
-
- const devices = [];
- const lines = result.trim().split(/\r?\n/);
-
- for (let i = 0; i < lines.length; i++) {
- let words = lines[i].split(/[ ,\t]+/).filter(w => w !== '');
-
- if (words[1] === 'device') {
- devices.push(words[0]);
- }
- }
- return devices;
-}
-
-/**
- * Executes the commands needed to get a list of devices from ADB
- */
-function getDevices(): Array<string> {
- try {
- const devicesResult = child_process.execSync('adb devices');
- return parseDevicesResult(devicesResult.toString());
- } catch (e) {
- return [];
- }
-}
-
-module.exports = {
- parseDevicesResult: parseDevicesResult,
- getDevices: getDevices,
-};

local-cli/runAndroid/runAndroid.js

@@ -1,485 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const adb = require('./adb');
-const chalk = require('chalk');
-const child_process = require('child_process');
-const fs = require('fs');
-const isPackagerRunning = require('../util/isPackagerRunning');
-const findReactNativeScripts = require('../util/findReactNativeScripts');
-const isString = require('lodash/isString');
-const path = require('path');
-const Promise = require('promise');
-
-// Verifies this is an Android project
-function checkAndroid(root) {
- return fs.existsSync(path.join(root, 'android/gradlew'));
-}
-
-/**
- * Starts the app on a connected Android emulator or device.
- */
-function runAndroid(argv, config, args) {
- if (!checkAndroid(args.root)) {
- const reactNativeScriptsPath = findReactNativeScripts();
- if (reactNativeScriptsPath) {
- child_process.spawnSync(
- reactNativeScriptsPath,
- ['android'].concat(process.argv.slice(1)),
- {stdio: 'inherit'},
- );
- } else {
- console.log(
- chalk.red(
- 'Android project not found. Maybe run react-native android first?',
- ),
- );
- }
- return;
- }
-
- if (!args.packager) {
- return buildAndRun(args);
- }
-
- return isPackagerRunning(args.port).then(result => {
- if (result === 'running') {
- console.log(chalk.bold('JS server already running.'));
- } else if (result === 'unrecognized') {
- console.warn(
- chalk.yellow('JS server not recognized, continuing with build...'),
- );
- } else {
- // result == 'not_running'
- console.log(chalk.bold('Starting JS server...'));
- startServerInNewWindow(args.port, args.terminal);
- }
- return buildAndRun(args);
- });
-}
-
-function getAdbPath() {
- return process.env.ANDROID_HOME
- ? process.env.ANDROID_HOME + '/platform-tools/adb'
- : 'adb';
-}
-
-// Runs ADB reverse tcp:8081 tcp:8081 to allow loading the jsbundle from the packager
-function tryRunAdbReverse(packagerPort, device) {
- try {
- const adbPath = getAdbPath();
- const adbArgs = ['reverse', `tcp:${packagerPort}`, `tcp:${packagerPort}`];
-
- // If a device is specified then tell adb to use it
- if (device) {
- adbArgs.unshift('-s', device);
- }
-
- console.log(chalk.bold(`Running ${adbPath} ${adbArgs.join(' ')}`));
-
- child_process.execFileSync(adbPath, adbArgs, {
- stdio: [process.stdin, process.stdout, process.stderr],
- });
- } catch (e) {
- console.log(chalk.yellow(`Could not run adb reverse: ${e.message}`));
- }
-}
-
-function getPackageNameWithSuffix(appId, appIdSuffix, packageName) {
- if (appId) {
- return appId;
- } else if (appIdSuffix) {
- return packageName + '.' + appIdSuffix;
- }
-
- return packageName;
-}
-
-// Builds the app and runs it on a connected emulator / device.
-function buildAndRun(args) {
- process.chdir(path.join(args.root, 'android'));
- const cmd = process.platform.startsWith('win') ? 'gradlew.bat' : './gradlew';
-
- const packageName = fs
- .readFileSync(`${args.appFolder}/src/main/AndroidManifest.xml`, 'utf8')
- .match(/package="(.+?)"/)[1];
-
- const packageNameWithSuffix = getPackageNameWithSuffix(
- args.appId,
- args.appIdSuffix,
- packageName,
- );
-
- const adbPath = getAdbPath();
- if (args.deviceId) {
- if (isString(args.deviceId)) {
- runOnSpecificDevice(
- args,
- cmd,
- packageNameWithSuffix,
- packageName,
- adbPath,
- );
- } else {
- console.log(chalk.red('Argument missing for parameter --deviceId'));
- }
- } else {
- runOnAllDevices(args, cmd, packageNameWithSuffix, packageName, adbPath);
- }
-}
-
-function runOnSpecificDevice(
- args,
- gradlew,
- packageNameWithSuffix,
- packageName,
- adbPath,
-) {
- let devices = adb.getDevices();
- if (devices && devices.length > 0) {
- if (devices.indexOf(args.deviceId) !== -1) {
- buildApk(gradlew);
- installAndLaunchOnDevice(
- args,
- args.deviceId,
- packageNameWithSuffix,
- packageName,
- adbPath,
- );
- } else {
- console.log(
- 'Could not find device with the id: "' + args.deviceId + '".',
- );
- console.log('Choose one of the following:');
- console.log(devices);
- }
- } else {
- console.log('No Android devices connected.');
- }
-}
-
-function buildApk(gradlew) {
- try {
- console.log(chalk.bold('Building the app...'));
-
- // using '-x lint' in order to ignore linting errors while building the apk
- child_process.execFileSync(gradlew, ['build', '-x', 'lint'], {
- stdio: [process.stdin, process.stdout, process.stderr],
- });
- } catch (e) {
- console.log(
- chalk.red('Could not build the app, read the error above for details.\n'),
- );
- }
-}
-
-function tryInstallAppOnDevice(args, device) {
- try {
- const pathToApk = `${args.appFolder}/build/outputs/apk/${
- args.appFolder
- }-debug.apk`;
- const adbPath = getAdbPath();
- const adbArgs = ['-s', device, 'install', pathToApk];
- console.log(
- chalk.bold(
- `Installing the app on the device (cd android && adb -s ${device} install ${pathToApk}`,
- ),
- );
- child_process.execFileSync(adbPath, adbArgs, {
- stdio: [process.stdin, process.stdout, process.stderr],
- });
- } catch (e) {
- console.log(e.message);
- console.log(
- chalk.red(
- 'Could not install the app on the device, read the error above for details.\n',
- ),
- );
- }
-}
-
-function tryLaunchAppOnDevice(
- device,
- packageNameWithSuffix,
- packageName,
- adbPath,
- mainActivity,
-) {
- try {
- const adbArgs = [
- '-s',
- device,
- 'shell',
- 'am',
- 'start',
- '-n',
- packageNameWithSuffix + '/' + packageName + '.' + mainActivity,
- ];
- console.log(
- chalk.bold(
- `Starting the app on ${device} (${adbPath} ${adbArgs.join(' ')})...`,
- ),
- );
- child_process.spawnSync(adbPath, adbArgs, {stdio: 'inherit'});
- } catch (e) {
- console.log(
- chalk.red('adb invocation failed. Do you have adb in your PATH?'),
- );
- }
-}
-
-function installAndLaunchOnDevice(
- args,
- selectedDevice,
- packageNameWithSuffix,
- packageName,
- adbPath,
-) {
- tryRunAdbReverse(args.port, selectedDevice);
- tryInstallAppOnDevice(args, selectedDevice);
- tryLaunchAppOnDevice(
- selectedDevice,
- packageNameWithSuffix,
- packageName,
- adbPath,
- args.mainActivity,
- );
-}
-
-function runOnAllDevices(
- args,
- cmd,
- packageNameWithSuffix,
- packageName,
- adbPath,
-) {
- try {
- const gradleArgs = [];
- if (args.variant) {
- gradleArgs.push(
- 'install' + args.variant[0].toUpperCase() + args.variant.slice(1),
- );
- } else if (args.flavor) {
- console.warn(
- chalk.yellow('--flavor has been deprecated. Use --variant instead'),
- );
- gradleArgs.push(
- 'install' + args.flavor[0].toUpperCase() + args.flavor.slice(1),
- );
- } else {
- gradleArgs.push('installDebug');
- }
-
- if (args.installDebug) {
- gradleArgs.push(args.installDebug);
- }
-
- console.log(
- chalk.bold(
- `Building and installing the app on the device (cd android && ${cmd} ${gradleArgs.join(
- ' ',
- )})...`,
- ),
- );
-
- child_process.execFileSync(cmd, gradleArgs, {
- stdio: [process.stdin, process.stdout, process.stderr],
- });
- } catch (e) {
- console.log(
- chalk.red(
- 'Could not install the app on the device, read the error above for details.\n' +
- 'Make sure you have an Android emulator running or a device connected and have\n' +
- 'set up your Android development environment:\n' +
- 'https://facebook.github.io/react-native/docs/getting-started.html',
- ),
- );
- // stderr is automatically piped from the gradle process, so the user
- // should see the error already, there is no need to do
- // `console.log(e.stderr)`
- return Promise.reject();
- }
- const devices = adb.getDevices();
- if (devices && devices.length > 0) {
- devices.forEach(device => {
- tryRunAdbReverse(args.port, device);
- tryLaunchAppOnDevice(
- device,
- packageNameWithSuffix,
- packageName,
- adbPath,
- args.mainActivity,
- );
- });
- } else {
- try {
- // If we cannot execute based on adb devices output, fall back to
- // shell am start
- const fallbackAdbArgs = [
- 'shell',
- 'am',
- 'start',
- '-n',
- packageNameWithSuffix + '/' + packageName + '.MainActivity',
- ];
- console.log(
- chalk.bold(
- `Starting the app (${adbPath} ${fallbackAdbArgs.join(' ')}...`,
- ),
- );
- child_process.spawnSync(adbPath, fallbackAdbArgs, {stdio: 'inherit'});
- } catch (e) {
- console.log(
- chalk.red('adb invocation failed. Do you have adb in your PATH?'),
- );
- // stderr is automatically piped from the gradle process, so the user
- // should see the error already, there is no need to do
- // `console.log(e.stderr)`
- return Promise.reject();
- }
- }
-}
-
-function startServerInNewWindow(port, terminal = process.env.REACT_TERMINAL) {
- // set up OS-specific filenames and commands
- const isWindows = /^win/.test(process.platform);
- const scriptFile = isWindows
- ? 'launchPackager.bat'
- : 'launchPackager.command';
- const packagerEnvFilename = isWindows ? '.packager.bat' : '.packager.env';
- const portExportContent = isWindows
- ? `set RCT_METRO_PORT=${port}`
- : `export RCT_METRO_PORT=${port}`;
-
- // set up the launchpackager.(command|bat) file
- const scriptsDir = path.resolve(__dirname, '..', '..', 'scripts');
- const launchPackagerScript = path.resolve(scriptsDir, scriptFile);
- const procConfig = {cwd: scriptsDir};
-
- // set up the .packager.(env|bat) file to ensure the packager starts on the right port
- const packagerEnvFile = path.join(
- __dirname,
- '..',
- '..',
- 'scripts',
- packagerEnvFilename,
- );
-
- // ensure we overwrite file by passing the 'w' flag
- fs.writeFileSync(packagerEnvFile, portExportContent, {
- encoding: 'utf8',
- flag: 'w',
- });
-
- if (process.platform === 'darwin') {
- if (terminal) {
- return child_process.spawnSync(
- 'open',
- ['-a', terminal, launchPackagerScript],
- procConfig,
- );
- }
- return child_process.spawnSync('open', [launchPackagerScript], procConfig);
- } else if (process.platform === 'linux') {
- if (terminal) {
- procConfig.detached = true;
- return child_process.spawn(
- terminal,
- ['-e', 'sh ' + launchPackagerScript],
- procConfig,
- );
- }
- // By default, the child shell process will be attached to the parent
- procConfig.detached = false;
- return child_process.spawn('sh', [launchPackagerScript], procConfig);
- } else if (/^win/.test(process.platform)) {
- procConfig.detached = true;
- procConfig.stdio = 'ignore';
- return child_process.spawn(
- 'cmd.exe',
- ['/C', launchPackagerScript],
- procConfig,
- );
- } else {
- console.log(
- chalk.red(
- `Cannot start the packager. Unknown platform ${process.platform}`,
- ),
- );
- }
-}
-
-module.exports = {
- name: 'run-android',
- description:
- 'builds your app and starts it on a connected Android emulator or device',
- func: runAndroid,
- options: [
- {
- command: '--install-debug',
- },
- {
- command: '--root [string]',
- description:
- 'Override the root directory for the android build (which contains the android directory)',
- default: '',
- },
- {
- command: '--flavor [string]',
- description: '--flavor has been deprecated. Use --variant instead',
- },
- {
- command: '--variant [string]',
- },
- {
- command: '--appFolder [string]',
- description:
- 'Specify a different application folder name for the android source.',
- default: 'app',
- },
- {
- command: '--appId [string]',
- description: 'Specify an applicationId to launch after build.',
- default: '',
- },
- {
- command: '--appIdSuffix [string]',
- description: 'Specify an applicationIdSuffix to launch after build.',
- default: '',
- },
- {
- command: '--main-activity [string]',
- description: 'Name of the activity to start',
- default: 'MainActivity',
- },
- {
- command: '--deviceId [string]',
- description:
- 'builds your app and starts it on a specific device/simulator with the ' +
- 'given device id (listed by running "adb devices" on the command line).',
- },
- {
- command: '--no-packager',
- description: 'Do not launch packager while building',
- },
- {
- command: '--port [number]',
- default: process.env.RCT_METRO_PORT || 8081,
- parse: (val: string) => Number(val),
- },
- {
- command: '--terminal [string]',
- description:
- 'Launches the Metro Bundler in a new window using the specified terminal path.',
- default: '',
- },
- ],
-};

local-cli/runIOS/findMatchingSimulator.js

@@ -1,91 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-/**
- * Takes in a parsed simulator list and a desired name, and returns an object with the matching simulator. The desired
- * name can optionally include the iOS version in between parenthesis after the device name. Ex: "iPhone 6 (9.2)" in
- * which case it'll attempt to find a simulator with the exact version specified.
- *
- * If the simulatorString argument is null, we'll go into default mode and return the currently booted simulator, or if
- * none is booted, it will be the first in the list.
- *
- * @param Object simulators a parsed list from `xcrun simctl list --json devices` command
- * @param String|null simulatorString the string with the name of desired simulator. If null, it will use the currently
- * booted simulator, or if none are booted, the first in the list.
- * @returns {Object} {udid, name, version}
- */
-function findMatchingSimulator(simulators, simulatorString) {
- if (!simulators.devices) {
- return null;
- }
- const devices = simulators.devices;
-
- const parsedSimulatorName = simulatorString ? simulatorString.match(/(.*)? (?:\((.*)?\))?/) : [];
- if (parsedSimulatorName[2] !== undefined) {
- var simulatorVersion = parsedSimulatorName[2];
- var simulatorName = parsedSimulatorName[1];
- } else {
- simulatorName = simulatorString;
- }
-
- var match;
- for (let version in devices) {
- // Making sure the version of the simulator is an iOS or tvOS (Removes Apple Watch, etc)
- if (!version.startsWith('iOS') && !version.startsWith('tvOS')) {
- continue;
- }
- if (simulatorVersion && !version.endsWith(simulatorVersion)) {
- continue;
- }
- for (let i in devices[version]) {
- let simulator = devices[version][i];
- // Skipping non-available simulator
- if (
- simulator.availability !== '(available)' &&
- simulator.isAvailable !== 'YES'
- ) {
- continue;
- }
- let booted = simulator.state === 'Booted';
- if (booted && simulatorName === null) {
- return {
- udid: simulator.udid,
- name: simulator.name,
- booted,
- version,
- };
- }
- if (simulator.name === simulatorName && !match) {
- match = {
- udid: simulator.udid,
- name: simulator.name,
- booted,
- version,
- };
- }
- // Keeps track of the first available simulator for use if we can't find one above.
- if (simulatorName === null && !match) {
- match = {
- udid: simulator.udid,
- name: simulator.name,
- booted,
- version,
- };
- }
- }
- }
- if (match) {
- return match;
- }
- return null;
-}
-
-module.exports = findMatchingSimulator;

local-cli/runIOS/findXcodeProject.js

@@ -1,43 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow strict
- */
-
-'use strict';
-
-const path = require('path');
-
-type ProjectInfo = {
- name: string,
- isWorkspace: boolean,
-};
-
-function findXcodeProject(files: Array<string>): ?ProjectInfo {
- const sortedFiles = files.sort();
- for (let i = sortedFiles.length - 1; i >= 0; i--) {
- const fileName = files[i];
- const ext = path.extname(fileName);
-
- if (ext === '.xcworkspace') {
- return {
- name: fileName,
- isWorkspace: true,
- };
- }
- if (ext === '.xcodeproj') {
- return {
- name: fileName,
- isWorkspace: false,
- };
- }
- }
-
- return null;
-}
-
-module.exports = findXcodeProject;

local-cli/runIOS/parseIOSDevicesList.js

@@ -1,38 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow strict
- */
-
-'use strict';
-
-type IOSDeviceInfo = {
- name: string,
- udid: string,
- version: string,
-};
-
-/**
- * Parses the output of `xcrun simctl list devices` command
- */
-function parseIOSDevicesList(text: string): Array<IOSDeviceInfo> {
- const devices = [];
- text.split('\n').forEach(line => {
- const device = line.match(/(.*?) \((.*?)\) \[(.*?)\]/);
- const noSimulator = line.match(/(.*?) \((.*?)\) \[(.*?)\] \((.*?)\)/);
- if (device != null && noSimulator == null) {
- var name = device[1];
- var version = device[2];
- var udid = device[3];
- devices.push({udid, name, version});
- }
- });
-
- return devices;
-}
-
-module.exports = parseIOSDevicesList;

local-cli/runIOS/runIOS.js

@@ -1,455 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const child_process = require('child_process');
-const fs = require('fs');
-const path = require('path');
-const findXcodeProject = require('./findXcodeProject');
-const findReactNativeScripts = require('../util/findReactNativeScripts');
-const parseIOSDevicesList = require('./parseIOSDevicesList');
-const findMatchingSimulator = require('./findMatchingSimulator');
-const getBuildPath = function(configuration = 'Debug', appName, isDevice) {
- let device;
-
- if (isDevice) {
- device = 'iphoneos';
- } else if (appName.toLowerCase().includes('tvos')) {
- device = 'appletvsimulator';
- } else {
- device = 'iphonesimulator';
- }
-
- return `build/Build/Products/${configuration}-${device}/${appName}.app`;
-};
-const xcprettyAvailable = function() {
- try {
- child_process.execSync('xcpretty --version', {
- stdio: [0, 'pipe', 'ignore'],
- });
- } catch (error) {
- return false;
- }
- return true;
-};
-
-function runIOS(argv, config, args) {
- if (!fs.existsSync(args.projectPath)) {
- const reactNativeScriptsPath = findReactNativeScripts();
- if (reactNativeScriptsPath) {
- child_process.spawnSync(
- reactNativeScriptsPath,
- ['ios'].concat(process.argv.slice(1)),
- {stdio: 'inherit'},
- );
- return;
- } else {
- throw new Error(
- 'iOS project folder not found. Are you sure this is a React Native project?',
- );
- }
- }
- process.chdir(args.projectPath);
- const xcodeProject = findXcodeProject(fs.readdirSync('.'));
- if (!xcodeProject) {
- throw new Error('Could not find Xcode project files in ios folder');
- }
-
- const inferredSchemeName = path.basename(
- xcodeProject.name,
- path.extname(xcodeProject.name),
- );
- const scheme = args.scheme || inferredSchemeName;
- console.log(
- `Found Xcode ${xcodeProject.isWorkspace ? 'workspace' : 'project'} ${
- xcodeProject.name
- }`,
- );
- const devices = parseIOSDevicesList(
- child_process.execFileSync('xcrun', ['instruments', '-s'], {
- encoding: 'utf8',
- }),
- );
- if (args.device) {
- const selectedDevice = matchingDevice(devices, args.device);
- if (selectedDevice) {
- return runOnDevice(
- selectedDevice,
- scheme,
- xcodeProject,
- args.configuration,
- args.packager,
- args.verbose,
- args.port,
- );
- } else {
- if (devices && devices.length > 0) {
- console.log(
- 'Could not find device with the name: "' + args.device + '".',
- );
- console.log('Choose one of the following:');
- printFoundDevices(devices);
- } else {
- console.log('No iOS devices connected.');
- }
- }
- } else if (args.udid) {
- return runOnDeviceByUdid(args, scheme, xcodeProject, devices);
- } else {
- return runOnSimulator(xcodeProject, args, scheme);
- }
-}
-
-function runOnDeviceByUdid(args, scheme, xcodeProject, devices) {
- const selectedDevice = matchingDeviceByUdid(devices, args.udid);
- if (selectedDevice) {
- return runOnDevice(
- selectedDevice,
- scheme,
- xcodeProject,
- args.configuration,
- args.packager,
- args.verbose,
- args.port,
- );
- } else {
- if (devices && devices.length > 0) {
- console.log('Could not find device with the udid: "' + args.udid + '".');
- console.log('Choose one of the following:');
- printFoundDevices(devices);
- } else {
- console.log('No iOS devices connected.');
- }
- }
-}
-
-function runOnSimulator(xcodeProject, args, scheme) {
- return new Promise(resolve => {
- try {
- var simulators = JSON.parse(
- child_process.execFileSync(
- 'xcrun',
- ['simctl', 'list', '--json', 'devices'],
- {encoding: 'utf8'},
- ),
- );
- } catch (e) {
- throw new Error('Could not parse the simulator list output');
- }
-
- const selectedSimulator = findMatchingSimulator(simulators, args.simulator);
- if (!selectedSimulator) {
- throw new Error(`Could not find ${args.simulator} simulator`);
- }
-
- /**
- * Booting simulator through `xcrun simctl boot` will boot it in the `headless` mode
- * (running in the background).
- *
- * In order for user to see the app and the simulator itself, we have to make sure
- * that the Simulator.app is running.
- *
- * We also pass it `-CurrentDeviceUDID` so that when we launch it for the first time,
- * it will not boot the "default" device, but the one we set. If the app is already running,
- * this flag has no effect.
- */
- const activeDeveloperDir = child_process
- .execFileSync('xcode-select', ['-p'], {encoding: 'utf8'})
- .trim();
- child_process.execFileSync('open', [
- `${activeDeveloperDir}/Applications/Simulator.app`,
- '--args',
- '-CurrentDeviceUDID',
- selectedSimulator.udid,
- ]);
-
- if (!selectedSimulator.booted) {
- const simulatorFullName = formattedDeviceName(selectedSimulator);
- console.log(`Launching ${simulatorFullName}...`);
- try {
- child_process.spawnSync('xcrun', [
- 'instruments',
- '-w',
- selectedSimulator.udid,
- ]);
- } catch (e) {
- // instruments always fail with 255 because it expects more arguments,
- // but we want it to only launch the simulator
- }
- }
-
- buildProject(
- xcodeProject,
- selectedSimulator.udid,
- scheme,
- args.configuration,
- args.packager,
- args.verbose,
- args.port,
- ).then(appName => resolve({udid: selectedSimulator.udid, appName}));
- }).then(({udid, appName}) => {
- if (!appName) {
- appName = scheme;
- }
- let appPath = getBuildPath(args.configuration, appName);
- console.log(`Installing ${appPath}`);
- child_process.spawnSync('xcrun', ['simctl', 'install', udid, appPath], {
- stdio: 'inherit',
- });
-
- const bundleID = child_process
- .execFileSync(
- '/usr/libexec/PlistBuddy',
- ['-c', 'Print:CFBundleIdentifier', path.join(appPath, 'Info.plist')],
- {encoding: 'utf8'},
- )
- .trim();
-
- console.log(`Launching ${bundleID}`);
- child_process.spawnSync('xcrun', ['simctl', 'launch', udid, bundleID], {
- stdio: 'inherit',
- });
- });
-}
-
-function runOnDevice(
- selectedDevice,
- scheme,
- xcodeProject,
- configuration,
- launchPackager,
- verbose,
- port,
-) {
- return buildProject(
- xcodeProject,
- selectedDevice.udid,
- scheme,
- configuration,
- launchPackager,
- verbose,
- port,
- ).then(appName => {
- if (!appName) {
- appName = scheme;
- }
- const iosDeployInstallArgs = [
- '--bundle',
- getBuildPath(configuration, appName, true),
- '--id',
- selectedDevice.udid,
- '--justlaunch',
- ];
- console.log(
- `installing and launching your app on ${selectedDevice.name}...`,
- );
- const iosDeployOutput = child_process.spawnSync(
- 'ios-deploy',
- iosDeployInstallArgs,
- {encoding: 'utf8'},
- );
- if (iosDeployOutput.error) {
- console.log('');
- console.log('** INSTALLATION FAILED **');
- console.log('Make sure you have ios-deploy installed globally.');
- console.log('(e.g "npm install -g ios-deploy")');
- } else {
- console.log('** INSTALLATION SUCCEEDED **');
- }
- });
-}
-
-function buildProject(
- xcodeProject,
- udid,
- scheme,
- configuration = 'Debug',
- launchPackager = false,
- verbose,
- port,
-) {
- return new Promise((resolve, reject) => {
- var xcodebuildArgs = [
- xcodeProject.isWorkspace ? '-workspace' : '-project',
- xcodeProject.name,
- '-configuration',
- configuration,
- '-scheme',
- scheme,
- '-destination',
- `id=${udid}`,
- '-derivedDataPath',
- 'build',
- ];
- console.log(`Building using "xcodebuild ${xcodebuildArgs.join(' ')}"`);
- let xcpretty;
- if (!verbose) {
- xcpretty =
- xcprettyAvailable() &&
- child_process.spawn('xcpretty', [], {
- stdio: ['pipe', process.stdout, process.stderr],
- });
- }
- const buildProcess = child_process.spawn(
- 'xcodebuild',
- xcodebuildArgs,
- getProcessOptions(launchPackager, port),
- );
- let buildOutput = '';
- buildProcess.stdout.on('data', function(data) {
- buildOutput += data.toString();
- if (xcpretty) {
- xcpretty.stdin.write(data);
- } else {
- console.log(data.toString());
- }
- });
- buildProcess.stderr.on('data', function(data) {
- console.error(data.toString());
- });
- buildProcess.on('close', function(code) {
- if (xcpretty) {
- xcpretty.stdin.end();
- }
- //FULL_PRODUCT_NAME is the actual file name of the app, which actually comes from the Product Name in the build config, which does not necessary match a scheme name, example output line: export FULL_PRODUCT_NAME="Super App Dev.app"
- let productNameMatch = /export FULL_PRODUCT_NAME="?(.+).app"?$/m.exec(
- buildOutput,
- );
- if (
- productNameMatch &&
- productNameMatch.length &&
- productNameMatch.length > 1
- ) {
- return resolve(productNameMatch[1]); //0 is the full match, 1 is the app name
- }
- return buildProcess.error ? reject(buildProcess.error) : resolve();
- });
- });
-}
-
-function matchingDevice(devices, deviceName) {
- if (deviceName === true && devices.length === 1) {
- console.log(
- `Using first available device ${
- devices[0].name
- } due to lack of name supplied.`,
- );
- return devices[0];
- }
- for (let i = devices.length - 1; i >= 0; i--) {
- if (
- devices[i].name === deviceName ||
- formattedDeviceName(devices[i]) === deviceName
- ) {
- return devices[i];
- }
- }
-}
-
-function matchingDeviceByUdid(devices, udid) {
- for (let i = devices.length - 1; i >= 0; i--) {
- if (devices[i].udid === udid) {
- return devices[i];
- }
- }
-}
-
-function formattedDeviceName(simulator) {
- return `${simulator.name} (${simulator.version})`;
-}
-
-function printFoundDevices(devices) {
- for (let i = devices.length - 1; i >= 0; i--) {
- console.log(devices[i].name + ' Udid: ' + devices[i].udid);
- }
-}
-
-function getProcessOptions(launchPackager, port) {
- if (launchPackager) {
- return {
- env: {...process.env, RCT_METRO_PORT: port},
- };
- }
-
- return {
- env: {...process.env, RCT_NO_LAUNCH_PACKAGER: true},
- };
-}
-
-module.exports = {
- name: 'run-ios',
- description: 'builds your app and starts it on iOS simulator',
- func: runIOS,
- examples: [
- {
- desc: 'Run on a different simulator, e.g. iPhone 5',
- cmd: 'react-native run-ios --simulator "iPhone 5"',
- },
- {
- desc: 'Pass a non-standard location of iOS directory',
- cmd: 'react-native run-ios --project-path "./app/ios"',
- },
- {
- desc: "Run on a connected device, e.g. Max's iPhone",
- cmd: 'react-native run-ios --device "Max\'s iPhone"',
- },
- {
- desc: 'Run on the AppleTV simulator',
- cmd:
- 'react-native run-ios --simulator "Apple TV" --scheme "helloworld-tvOS"',
- },
- ],
- options: [
- {
- command: '--simulator [string]',
- description:
- 'Explicitly set simulator to use. Optionally include iOS version between' +
- 'parenthesis at the end to match an exact version: "iPhone 6 (10.0)"',
- default: 'iPhone X',
- },
- {
- command: '--configuration [string]',
- description: 'Explicitly set the scheme configuration to use',
- },
- {
- command: '--scheme [string]',
- description: 'Explicitly set Xcode scheme to use',
- },
- {
- command: '--project-path [string]',
- description:
- 'Path relative to project root where the Xcode project ' +
- "(.xcodeproj) lives. The default is 'ios'.",
- default: 'ios',
- },
- {
- command: '--device [string]',
- description:
- 'Explicitly set device to use by name. The value is not required if you have a single device connected.',
- },
- {
- command: '--udid [string]',
- description: 'Explicitly set device to use by udid',
- },
- {
- command: '--no-packager',
- description: 'Do not launch packager while building',
- },
- {
- command: '--verbose',
- description: 'Do not use xcpretty even if installed',
- },
- {
- command: '--port [number]',
- default: process.env.RCT_METRO_PORT || 8081,
- parse: (val: string) => Number(val),
- },
- ],
-};

local-cli/server/checkNodeVersion.js

@@ -1,46 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * Be mindful that this script may be run by legacy NodeJS runtimes. Keep this
- * script ES5 compatible (e.g. do not insert the `@format` pragma here which
- * may introduce non-ES5 compatible syntax.)
- *
- */
-
-'use strict';
-
-var chalk = require('chalk');
-var formatBanner = require('metro-core/src/formatBanner');
-var semver = require('semver');
-
-module.exports = function() {
- if (!semver.satisfies(process.version, '>=8.3')) {
- var engine = semver.satisfies(process.version, '<1') ? 'Node' : 'io.js';
-
- var message =
- 'You are currently running ' +
- engine +
- ' ' +
- process.version +
- '.\n' +
- '\n' +
- 'React Native runs on Node 8.3 or newer. There are several ways to ' +
- 'upgrade Node.js depending on your preference.\n' +
- '\n' +
- 'nvm: nvm install 8.3 --reinstall-packages-from=node\n' +
- 'Homebrew: brew update && brew upgrade node\n' +
- 'Installer: download from https://nodejs.org/\n';
- console.log(
- formatBanner(message, {
- chalkFunction: chalk.green,
- marginLeft: 1,
- marginRight: 1,
- paddingBottom: 1,
- })
- );
- process.exit(1);
- }
-};

local-cli/server/middleware/copyToClipBoardMiddleware.js

@@ -1,29 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const copyToClipBoard = require('../util/copyToClipBoard');
-var chalk = require('chalk');
-
-/**
- * Handle the request from JS to copy contents onto host system clipboard.
- * This is only supported on Mac for now.
- */
-module.exports = function(req, res, next) {
- if (req.url === '/copy-to-clipboard') {
- var ret = copyToClipBoard(req.rawBody);
- if (!ret) {
- console.warn(chalk.red('Copy button is not supported on this platform!'));
- }
- res.end('OK');
- } else {
- next();
- }
-};

local-cli/server/middleware/getDevToolsMiddleware.js

@@ -1,70 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-'use strict';
-
-const launchChrome = require('../util/launchChrome');
-
-const {exec} = require('child_process');
-
-function launchChromeDevTools(host, args = '') {
- var debuggerURL = 'http://' + host + '/debugger-ui' + args;
- console.log('Launching Dev Tools...');
- launchChrome(debuggerURL);
-}
-
-function escapePath(pathname) {
- // " Can escape paths with spaces in OS X, Windows, and *nix
- return '"' + pathname + '"';
-}
-
-function launchDevTools({host, watchFolders}, isChromeConnected) {
- // Explicit config always wins
- var customDebugger = process.env.REACT_DEBUGGER;
- if (customDebugger) {
- var folders = watchFolders.map(escapePath).join(' ');
- var command = customDebugger + ' ' + folders;
- console.log('Starting custom debugger by executing: ' + command);
- exec(command, function(error, stdout, stderr) {
- if (error !== null) {
- console.log('Error while starting custom debugger: ' + error);
- }
- });
- } else if (!isChromeConnected()) {
- // Dev tools are not yet open; we need to open a session
- launchChromeDevTools(host);
- }
-}
-
-module.exports = function(options, isChromeConnected) {
- return function(req, res, next) {
- var host = req.headers.host;
- if (req.url === '/launch-safari-devtools') {
- // TODO: remove `console.log` and dev tools binary
- console.log(
- 'We removed support for Safari dev-tools. ' +
- 'If you still need this, please let us know.',
- );
- } else if (req.url === '/launch-chrome-devtools') {
- // TODO: Remove this case in the future
- console.log(
- 'The method /launch-chrome-devtools is deprecated. You are ' +
- ' probably using an application created with an older CLI with the ' +
- ' packager of a newer CLI. Please upgrade your application: ' +
- 'https://facebook.github.io/react-native/docs/upgrading.html',
- );
- launchDevTools(options, isChromeConnected);
- res.end('OK');
- } else if (req.url === '/launch-js-devtools') {
- launchDevTools({...options, host}, isChromeConnected);
- res.end('OK');
- } else {
- next();
- }
- };
-};

local-cli/server/middleware/index.html

@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <title>React Native</title>
-</head>
-<body>
- <p>React Native packager is running.</p>
- <p><a href="http://facebook.github.io/react-native/">Visit documentation</a></p>
-</body>
-</html>

local-cli/server/middleware/indexPage.js

@@ -1,21 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const fs = require('fs');
-const path = require('path');
-
-module.exports = function(req, res, next) {
- if (req.url === '/') {
- res.end(fs.readFileSync(path.join(__dirname, 'index.html')));
- } else {
- next();
- }
-};

local-cli/server/middleware/loadRawBodyMiddleware.js

@@ -1,23 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-module.exports = function(req, res, next) {
- req.rawBody = '';
- req.setEncoding('utf8');
-
- req.on('data', function(chunk) {
- req.rawBody += chunk;
- });
-
- req.on('end', function() {
- next();
- });
-};

local-cli/server/middleware/MiddlewareManager.js

@@ -1,69 +0,0 @@
-/**
- * Copyright (c) 2013-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @strict
- * @flow
- */
-
-const compression = require('compression');
-const connect = require('connect');
-const errorhandler = require('errorhandler');
-const path = require('path');
-const serveStatic = require('serve-static');
-const WebSocketServer = require('ws').Server;
-
-const indexPageMiddleware = require('./indexPage');
-const copyToClipBoardMiddleware = require('./copyToClipBoardMiddleware');
-const loadRawBodyMiddleware = require('./loadRawBodyMiddleware');
-const openStackFrameInEditorMiddleware = require('./openStackFrameInEditorMiddleware');
-const statusPageMiddleware = require('./statusPageMiddleware');
-const systraceProfileMiddleware = require('./systraceProfileMiddleware');
-const getDevToolsMiddleware = require('./getDevToolsMiddleware');
-
-type Options = {
- +watchFolders: $ReadOnlyArray<string>,
- +host?: string,
-}
-
-type WebSocketProxy = {
- server: WebSocketServer,
- isChromeConnected: () => boolean,
-};
-
-type Connect = $Call<connect>;
-
-module.exports = class MiddlewareManager {
- app: Connect;
- options: Options;
-
- constructor(options: Options) {
- const debuggerUIFolder = path.join(__dirname, '..', 'util', 'debugger-ui');
-
- this.options = options;
- this.app = connect()
- .use(loadRawBodyMiddleware)
- .use(compression())
- .use('/debugger-ui', serveStatic(debuggerUIFolder))
- .use(openStackFrameInEditorMiddleware(this.options))
- .use(copyToClipBoardMiddleware)
- .use(statusPageMiddleware)
- .use(systraceProfileMiddleware)
- .use(indexPageMiddleware)
- .use(errorhandler());
- }
-
- serveStatic = (folder: string) => {
- this.app.use(serveStatic(folder));
- };
-
- getConnectInstance = () => this.app;
-
- attachDevToolsSocket = (socket: WebSocketProxy) => {
- this.app.use(
- getDevToolsMiddleware(this.options, () => socket.isChromeConnected()),
- );
- };
-};

local-cli/server/middleware/openStackFrameInEditorMiddleware.js

@@ -1,24 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const launchEditor = require('../util/launchEditor');
-
-module.exports = function({watchFolders}) {
- return function(req, res, next) {
- if (req.url === '/open-stack-frame') {
- const frame = JSON.parse(req.rawBody);
- launchEditor(frame.file, frame.lineNumber, watchFolders);
- res.end('OK');
- } else {
- next();
- }
- };
-};

local-cli/server/middleware/statusPageMiddleware.js

@@ -1,22 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-/**
- * Status page so that anyone who needs to can verify that the packager is
- * running on 8081 and not another program / service.
- */
-module.exports = function(req, res, next) {
- if (req.url === '/status') {
- res.end('packager-status:running');
- } else {
- next();
- }
-};

local-cli/server/middleware/systraceProfileMiddleware.js

@@ -1,32 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const fs = require('fs');
-
-module.exports = function(req, res, next) {
- if (req.url !== '/systrace') {
- next();
- return;
- }
-
- console.log('Dumping profile information...');
- var dumpName = '/tmp/dump_' + Date.now() + '.json';
- fs.writeFileSync(dumpName, req.rawBody);
- var response =
- 'Your profile was saved at:\n' +
- dumpName +
- '\n\n' +
- 'On Google Chrome navigate to chrome://tracing and then click on "load" ' +
- 'to load and visualise your profile.\n\n' +
- 'This message is also printed to your console by the packager so you can copy it :)';
- console.log(response);
- res.end(response);
-};

local-cli/server/middleware/unless.js

@@ -1,20 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-module.exports = (url, middleware) => {
- return (req, res, next) => {
- if (req.url === url || req.url.startsWith(url + '/')) {
- middleware(req, res, next);
- } else {
- next();
- }
- };
-};

local-cli/server/runServer.js

@@ -1,124 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @flow
- * @format
- */
-
-'use strict';
-
-require('../../setupBabel')();
-
-const Metro = require('metro');
-
-const {Terminal} = require('metro-core');
-
-const messageSocket = require('./util/messageSocket');
-const morgan = require('morgan');
-const path = require('path');
-const webSocketProxy = require('./util/webSocketProxy');
-const MiddlewareManager = require('./middleware/MiddlewareManager');
-
-/* $FlowFixMe(site=react_native_oss) */
-import type {ConfigT} from 'metro-config/src/configTypes.flow';
-
-export type Args = {|
- +assetExts: $ReadOnlyArray<string>,
- +cert: string,
- +customLogReporterPath?: string,
- +host: string,
- +https: boolean,
- +maxWorkers: number,
- +key: string,
- +nonPersistent: boolean,
- +platforms: $ReadOnlyArray<string>,
- +port: number,
- +projectRoot: string,
- +providesModuleNodeModules: Array<string>,
- +resetCache: boolean,
- +sourceExts: $ReadOnlyArray<string>,
- +transformer?: string,
- +verbose: boolean,
- +watchFolders: $ReadOnlyArray<string>,
-|};
-
-async function runServer(args: Args, config: ConfigT) {
- const terminal = new Terminal(process.stdout);
- const ReporterImpl = getReporterImpl(args.customLogReporterPath || null);
- const reporter = new ReporterImpl(terminal);
- const middlewareManager = new MiddlewareManager(args);
-
- middlewareManager.getConnectInstance().use(morgan('combined'));
-
- args.watchFolders.forEach(middlewareManager.serveStatic);
-
- // $FlowFixMe Metro configuration is immutable.
- config.maxWorkers = args.maxWorkers;
- // $FlowFixMe Metro configuration is immutable.
- config.server.port = args.port;
- // $FlowFixMe Metro configuration is immutable.
- config.reporter = reporter;
- // $FlowFixMe Metro configuration is immutable.
- config.resetCache = args.resetCache;
- // $FlowFixMe Metro configuration is immutable.
- config.projectRoot = args.projectRoot;
- // $FlowFixMe Metro configuration is immutable.
- config.watchFolders = args.watchFolders.slice(0);
- // $FlowFixMe Metro configuration is immutable.
- config.server.enhanceMiddleware = middleware =>
- middlewareManager.getConnectInstance().use(middleware);
-
- const serverInstance = await Metro.runServer(config, {
- host: args.host,
- secure: args.https,
- secureCert: args.cert,
- secureKey: args.key,
- hmrEnabled: true,
- });
-
- const wsProxy = webSocketProxy.attachToServer(
- serverInstance,
- '/debugger-proxy',
- );
- const ms = messageSocket.attachToServer(serverInstance, '/message');
- middlewareManager.attachDevToolsSocket(wsProxy);
- middlewareManager.attachDevToolsSocket(ms);
-
- // In Node 8, the default keep-alive for an HTTP connection is 5 seconds. In
- // early versions of Node 8, this was implemented in a buggy way which caused
- // some HTTP responses (like those containing large JS bundles) to be
- // terminated early.
- //
- // As a workaround, arbitrarily increase the keep-alive from 5 to 30 seconds,
- // which should be enough to send even the largest of JS bundles.
- //
- // For more info: https://github.com/nodejs/node/issues/13391
- //
- // $FlowFixMe (site=react_native_fb)
- serverInstance.keepAliveTimeout = 30000;
-}
-
-function getReporterImpl(customLogReporterPath: ?string) {
- if (customLogReporterPath == null) {
- return require('metro/src/lib/TerminalReporter');
- }
- try {
- // First we let require resolve it, so we can require packages in node_modules
- // as expected. eg: require('my-package/reporter');
- /* $FlowFixMe: can't type dynamic require */
- return require(customLogReporterPath);
- } catch (e) {
- if (e.code !== 'MODULE_NOT_FOUND') {
- throw e;
- }
- // If that doesn't work, then we next try relative to the cwd, eg:
- // require('./reporter');
- /* $FlowFixMe: can't type dynamic require */
- return require(path.resolve(customLogReporterPath));
- }
-}
-
-module.exports = runServer;

local-cli/server/server.js

@@ -1,130 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow
- */
-
-'use strict';
-
-const runServer = require('./runServer');
-
-import type {RNConfig} from '../core';
-/* $FlowFixMe(site=react_native_oss) */
-import type {ConfigT} from 'metro-config/src/configTypes.flow';
-import type {Args as RunServerArgs} from './runServer';
-
-/**
- * Starts the React Native Packager Server.
- */
-function server(argv: mixed, config: RNConfig, args: RunServerArgs) {
- /* $FlowFixMe(site=react_native_fb) ConfigT shouldn't be extendable. */
- const configT: ConfigT = config;
- runServer(args, configT);
-}
-
-module.exports = {
- name: 'start',
- func: server,
- description: 'starts the webserver',
- options: [
- {
- command: '--port [number]',
- parse: (val: string) => Number(val),
- default: (config: ConfigT) => config.server.port,
- },
- {
- command: '--host [string]',
- default: '',
- },
- {
- command: '--projectRoot [string]',
- description: 'Specify the main project root',
- default: (config: ConfigT) => config.projectRoot,
- },
- {
- command: '--watchFolders [list]',
- description:
- 'Specify any additional folders to be added to the watch list',
- parse: (val: string) => val.split(','),
- default: (config: ConfigT) => config.watchFolders,
- },
- {
- command: '--assetExts [list]',
- description:
- 'Specify any additional asset extensions to be used by the packager',
- parse: (val: string) => val.split(','),
- default: (config: ConfigT) => config.resolver.assetExts,
- },
- {
- command: '--sourceExts [list]',
- description:
- 'Specify any additional source extensions to be used by the packager',
- parse: (val: string) => val.split(','),
- default: (config: ConfigT) => config.resolver.sourceExts,
- },
- {
- command: '--platforms [list]',
- description:
- 'Specify any additional platforms to be used by the packager',
- parse: (val: string) => val.split(','),
- default: (config: ConfigT) => config.resolver.platforms,
- },
- {
- command: '--providesModuleNodeModules [list]',
- description:
- 'Specify any npm packages that import dependencies with providesModule',
- parse: (val: string) => val.split(','),
- default: (config: ConfigT) => config.resolver.providesModuleNodeModules,
- },
- {
- command: '--max-workers [number]',
- description:
- 'Specifies the maximum number of workers the worker-pool ' +
- 'will spawn for transforming files. This defaults to the number of the ' +
- 'cores available on your machine.',
- default: (config: ConfigT) => config.maxWorkers,
- parse: (workers: string) => Number(workers),
- },
- {
- command: '--skipflow',
- description: 'Disable flow checks',
- },
- {
- command: '--nonPersistent',
- description: 'Disable file watcher',
- },
- {
- command: '--transformer [string]',
- description: 'Specify a custom transformer to be used',
- },
- {
- command: '--reset-cache, --resetCache',
- description: 'Removes cached files',
- },
- {
- command: '--custom-log-reporter-path, --customLogReporterPath [string]',
- description:
- 'Path to a JavaScript file that exports a log reporter as a replacement for TerminalReporter',
- },
- {
- command: '--verbose',
- description: 'Enables logging',
- },
- {
- command: '--https',
- description: 'Enables https connections to the server',
- },
- {
- command: '--key [path]',
- description: 'Path to custom SSL key',
- },
- {
- command: '--cert [path]',
- description: 'Path to custom SSL cert',
- },
- ],
-};

local-cli/server/util/copyToClipBoard.js

@@ -1,41 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-var child_process = require('child_process');
-var spawn = child_process.spawn;
-var path = require('path');
-var fs = require('fs');
-
-const xsel = path.join(__dirname, 'external/xsel');
-fs.chmodSync(xsel, '0755');
-/**
- * Copy the content to host system clipboard.
- */
-function copyToClipBoard(content) {
- switch (process.platform) {
- case 'darwin':
- var child = spawn('pbcopy', []);
- child.stdin.end(new Buffer(content, 'utf8'));
- return true;
- case 'win32':
- var child = spawn('clip', []);
- child.stdin.end(new Buffer(content, 'utf8'));
- return true;
- case 'linux':
- var child = spawn(xsel, ['--clipboard', '--input']);
- child.stdin.end(new Buffer(content, 'utf8'));
- return true;
- default:
- return false;
- }
-}
-
-module.exports = copyToClipBoard;

local-cli/server/util/debugger-ui/debuggerWorker.js

@@ -1,86 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-/* global __fbBatchedBridge, self, importScripts, postMessage, onmessage: true */
-/* eslint no-unused-vars: 0 */
-
-'use strict';
-
-onmessage = (function() {
- var visibilityState;
- var showVisibilityWarning = (function() {
- var hasWarned = false;
- return function() {
- // Wait until `YellowBox` gets initialized before displaying the warning.
- if (hasWarned || console.warn.toString().includes('[native code]')) {
- return;
- }
- hasWarned = true;
- console.warn(
- 'Remote debugger is in a background tab which may cause apps to ' +
- 'perform slowly. Fix this by foregrounding the tab (or opening it in ' +
- 'a separate window).',
- );
- };
- })();
-
- var messageHandlers = {
- executeApplicationScript: function(message, sendReply) {
- for (var key in message.inject) {
- self[key] = JSON.parse(message.inject[key]);
- }
- var error;
- try {
- importScripts(message.url);
- } catch (err) {
- error = err.message;
- }
- sendReply(null /* result */, error);
- },
- setDebuggerVisibility: function(message) {
- visibilityState = message.visibilityState;
- },
- };
-
- return function(message) {
- if (visibilityState === 'hidden') {
- showVisibilityWarning();
- }
-
- var object = message.data;
-
- var sendReply = function(result, error) {
- postMessage({replyID: object.id, result: result, error: error});
- };
-
- var handler = messageHandlers[object.method];
- if (handler) {
- // Special cased handlers
- handler(object, sendReply);
- } else {
- // Other methods get called on the bridge
- var returnValue = [[], [], [], 0];
- var error;
- try {
- if (typeof __fbBatchedBridge === 'object') {
- returnValue = __fbBatchedBridge[object.method].apply(
- null,
- object.arguments,
- );
- } else {
- error = 'Failed to call function, __fbBatchedBridge is undefined';
- }
- } catch (err) {
- error = err.message;
- } finally {
- sendReply(JSON.stringify(returnValue), error);
- }
- }
- };
-})();

local-cli/server/util/debugger-ui/DeltaPatcher.js

@@ -1,130 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-/**
- * This file is a copy of the reference `DeltaPatcher`, located in
- * metro. The reason to not reuse that file is that in this context
- * we cannot have flow annotations or CJS syntax (since this file is directly)
- * injected into a static HTML page.
- *
- * TODO: Find a simple and lightweight way to compile `DeltaPatcher` to avoid
- * having this duplicated file.
- */
-(function(global) {
- 'use strict';
-
- /**
- * This is a reference client for the Delta Bundler: it maintains cached the
- * last patched bundle delta and it's capable of applying new Deltas received
- * from the Bundler.
- */
- class DeltaPatcher {
- constructor() {
- this._lastBundle = {
- pre: new Map(),
- post: new Map(),
- modules: new Map(),
- id: undefined,
- };
- this._initialized = false;
- this._lastNumModifiedFiles = 0;
- this._lastModifiedDate = new Date();
- }
-
- static get(id) {
- let deltaPatcher = this._deltaPatchers.get(id);
-
- if (!deltaPatcher) {
- deltaPatcher = new DeltaPatcher();
- this._deltaPatchers.set(id, deltaPatcher);
- }
-
- return deltaPatcher;
- }
-
- /**
- * Applies a Delta Bundle to the current bundle.
- */
- applyDelta(deltaBundle) {
- // Make sure that the first received delta is a fresh one.
- if (!this._initialized && !deltaBundle.reset) {
- throw new Error(
- 'DeltaPatcher should receive a fresh Delta when being initialized',
- );
- }
-
- this._initialized = true;
-
- // Reset the current delta when we receive a fresh delta.
- if (deltaBundle.reset) {
- this._lastBundle = {
- pre: new Map(),
- post: new Map(),
- modules: new Map(),
- id: undefined,
- };
- }
-
- this._lastNumModifiedFiles =
- deltaBundle.pre.size + deltaBundle.post.size + deltaBundle.delta.size;
-
- if (this._lastNumModifiedFiles > 0) {
- this._lastModifiedDate = new Date();
- }
-
- this._patchMap(this._lastBundle.pre, deltaBundle.pre);
- this._patchMap(this._lastBundle.post, deltaBundle.post);
- this._patchMap(this._lastBundle.modules, deltaBundle.delta);
-
- this._lastBundle.id = deltaBundle.id;
-
- return this;
- }
-
- getLastBundleId() {
- return this._lastBundle.id;
- }
-
- /**
- * Returns the number of modified files in the last received Delta. This is
- * currently used to populate the `X-Metro-Files-Changed-Count` HTTP header
- * when metro serves the whole JS bundle, and can potentially be removed once
- * we only send the actual deltas to clients.
- */
- getLastNumModifiedFiles() {
- return this._lastNumModifiedFiles;
- }
-
- getLastModifiedDate() {
- return this._lastModifiedDate;
- }
-
- getAllModules() {
- return [].concat(
- Array.from(this._lastBundle.pre.values()),
- Array.from(this._lastBundle.modules.values()),
- Array.from(this._lastBundle.post.values()),
- );
- }
-
- _patchMap(original, patch) {
- for (const [key, value] of patch.entries()) {
- if (value == null) {
- original.delete(key);
- } else {
- original.set(key, value);
- }
- }
- }
- }
-
- DeltaPatcher._deltaPatchers = new Map();
-
- global.DeltaPatcher = DeltaPatcher;
-})(window);

local-cli/server/util/debugger-ui/deltaUrlToBlobUrl.js

@@ -1,71 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @flow strict
- * @format
- */
-
-/* global Blob, URL: true */
-
-(function(global) {
- 'use strict';
-
- let cachedBundleUrls = new Map();
-
- /**
- * Converts the passed delta URL into an URL object containing already the
- * whole JS bundle Blob.
- */
- async function deltaUrlToBlobUrl(deltaUrl) {
- const client = global.DeltaPatcher.get(deltaUrl);
-
- const deltaBundleId = client.getLastBundleId()
- ? `&deltaBundleId=${client.getLastBundleId()}`
- : '';
-
- const data = await fetch(deltaUrl + deltaBundleId);
- const bundle = await data.json();
-
- const deltaPatcher = client.applyDelta({
- id: bundle.id,
- pre: new Map(bundle.pre),
- post: new Map(bundle.post),
- delta: new Map(bundle.delta),
- reset: bundle.reset,
- });
-
- let cachedBundle = cachedBundleUrls.get(deltaUrl);
-
- // If nothing changed, avoid recreating a bundle blob by reusing the
- // previous one.
- if (deltaPatcher.getLastNumModifiedFiles() === 0 && cachedBundle) {
- return cachedBundle;
- }
-
- // Clean up the previous bundle URL to not leak memory.
- if (cachedBundle) {
- URL.revokeObjectURL(cachedBundle);
- }
-
- // To make Source Maps work correctly, we need to add a newline between
- // modules.
- const blobContent = deltaPatcher
- .getAllModules()
- .map(module => module + '\n');
-
- // Build the blob with the whole JS bundle.
- const blob = new Blob(blobContent, {
- type: 'application/javascript',
- });
-
- const bundleContents = URL.createObjectURL(blob);
- cachedBundleUrls.set(deltaUrl, bundleContents);
-
- return bundleContents;
- }
-
- global.deltaUrlToBlobUrl = deltaUrlToBlobUrl;
-})(window || {});

local-cli/server/util/debugger-ui/index.html

@@ -1,280 +0,0 @@
-<!DOCTYPE html>
-<!--
- Copyright (c) 2015-present, Facebook, Inc.
-
- This source code is licensed under the MIT license found in the
- LICENSE file in the root directory of this source tree.
-<html>
-<head>
-<meta charset=utf-8>
-<link rel="icon" href="data:;base64,iVBORw0KGgo=">
-<title>React Native Debugger</title>
-<script src="/debugger-ui/DeltaPatcher.js"></script>
-<script src="/debugger-ui/deltaUrlToBlobUrl.js"></script>
-<script>
-/* eslint-env browser */
-'use strict';
-(function() {
-
- const isMacLike = /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform);
- const refreshShortcut = isMacLike ? '⌘R' : 'Ctrl R';
- window.onload = function() {
- if (!isMacLike) {
- document.getElementById('shortcut').innerHTML = 'Ctrl⇧J';
- }
- Page.render();
- };
-
- const Assets = {
- blueIcon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAABAJJREFUWMPNV0tIlFEU/nsaPSCrhVFZBBFRFkXvKCpCw6BFtagkWoS1CApp0YMKclHRYxNpj0UUQWUavYmeEi2MsFVS/s7oqOPo6DjqzKjpzOjpnDl35s7MP/8/vyUxFy7c/5x7z/nued5fUcwOgLGKBXIUFYqUaijHqeL0iamGaMSjPbR32IYNMpQaKEbhHlQCpibtpTN09q+HBdJQSCEK7DatWDu7QzJI1pBvrULFPyiOt0iFeWtUw2I8YB825RKEXamFLDM31yifqAIcbwO40QmQ3wIwXtUqmFwDcNQJcKeL96apOiB0LUF+0jH7u26AwUEA3wCERmsAYF+z5B9CUF1B5rmDvPeBx8AdCWOCA05zYEEdCz6JtxqB3xsbACp/M+0WWuR+F6+/9ACsqOczV90AQQSRYdEBQbo0pteJ9p1NrCAsnOYYnNc7IDIuocJRUWdyGpm+qcEgO2JcQTmrEzxkahpZdbH0aABX3LG89Q1M3243CErSGalwBkVmi7gN3SpM2+uQLrgrXLCjSfJ3Cautqk9SrEIVk0qnQfrMtrKwtxiIj70A33vZvwGcA2IGxKxE3j0E9MLHZ6ZZkqQm6Ra1XcOcjofPtwO4AtLULbhuD7DSpwjmspvNTwop8tuQ5wnK/U1+gNMYvFNqdK1QpIjGEsPY7eC0IqFvUPgrHys90MKCz7p43xy0TqaV1xSINPaLmHmNZz73yLTdljgeyhXRySLEXDsr/tYrA29tPQtqxhtZ+zkLnnjlTcns41S+sd3PtCU2Prsaz1b1AfgHOTjjAKiKaKcR4kf0dS0qmRBXyYhGg4rOLCtoBvm7oJXXP/u0VZLc98yrAeDTAHiPAGx+LQCLAJCPJp6ZAMBUVFLg5PWvOADpyHMG2GpxALwaF1C6kb+/ogvm1zJtjXABCSEgo5H20COV3+5kF5D5G4ULVooUpAL2AwH1o8x1Oi7QBOEeB0czpVYpoi71cFwcFEF4RgThDCtnC60vtDMvz8F7X/rYmrQ2DkKdNCQ/X+uQDYgE1fSzMLJQiYeVXsRZ5mUaWSg6bem70GVQD0JpmKQQzauVzYZSsrqPlVExCo+g+K7CJvUIgT0XGTLXaqYQJSnF2aIUZ0eV4jxRim+ihYpETyC3hflb7Uzb3GimFCdpRuHCsiiuGRVHNSPqCdG8ZTYtKP1mlKQdhxvLcpuk0bvgnEsCoDgYGXVmg+iGuXaz7djgQbJQPEhOtPE3AfkkSizldYlIx3KkLbXJjKCgzbSafZAkeZJ96ObAc4tG48XMOOKU/MNOmS3UkEh5mXeoTzKDR+kklbsaPTjp4ZmeoLtRxzvWyn3hVBsXpqE9SlPiWZ4SPyYp8WuWEj+n/+n3/A8emj1HwPlGOgAAAABJRU5ErkJggg==',
- grayIcon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAA9VJREFUWMPNV+dKJEEQnl93r3Avcfcavpe/zHlXzDmLYlZU1oSrYEDFsGZdVDBvUBTUuv6K6aZ34ioiW1BMT1dPdXWFr3oMI03q7u7+lZOTk5WbmxsQz5DgiOCEyRiHTFkW1hrfRXl5eX+E0qDgmGBKk7E2iG+/vHFZWdlvcaJswclPbJzC+BY6oOvTpxYfhr+6sYMh4bS9kZ+f/098EP2uzTUjoPNvOie3bV5YWEihUIjW1tZobGyMCgoKbBsUFxfT5OQkbWxs8FpxEEcjXD1hxtzR7cfHx/Tx8UGvr68ESiaTNDQ0pOTj4+P08vLCsufnZ167vb3tGg7HnECyOH1QU1PDimdmZvi9ra2Nrq6ueG59fZ22trZ4HI1GqbGxkdcsLy/T+/s7lZeXuxmR7eR6x2zv6+vjDaRysFhPq6urJGlpaQlKlbyrq4vn29vbXasjJRRmnTsuhqtBdXV1KfO6ATixLmttbeX53t5er8QM6gjnCjIdHR2sDKeSc4ODgyoEm5ubPIanpLy/v5/nmpqaPMGKERPQ6VU+wWCQlSERd3d3Of6ILxjJBpbvl5eXnBP7+/v8TWlpqV95ZhkmftuESKDFxUV6enpSrk4kEirLI5EIxx7ux4aYw1pZDaB4PE6zs7NUUlLilgsBw2wsKYKBgQFWBKVHR0d0cHDA45GREVY8NzenvAPGGMaAhoeH+Xl4eEjn5+eqbHt6epyMCBlmJ1OTIi68GdwpE6+lpUWd6P7+nqtgb29PnRRuB/BADtaTtrm5ma6vr+nt7Y2T02JAxDDbqZo8PT2lh4cHRj99HnMgIGEgECArId5TU1M8vrm5saEkwodQWQxI2Aw4OTmhx8dHmwE4OWh0dNTRAMRZGnB7e2szAGGA1yw5ELeFAOWGEFxcXFB1dbVyo4wlDAHoAGoloRwRglgsxqyXIABMhgChdAqBaxKitFB6YBgF9+tJWFFRoeA2HA6zDBiBtUhceBNjzyR0K0O4eWVlRTUgKLq7u2NlGO/s7PCmYGkgZHrZ4n1hYcEVD2QZegJRVVUVK0NJoSSRYBJ8JEkggqthmASiyspKfyDyg+LOzk5WhqcVinE/kD0BYUu3GaVAsV8zksBSW1ubMo/N9STUZQ0NDTajXJuRXzuWjUVvx+D5+XllAPLAqRsC1NJqx14XEpxcv5DAEIAVCHWNmIPOzs6ovr5eVQTyRMK074XE70omywmNCIQSxf1PyicmJlS1oAqw1go6vlcyr0tpUVERdzVcOLExkM26Bkg4PT3NfQHe+vSlNCOu5RnxY5IRv2YZ8XP6U7/n/wFyU6HBPUWxjAAAAABJRU5ErkJggg==',
- orangeIcon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAABGZJREFUWMPNV+tvFFUU30/4L/i9K0gQImoiQTQmGtEQQAWCoSGgJiZqojZCYsoHQkNIwAcJppWgHwjqLi1SHrVP2m4tfdAULKUW2NLSx0ILbGsf293ZeR7OOXc72+nM7GwbQjrJze7eufeex+/3O+euz5flAyUrliSL/esTAX9hIugPJYI5YfyMicHfQ/SO1tBa35N68LBnpaC/KB7wT8YDOZDd8E/SHtq7cMMV/mfiwZwCjGo6e8PWwXvxDDpr3lFjSlsXatjmCJ6VdTbkwLJV6HnkSRmflY2IXPL8Su/InYyXrAS54zAoPX9Csi0f4sUr7EbOvAjy1QJQ+87w2vjp5Y5OuGaCcHJLuzZ8GQzDAEOZBnoMaRSSLd+a7+W2fWDIU+JdcpzXqv0X3eFw4gSRxXHD3+/wwfL17/m3VLsD9LEunlPuBEG9W8rftUftIFW9z2uUW7+BoWsQL33VGRK05ZR6R7YnG79gAzOHiwOWgRI+BTOPcvMEzj1nvpfqd4s9tbmu6rBAIXTuTB5KNT2J8vcs81YHfrW8ky5t5/nkP5+5kpJsmhUuU5GR6naKaDAq06nmb3hOJQj6zgpjjZ+n31/+Uuyp/jBjseKKSaUzo3wuvC6MDTeCOlgO2mgXkkxDjFX81MXQNR7a6A3kxFlQI7W8J/7XKxmlSbZ9VL8dF5SuAeW/ImT1mJlqI/EIf//PRtVIDWNP6Vfv1TLzdWkMlTJlrtfjIyB3/oiOvOTGhUIfNRGbZ01fsazoUO1+AxqoZ6PJK98JRXQeTWXnDUicXyc4gc4wFC17Rcbuh0B72GbKVmr41EmSIR91MgvmoU+E4dFOk3hSzbZURA9BnxpgFahDVWaklHYqPBQxDSZtxQaxt3oL6ONhhEhhclodyAlTBmKWojPSAnpsEKvdC5bFNMcRYtGhqOc+hLd87aCoCRN3bFWS4CPY5mQg5uBAExqL2BzQMHLhQD4kzr3m4MDLpgP6ZO8cB1ajA1HO2hwOTNkhQLkR3lq0AxJlb6fSuDVFwihC0I8QLAV1oCwNAcpRQDDMQxSuD8ReLGAMgSYzlE4Q2EnY/DWzmaSmDlbwIF5Q9IKEP4kDzq1ltTAJu38RhpvzRC+4V8fZ5B6SkYQuMiScldsn0w2IZIbRG1KUM6QMlLNRpfs4KEOVPKdjhqyyjYLS9bNrPWAZehaii2+ZzYYkqU/0mgXINESFCYc+3sPQqJFLQgkX3vQuRJ6luH5XqhTvmgVRnugBPQEcvwtyImxpKX8s9tTlepdiz2bUuifVjN61NqOeP6wknJ21yk02p1ybkWc7nmksVZutDtw4lu6GyAOMaFY3/EjswaKWVTvOeCHByJn5HUdSstoM2oMWETnqWkUyMkcetGLkG01FEGlnyrTnhcTzSjbSLIiH1y0mnRLD+9+B9JWsfb/lusYyRGXM60qW+VK6irsaXzjx4kmVzbYGO5787yHuC/L1H+Z/KV0U1/JF8cdkUfw1WxR/Tp/W3/PHSyH/l51SdaoAAAAASUVORK5CYII=',
- };
-
- const Page = window.Page = {
-
- state: {
- isDark: localStorage.getItem('darkTheme') === 'on',
- isPriorityMaintained: localStorage.getItem('maintainPriority') === 'on',
- status: {type: 'disconnected'},
- visibilityState: document.visibilityState,
- },
-
- setState(partialState) {
- Page.state = Object.assign({}, Page.state, partialState);
- Page.render();
- },
-
- render() {
- const {
- isDark,
- isPriorityMaintained,
- status,
- visibilityState,
- } = Page.state;
-
- const statusNode = document.getElementById('status');
- switch (status.type) {
- case 'connected':
- statusNode.innerHTML = 'Debugger session #' + status.id + ' active.';
- break;
- case 'error':
- statusNode.innerHTML = status.error.reason || 'Disconnected from proxy. Attempting reconnection. Is node server running?';
- break;
- case 'connecting':
- case 'disconnected':
- // Fall through.
- default:
- statusNode.innerHTML = 'Waiting, press <span class="shortcut">' + refreshShortcut + '</span> in simulator to reload and connect.';
- break;
- }
-
- const linkNode = document.querySelector('link[rel=icon]');
- if (status.type === 'disconnected' ||
- status.type === 'error') {
- linkNode.href = Assets.grayIcon;
- } else {
- if (visibilityState === 'visible' || isPriorityMaintained) {
- linkNode.href = Assets.blueIcon;
- } else {
- linkNode.href = Assets.orangeIcon;
- }
- }
-
- const darkCheckbox = document.getElementById('dark');
- document.body.classList.toggle('dark', isDark);
- darkCheckbox.checked = isDark;
- localStorage.setItem('darkTheme', isDark ? 'on' : '');
-
- const maintainPriorityCheckbox = document.getElementById('maintain-priority');
- const silence = document.getElementById('silence');
- silence.volume = 0.1;
- if (isPriorityMaintained) {
- silence.play();
- } else {
- silence.pause();
- }
- maintainPriorityCheckbox.checked = isPriorityMaintained;
- localStorage.setItem('maintainPriority', isPriorityMaintained ? 'on' : '');
- },
-
- toggleDarkTheme() {
- Page.setState({isDark: !Page.state.isDark});
- },
-
- togglePriorityMaintenance() {
- Page.setState({isPriorityMaintained: !Page.state.isPriorityMaintained});
- },
-
- };
-
- function connectToDebuggerProxy() {
- const ws = new WebSocket('ws://' + window.location.host + '/debugger-proxy?role=debugger&name=Chrome');
- let worker;
- let queuedMessages = [];
- let appExecuted = false;
-
- function createJSRuntime() {
- // This worker will run the application JavaScript code,
- // making sure that it's run in an environment without a global
- // document, to make it consistent with the JSC executor environment.
- worker = new Worker('debuggerWorker.js');
- worker.onmessage = function(message) {
- ws.send(JSON.stringify(message.data));
- };
- window.onbeforeunload = function() {
- return 'If you reload this page, it is going to break the debugging session. ' +
- 'You should press' + refreshShortcut + 'in simulator to reload.';
- };
- updateVisibility();
- }
-
- function shutdownJSRuntime() {
- if (worker) {
- worker.terminate();
- worker = null;
- window.onbeforeunload = null;
- }
- }
-
- function updateVisibility() {
- if (worker && !Page.state.isPriorityMaintained) {
- worker.postMessage({
- method: 'setDebuggerVisibility',
- visibilityState: document.visibilityState,
- });
- }
- Page.setState({visibilityState: document.visibilityState});
- }
-
- ws.onopen = function() {
- Page.setState({status: {type: 'connecting'}});
- };
-
- ws.onmessage = async function(message) {
- if (!message.data) {
- return;
- }
- const object = JSON.parse(message.data);
-
- if (object.$event === 'client-disconnected') {
- shutdownJSRuntime();
- Page.setState({status: {type: 'disconnected'}});
- return;
- }
-
- if (!object.method) {
- return;
- }
-
- // Special message that asks for a new JS runtime
- if (object.method === 'prepareJSRuntime') {
- shutdownJSRuntime();
- console.clear();
- createJSRuntime();
- ws.send(JSON.stringify({replyID: object.id}));
- Page.setState({status: {type: 'connected', id: object.id}});
- } else if (object.method === '$disconnected') {
- shutdownJSRuntime();
- Page.setState({status: {type: 'disconnected'}});
- } else if (object.method === 'executeApplicationScript') {
- appExecuted = false;
- worker.postMessage({
- ...object,
- url: await getBlobUrl(object.url),
- });
- appExecuted = true;
- // Flush any messages queued up and clear them
- for (const message of queuedMessages) {
- worker.postMessage(message);
- }
- queuedMessages = [];
- } else {
- // Otherwise, pass through to the worker provided the
- // application script has been executed. If not add
- // it to a queue until it has been executed.
- if (appExecuted) {
- worker.postMessage(object);
- } else {
- queuedMessages.push(object);
- }
- }
- };
-
- ws.onclose = function(error) {
- shutdownJSRuntime();
- Page.setState({status: {type: 'error', error}});
- if (error.reason) {
- console.warn(error.reason);
- }
- setTimeout(connectToDebuggerProxy, 500);
- };
-
- // Let debuggerWorker.js know when we're not visible so that we can warn about
- // poor performance when using remote debugging.
- document.addEventListener('visibilitychange', updateVisibility, false);
- }
-
- connectToDebuggerProxy();
-
- async function getBlobUrl(url) {
- return await window.deltaUrlToBlobUrl(url.replace('.bundle', '.delta'));
- }
-})();
-</script>
-<style type="text/css">
- html,
- body {
- font-family: Helvetica, Verdana, sans-serif;
- font-size: large;
- font-weight: 200;
- height: 100%;
- margin: 0;
- padding: 0;
- }
- .shortcut {
- border-radius: 4px;
- color: #eee;
- background-color: #333;
- font-family: "Monaco", monospace;
- font-size: medium;
- letter-spacing: 3px;
- padding: 4px;
- }
- .content {
- padding: 10px;
- }
- body.dark {
- background-color: #242424;
- color: #666;
- }
- .dark .shortcut {
- color: #777;
- }
- .dark a {
- color: #3b99fc;
- }
- input[type=checkbox] {
- vertical-align: middle;
- }
-</style>
-</head>
-<body>
- <div class="content">
- <label for="dark">
- <input type="checkbox" id="dark" onclick="Page.toggleDarkTheme()"> Dark Theme
- </label>
- <label for="maintain-priority">
- <input type="checkbox" id="maintain-priority" onclick="Page.togglePriorityMaintenance()"> Maintain Priority
- </label>
- <p>
- React Native JS code runs as a web worker inside this tab.
- </p>
- <p>Press <kbd id="shortcut" class="shortcut">⌘⌥I</kbd> to open Developer Tools. Enable <a href="https://stackoverflow.com/a/17324511/232122" target="_blank">Pause On Caught Exceptions</a> for a better debugging experience.</p>
- <p>You may also install <a href="https://github.com/facebook/react-devtools/tree/master/packages/react-devtools" target="_blank">the standalone version of React Developer Tools</a> to inspect the React component hierarchy, their props, and state.</p>
- <p>Status: <span id="status">Loading...</span></p>
- </div>
- <audio id="silence" loop src="data:audio/wav;base64,UklGRmxsAQBXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhiFgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v////////////////////////////////////////////////////////////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8AEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABkAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGQAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGQAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////////////////////7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6f/p/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//e/97/3v/e/97/3v/e/97/3v/e/97/3v/e/97/3v/e/97/3v/e/97/3v/e/97/3v/d/93/3f/d/93/3f/d/93/3f/d/93/3f/d/93/3f/d/93/3f/d/93/3f/d/93/3f/d/9z/3P/c/9z/3P/c/9z/3P/c/9z/3P/c/9z/3P/c/9z/3P/c/9z/3P/c/9z/3P/c/9z/3P/b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//a/9r/2v/a/9r/2v/a/9r/2v/a/9r/2v/a/9r/2v/a/9r/2v/a/9r/2v/a/9r/2v/a/9r/2v/a/9n/2f/Z/9n/2f/Z/9n/2f/Z/9n/2f/Z/9n/2f/Z/9n/2f/Z/9n/2f/Z/9n/2f/Z/9n/2f/Z/9n/2f/Z/9n/2P/Y/9j/2P/Y/9j/2P/Y/9j/2P/Y/9j/2P/Y/9j/2P/Y/9j/2P/Y/9j/2P/Y/9j/2P/Y/9j/2P/Y/9j/2P/Y/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//W/9b/1v/W/9b/1v/W/9b/1v/W/9b/1v/W/9b/1v/W/9b/1v/W/9b/1v/W/9b/1v/W/9b/1v/W/9b/1v/W/9b/1v/W/9b/1v/W/9b/1v/W/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1v/W/9b/1v/W/9b/1v/W/9b/1v/W/9b/1v/W/9b/1v/W/9b/1v/W/9b/1v/W/9b/1v/W/9b/1v/W/9b/1v/W/9b/1v/W/9b/1v/W/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/2P/Y/9j/2P/Y/9j/2P/Y/9j/2P/Y/9j/2P/Y/9j/2P/Y/9j/2P/Y/9j/2P/Y/9j/2P/Y/9j/2P/Y/9j/2f/Z/9n/2f/Z/9n/2f/Z/9n/2f/Z/9n/2f/Z/9n/2f/Z/9n/2f/Z/9n/2f/Z/9n/2f/Z/9n/2f/a/9r/2v/a/9r/2v/a/9r/2v/a/9r/2v/a/9r/2v/a/9r/2v/a/9r/2v/a/9r/2v/a/9r/2v/b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9z/3P/c/9z/3P/c/9z/3P/c/9z/3P/c/9z/3P/c/9z/3P/c/9z/3P/c/9z/3P/c/93/3f/d/93/3f/d/93/3f/d/93/3f/d/93/3f/d/93/3f/d/93/3f/d/93/3v/e/97/3v/e/97/3v/e/97/3v/e/97/3v/e/97/3v/e/97/3v/e/97/3v/f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/3//f/9//3//f/9//3//f/9//3//f/9//3//f/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+//7//v/+//7//v/+//7//v/+//7//v/+//8//z//P/8//z//P/8//z//P/8//z//P/8//z//f/9//3//f/9//3//f/9//3//f/9//3//f/9//7//v/+//7//v/+//7//v/+//7//v/+//7//////////////////////////////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAsACwALAAsACwALAAsACwALAAsACwALAAsADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8AEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAARABEAEQARABEAEQARABEAEQARABEAEQARABEAEgASABIAEgASABIAEgASABIAEgASABIAEgATABMAEwATABMAEwATABMAEwATABMAEwATABMAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGQAZABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACIAIgAiACIAIgAiACIAIgAiACIAIgAiACIAIgAiACIAIwAjACMAIwAjACMAIwAjACMAIwAjACMAIwAjACMAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACYAJgAmACYAJgAmACYAJgAmACYAJgAmACYAJgAmACYAJgAnACcAJwAnACcAJwAnACcAJwAnACcAJwAnACcAJwAnACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAvAC8ALwAvAC8ALwAvAC8ALwAvAC8ALwAvAC8ALwAvAC8ALwAvAC8ALwAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAxADEAMQAxADEAMQAxADEAMQAxADEAMQAxADEAMQAxADEAMQAxADEAMQAxADEAMgAyADIAMgAyADIAMgAyADIAMgAyADIAMgAyADIAMgAyADIAMgAyADIAMgAyADMAMwAzADMAMwAzADMAMwAzADMAMwAzADMAMwAzADMAMwAzADMAMwAzADMAMwAzADMANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADUANQA1ADUANQA1ADUANQA1ADUANQA1ADUANQA1ADUANQA1ADUANQA1ADUANQA1ADUANQA1ADUANgA2ADYANgA2ADYANgA2ADYANgA2ADYANgA2ADYANgA2ADYANgA2ADYANgA2ADYANgA2ADYANgA2ADYANgA3ADcANwA3ADcANwA3ADcANwA3ADcANwA3ADcANwA3ADcANwA3ADcANwA3ADcANwA3ADcANwA3ADcANwA3ADcANwA3ADcAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA3ADcANwA3ADcANwA3ADcANwA3ADcANwA3ADcANwA3ADcANwA3ADcANwA3ADcANwA3ADcANwA3ADcANwA3ADcANwA3ADYANgA2ADYANgA2ADYANgA2ADYANgA2ADYANgA2ADYANgA2ADYANgA2ADYANgA2ADYANgA2ADYANgA2ADUANQA1ADUANQA1ADUANQA1ADUANQA1ADUANQA1ADUANQA1ADUANQA1ADUANQA1ADUANQA1ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQAMwAzADMAMwAzADMAMwAzADMAMwAzADMAMwAzADMAMwAzADMAMwAzADMAMwAzADIAMgAyADIAMgAyADIAMgAyADIAMgAyADIAMgAyADIAMgAyADIAMgAyADIAMQAxADEAMQAxADEAMQAxADEAMQAxADEAMQAxADEAMQAxADEAMQAxADEAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAALwAvAC8ALwAvAC8ALwAvAC8ALwAvAC8ALwAvAC8ALwAvAC8ALwAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAJwAnACcAJwAnACcAJwAnACcAJwAnACcAJwAnACcAJgAmACYAJgAmACYAJgAmACYAJgAmACYAJgAmACYAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACMAIwAjACMAIwAjACMAIwAjACMAIwAjACMAIwAiACIAIgAiACIAIgAiACIAIgAiACIAIgAiACIAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAcABwAHAAcABwAHAAcABwAHAAcABwAHAAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGAAYABgAGAAYABgAGAAYABgAGAAYABgAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAWABYAFgAWABYAFgAWABYAFgAWABYAFgAVABUAFQAVABUAFQAVABUAFQAVABUAFQAUABQAFAAUABQAFAAUABQAFAAUABQAEwATABMAEwATABMAEwATABMAEwATABMAEgASABIAEgASABIAEgASABIAEgASABIAEQARABEAEQARABEAEQARABEAEQARABAAEAAQABAAEAAQABAAEAAQABAAEAAQAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgANAA0ADQANAA0ADQANAA0ADQANAA0ADAAMAAwADAAMAAwADAAMAAwADAAMAAsACwALAAsACwALAAsACwALAAsACwALAAoACgAKAAoACgAKAAoACgAKAAoACgAJAAkACQAJAAkACQAJAAkACQAJAAkACAAIAAgACAAIAAgACAAIAAgACAAIAAcABwAHAAcABwAHAAcABwAHAAcABwAGAAYABgAGAAYABgAGAAYABgAGAAYABQAFAAUABQAFAAUABQAFAAUABQAFAAQABAAEAAQABAAEAAQABAAEAAQABAADAAMAAwADAAMAAwADAAMAAwADAAIAAgACAAIAAgACAAIAAgACAAIAAgABAAEAAQABAAEAAQABAAEAAQABAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/////////////////////////////+//7//v/+//7//v/+//7//v/+//3//f/9//3//f/9//3//f/9//3//f/8//z//P/8//z//P/8//z//P/8//z/+//7//v/+//7//v/+//7//v/+//7//r/+v/6//r/+v/6//r/+v/6//r/+f/5//n/+f/5//n/+f/5//n/+f/5//j/+P/4//j/+P/4//j/+P/4//j/+P/3//f/9//3//f/9//3//f/9//3//b/9v/2//b/9v/2//b/9v/2//b/9v/1//X/9f/1//X/9f/1//X/9f/1//X/9P/0//T/9P/0//T/9P/0//T/9P/0//P/8//z//P/8//z//P/8//z//P/8v/y//L/8v/y//L/8v/y//L/8v/y//H/8f/x//H/8f/x//H/8f/x//H/8f/w//D/8P/w//D/8P/w//D/8P/w//D/7//v/+//7//v/+//7//v/+//7//u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/r/+v/6//r/+v/6//r/+v/6//r/+v/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+n/6f/p/+n/6f/p/+n/6f/p/+n/6f/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/5//n/+f/5//n/+f/5//n/+f/5//n/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/3//f/9//3//f/9//3//f/9//3//f/9//3v/e/97/3v/e/97/3v/e/97/3v/e/93/3f/d/93/3f/d/93/3f/d/93/3f/d/9z/3P/c/9z/3P/c/9z/3P/c/9z/3P/c/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9r/2v/a/9r/2v/a/9r/2v/a/9r/2v/a/9n/2f/Z/9n/2f/Z/9n/2f/Z/9n/2f/Z/9j/2P/Y/9j/2P/Y/9j/2P/Y/9j/2P/Y/9j/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1v/W/9b/1v/W/9b/1v/W/9b/1v/W/9b/1v/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/R/9H/0f/R/9H/0f/R/9H/0f/R/9H/0f/R/9H/0P/Q/9D/0P/Q/9D/0P/Q/9D/0P/Q/9D/0P/P/8//z//P/8//z//P/8//z//P/8//z//P/8//zv/O/87/zv/O/87/zv/O/87/zv/O/87/zv/O/83/zf/N/83/zf/N/83/zf/N/83/zf/N/83/zf/N/8z/zP/M/8z/zP/M/8z/zP/M/8z/zP/M/8z/zP/L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//K/8r/yv/K/8r/yv/K/8r/yv/K/8r/yv/K/8r/yv/K/8n/yf/J/8n/yf/J/8n/yf/J/8n/yf/J/8n/yf/J/8j/yP/I/8j/yP/I/8j/yP/I/8j/yP/I/8j/yP/I/8j/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/E/8T/xP/E/8T/xP/E/8T/xP/E/8T/xP/E/8T/xP/E/8T/xP/D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8L/wv/C/8L/wv/C/8L/wv/C/8L/wv/C/8L/wv/C/8L/wv/C/8L/wv/B/8H/wf/B/8H/wf/B/8H/wf/B/8H/wf/B/8H/wf/B/8H/wf/B/8H/wf/A/8D/wP/A/8D/wP/A/8D/wP/A/8D/wP/A/8D/wP/A/8D/wP/A/8D/wP/A/7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/++/77/vv++/77/vv++/77/vv++/77/vv++/77/vv++/77/vv++/77/vv++/77/vv++/77/vf+9/73/vf+9/73/vf+9/73/vf+9/73/vf+9/73/vf+9/73/vf+9/73/vf+9/73/vf+9/73/vf+8/7z/vP+8/7z/vP+8/7z/vP+8/7z/vP+8/7z/vP+8/7z/vP+8/7z/vP+8/7z/vP+8/7z/vP+8/7z/vP+8/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/vP+8/7z/vP+8/7z/vP+8/7z/vP+8/7z/vP+8/7z/vP+8/7z/vP+8/7z/vP+8/7z/vP+8/7z/vP+8/7z/vP+9/73/vf+9/73/vf+9/73/vf+9/73/vf+9/73/vf+9/73/vf+9/73/vf+9/73/vf+9/73/vf++/77/vv++/77/vv++/77/vv++/77/vv++/77/vv++/77/vv++/77/vv++/77/vv++/7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v//A/8D/wP/A/8D/wP/A/8D/wP/A/8D/wP/A/8D/wP/A/8D/wP/A/8D/wP/B/8H/wf/B/8H/wf/B/8H/wf/B/8H/wf/B/8H/wf/B/8H/wf/B/8H/wv/C/8L/wv/C/8L/wv/C/8L/wv/C/8L/wv/C/8L/wv/C/8L/wv/D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//E/8T/xP/E/8T/xP/E/8T/xP/E/8T/xP/E/8T/xP/E/8T/xP/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//I/8j/yP/I/8j/yP/I/8j/yP/I/8j/yP/I/8j/yP/I/8n/yf/J/8n/yf/J/8n/yf/J/8n/yf/J/8n/yf/K/8r/yv/K/8r/yv/K/8r/yv/K/8r/yv/K/8r/yv/L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/zP/M/8z/zP/M/8z/zP/M/8z/zP/M/8z/zP/M/83/zf/N/83/zf/N/83/zf/N/83/zf/N/83/zv/O/87/zv/O/87/zv/O/87/zv/O/87/zv/P/8//z//P/8//z//P/8//z//P/8//z//P/9D/0P/Q/9D/0P/Q/9D/0P/Q/9D/0P/Q/9D/0f/R/9H/0f/R/9H/0f/R/9H/0f/R/9H/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/T/9P/0//T/9P/0//T/9P/0//T/9P/0//U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1v/W/9b/1v/W/9b/1v/W/9b/1v/W/9b/1//X/9f/1//X/9f/1//X/9f/1//X/9j/2P/Y/9j/2P/Y/9j/2P/Y/9j/2P/Y/9n/2f/Z/9n/2f/Z/9n/2f/Z/9n/2f/a/9r/2v/a/9r/2v/a/9r/2v/a/9r/2//b/9v/2//b/9v/2//b/9v/2//b/9z/3P/c/9z/3P/c/9z/3P/c/9z/3P/d/93/3f/d/93/3f/d/93/3f/d/97/3v/e/97/3v/e/97/3v/e/97/3v/f/9//3//f/9//3//f/9//3//f/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/h/+H/4f/h/+H/4f/h/+H/4f/h/+L/4v/i/+L/4v/i/+L/4v/i/+L/4//j/+P/4//j/+P/4//j/+P/4//j/+T/5P/k/+T/5P/k/+T/5P/k/+T/5f/l/+X/5f/l/+X/5f/l/+X/5f/m/+b/5v/m/+b/5v/m/+b/5v/m/+f/5//n/+f/5//n/+f/5//n/+j/6P/o/+j/6P/o/+j/6P/o/+j/6f/p/+n/6f/p/+n/6f/p/+n/6f/q/+r/6v/q/+r/6v/q/+r/6v/q/+v/6//r/+v/6//r/+v/6//r/+z/7P/s/+z/7P/s/+z/7P/s/+z/7f/t/+3/7f/t/+3/7f/t/+3/7v/u/+7/7v/u/+7/7v/u/+7/7v/v/+//7//v/+//7//v/+//7//w//D/8P/w//D/8P/w//D/8P/w//H/8f/x//H/8f/x//H/8f/x//L/8v/y//L/8v/y//L/8v/y//P/8//z//P/8//z//P/8//z//P/9P/0//T/9P/0//T/9P/0//T/9f/1//X/9f/1//X/9f/1//X/9v/2//b/9v/2//b/9v/2//b/9//3//f/9//3//f/9//3//f/+P/4//j/+P/4//j/+P/4//j/+P/5//n/+f/5//n/+f/5//n/+f/6//r/+v/6//r/+v/6//r/+v/7//v/+//7//v/+//7//v/+//8//z//P/8//z//P/8//z//P/9//3//f/9//3//f/9//3//f/+//7//v/+//7//v/+//7//v////////////////////////8AAAAAAAAAAAAAAAAAAAAAAAABAAEAAQABAAEAAQABAAEAAQACAAIAAgACAAIAAgACAAIAAgADAAMAAwADAAMAAwADAAMAAwAEAAQABAAEAAQABAAEAAQABAAFAAUABQAFAAUABQAFAAUABQAGAAYABgAGAAYABgAGAAYABgAHAAcABwAHAAcABwAHAAcABwAIAAgACAAIAAgACAAIAAgACAAJAAkACQAJAAkACQAJAAkACQAKAAoACgAKAAoACgAKAAoACgALAAsACwALAAsACwALAAsADAAMAAwADAAMAAwADAAMAAwADQANAA0ADQANAA0ADQANAA0ADgAOAA4ADgAOAA4ADgAOAA4ADwAPAA8ADwAPAA8ADwAPAA8AEAAQABAAEAAQABAAEAAQABAAEQARABEAEQARABEAEQARABEAEgASABIAEgASABIAEgASABIAEwATABMAEwATABMAEwATABMAFAAUABQAFAAUABQAFAAUABQAFQAVABUAFQAVABUAFQAVABUAFgAWABYAFgAWABYAFgAWABYAFgAXABcAFwAXABcAFwAXABcAFwAYABgAGAAYABgAGAAYABgAGAAZABkAGQAZABkAGQAZABkAGQAaABoAGgAaABoAGgAaABoAGgAbABsAGwAbABsAGwAbABsAGwAcABwAHAAcABwAHAAcABwAHAAcAB0AHQAdAB0AHQAdAB0AHQAdAB4AHgAeAB4AHgAeAB4AHgAeAB8AHwAfAB8AHwAfAB8AHwAfACAAIAAgACAAIAAgACAAIAAgACAAIQAhACEAIQAhACEAIQAhACEAIgAiACIAIgAiACIAIgAiACIAIgAjACMAIwAjACMAIwAjACMAIwAkACQAJAAkACQAJAAkACQAJAAkACUAJQAlACUAJQAlACUAJQAlACUAJgAmACYAJgAmACYAJgAmACYAJwAnACcAJwAnACcAJwAnACcAJwAoACgAKAAoACgAKAAoACgAKAAoACkAKQApACkAKQApACkAKQApACkAKgAqACoAKgAqACoAKgAqACoAKgArACsAKwArACsAKwArACsAKwArACwALAAsACwALAAsACwALAAsACwALQAtAC0ALQAtAC0ALQAtAC0ALQAuAC4ALgAuAC4ALgAuAC4ALgAuAC8ALwAvAC8ALwAvAC8ALwAvAC8AMAAwADAAMAAwADAAMAAwADAAMAAwADEAMQAxADEAMQAxADEAMQAxADEAMgAyADIAMgAyADIAMgAyADIAMgAyADMAMwAzADMAMwAzADMAMwAzADMAMwA0ADQANAA0ADQANAA0ADQANAA0ADQANQA1ADUANQA1ADUANQA1ADUANQA2ADYANgA2ADYANgA2ADYANgA2ADYANgA3ADcANwA3ADcANwA3ADcANwA3ADcAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA9AD0APQA9AD0APQA9AD0APQA9AD0APQA9AD4APgA+AD4APgA+AD4APgA+AD4APgA+AD8APwA/AD8APwA/AD8APwA/AD8APwA/AD8AQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEIAQgBCAEIAQgBCAEIAQgBCAEIAQgBCAEIAQgBDAEMAQwBDAEMAQwBDAEMAQwBDAEMAQwBDAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEUARQBFAEUARQBFAEUARQBFAEUARQBFAEUARQBGAEYARgBGAEYARgBGAEYARgBGAEYARgBGAEYARgBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASQBJAEkASQBJAEkASQBJAEkASQBJAEkASQBJAEkASQBKAEoASgBKAEoASgBKAEoASgBKAEoASgBKAEoASgBKAEoASgBLAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsASwBMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAE0ATQBNAE0ATQBNAE0ATQBNAE0ATQBNAE0ATQBNAE0ATQBNAE0ATQBOAE4ATgBOAE4ATgBOAE4ATgBOAE4ATgBOAE4ATgBOAE4ATgBOAE4ATgBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFEAUQBRAFEAUQBRAFEAUQBRAFEAUQBRAFEAUQBRAFEAUQBRAFEAUQBRAFEAUQBRAFEAUQBRAFEAUQBSAFIAUgBSAFIAUgBSAFIAUgBSAFIAUgBSAFIAUgBSAFIAUgBSAFIAUgBSAFIAUgBSAFIAUgBSAFIAUgBSAFIAUgBSAFMAUwBTAFMAUwBTAFMAUwBTAFMAUwBTAFMAUwBTAFMAUwBTAFMAUwBTAFMAUwBTAFMAUwBTAFMAUwBTAFMAUwBTAFMAUwBTAFMAUwBTAFMAUwBTAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFMAUwBTAFMAUwBTAFMAUwBTAFMAUwBTAFMAUwBTAFMAUwBTAFMAUwBTAFMAUwBTAFMAUwBTAFMAUwBTAFMAUwBTAFMAUwBTAFMAUwBTAFMAUwBTAFIAUgBSAFIAUgBSAFIAUgBSAFIAUgBSAFIAUgBSAFIAUgBSAFIAUgBSAFIAUgBSAFIAUgBSAFIAUgBSAFIAUgBSAFEAUQBRAFEAUQBRAFEAUQBRAFEAUQBRAFEAUQBRAFEAUQBRAFEAUQBRAFEAUQBRAFEAUQBRAFEAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATgBOAE4ATgBOAE4ATgBOAE4ATgBOAE4ATgBOAE4ATgBOAE4ATgBOAE4ATQBNAE0ATQBNAE0ATQBNAE0ATQBNAE0ATQBNAE0ATQBNAE0ATQBMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsASwBKAEoASgBKAEoASgBKAEoASgBKAEoASgBKAEoASgBKAEoASQBJAEkASQBJAEkASQBJAEkASQBJAEkASQBJAEkASQBIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBGAEYARgBGAEYARgBGAEYARgBGAEYARgBGAEYARgBFAEUARQBFAEUARQBFAEUARQBFAEUARQBFAEUARABEAEQARABEAEQARABEAEQARABEAEQARABDAEMAQwBDAEMAQwBDAEMAQwBDAEMAQwBDAEMAQgBCAEIAQgBCAEIAQgBCAEIAQgBCAEIAQgBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBAAEAAQABAAEAAQABAAEAAQABAAEAAQAA/AD8APwA/AD8APwA/AD8APwA/AD8APwA/AD4APgA+AD4APgA+AD4APgA+AD4APgA9AD0APQA9AD0APQA9AD0APQA9AD0APQA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA4ADgAOAA4ADgAOAA4ADgAOAA4ADcANwA3ADcANwA3ADcANwA3ADcANwA2ADYANgA2ADYANgA2ADYANgA2ADUANQA1ADUANQA1ADUANQA1ADUANAA0ADQANAA0ADQANAA0ADQANAA0ADMAMwAzADMAMwAzADMAMwAzADMAMgAyADIAMgAyADIAMgAyADIAMgAxADEAMQAxADEAMQAxADEAMQAwADAAMAAwADAAMAAwADAAMAAwAC8ALwAvAC8ALwAvAC8ALwAvAC8ALgAuAC4ALgAuAC4ALgAuAC4ALQAtAC0ALQAtAC0ALQAtAC0ALQAsACwALAAsACwALAAsACwALAArACsAKwArACsAKwArACsAKwAqACoAKgAqACoAKgAqACoAKgApACkAKQApACkAKQApACkAKQAoACgAKAAoACgAKAAoACgAKAAnACcAJwAnACcAJwAnACcAJwAmACYAJgAmACYAJgAmACYAJgAlACUAJQAlACUAJQAlACUAJQAkACQAJAAkACQAJAAkACQAJAAjACMAIwAjACMAIwAjACMAIwAiACIAIgAiACIAIgAiACIAIQAhACEAIQAhACEAIQAhACEAIAAgACAAIAAgACAAIAAgAB8AHwAfAB8AHwAfAB8AHwAfAB4AHgAeAB4AHgAeAB4AHgAdAB0AHQAdAB0AHQAdAB0AHQAcABwAHAAcABwAHAAcABwAGwAbABsAGwAbABsAGwAbABoAGgAaABoAGgAaABoAGgAaABkAGQAZABkAGQAZABkAGQAYABgAGAAYABgAGAAYABgAFwAXABcAFwAXABcAFwAXABYAFgAWABYAFgAWABYAFgAVABUAFQAVABUAFQAVABUAFAAUABQAFAAUABQAFAAUABQAEwATABMAEwATABMAEwATABIAEgASABIAEgASABIAEgARABEAEQARABEAEQARABEAEAAQABAAEAAQABAAEAAQAA8ADwAPAA8ADwAPAA8ADgAOAA4ADgAOAA4ADgAOAA0ADQANAA0ADQANAA0ADQAMAAwADAAMAAwADAAMAAwACwALAAsACwALAAsACwALAAoACgAKAAoACgAKAAoACgAJAAkACQAJAAkACQAJAAkACAAIAAgACAAIAAgACAAHAAcABwAHAAcABwAHAAcABgAGAAYABgAGAAYABgAGAAUABQAFAAUABQAFAAUABQAEAAQABAAEAAQABAAEAAMAAwADAAMAAwADAAMAAwACAAIAAgACAAIAAgACAAIAAQABAAEAAQABAAEAAQABAAAAAAAAAAAAAAAAAAAA//////////////////////7//v/+//7//v/+//7//v/9//3//f/9//3//f/9//z//P/8//z//P/8//z//P/7//v/+//7//v/+//7//v/+v/6//r/+v/6//r/+v/5//n/+f/5//n/+f/5//n/+P/4//j/+P/4//j/+P/4//f/9//3//f/9//3//f/9v/2//b/9v/2//b/9v/2//X/9f/1//X/9f/1//X/9f/0//T/9P/0//T/9P/0//T/8//z//P/8//z//P/8//y//L/8v/y//L/8v/y//L/8f/x//H/8f/x//H/8f/x//D/8P/w//D/8P/w//D/7//v/+//7//v/+//7//v/+7/7v/u/+7/7v/u/+7/7v/t/+3/7f/t/+3/7f/t/+z/7P/s/+z/7P/s/+z/7P/r/+v/6//r/+v/6//r/+v/6v/q/+r/6v/q/+r/6v/q/+n/6f/p/+n/6f/p/+n/6P/o/+j/6P/o/+j/6P/o/+f/5//n/+f/5//n/+f/5//m/+b/5v/m/+b/5v/m/+b/5f/l/+X/5f/l/+X/5f/l/+T/5P/k/+T/5P/k/+T/5P/j/+P/4//j/+P/4//j/+P/4v/i/+L/4v/i/+L/4v/h/+H/4f/h/+H/4f/h/+H/4P/g/+D/4P/g/+D/4P/g/9//3//f/9//3//f/9//3//e/97/3v/e/97/3v/e/97/3f/d/93/3f/d/93/3f/d/9z/3P/c/9z/3P/c/9z/3P/b/9v/2//b/9v/2//b/9v/2v/a/9r/2v/a/9r/2v/a/9r/2f/Z/9n/2f/Z/9n/2f/Z/9j/2P/Y/9j/2P/Y/9j/2P/X/9f/1//X/9f/1//X/9f/1v/W/9b/1v/W/9b/1v/W/9X/1f/V/9X/1f/V/9X/1f/V/9T/1P/U/9T/1P/U/9T/1P/T/9P/0//T/9P/0//T/9P/0//S/9L/0v/S/9L/0v/S/9L/0f/R/9H/0f/R/9H/0f/R/9D/0P/Q/9D/0P/Q/9D/0P/Q/8//z//P/8//z//P/8//z//P/87/zv/O/87/zv/O/87/zv/N/83/zf/N/83/zf/N/83/zf/M/8z/zP/M/8z/zP/M/8z/zP/L/8v/y//L/8v/y//L/8v/y//K/8r/yv/K/8r/yv/K/8r/yf/J/8n/yf/J/8n/yf/J/8n/yP/I/8j/yP/I/8j/yP/I/8j/x//H/8f/x//H/8f/x//H/8f/x//G/8b/xv/G/8b/xv/G/8b/xv/F/8X/xf/F/8X/xf/F/8X/xf/E/8T/xP/E/8T/xP/E/8T/xP/D/8P/w//D/8P/w//D/8P/w//D/8L/wv/C/8L/wv/C/8L/wv/C/8H/wf/B/8H/wf/B/8H/wf/B/8H/wP/A/8D/wP/A/8D/wP/A/8D/wP+//7//v/+//7//v/+//7//v/+//77/vv++/77/vv++/77/vv++/77/vf+9/73/vf+9/73/vf+9/73/vf+8/7z/vP+8/7z/vP+8/7z/vP+8/7v/u/+7/7v/u/+7/7v/u/+7/7v/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7b/tv+2/7b/tv+2/7b/tv+2/7b/tv+1/7X/tf+1/7X/tf+1/7X/tf+1/7X/tP+0/7T/tP+0/7T/tP+0/7T/tP+0/7T/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/sv+y/7L/sv+y/7L/sv+y/7L/sv+y/7L/sf+x/7H/sf+x/7H/sf+x/7H/sf+x/7H/sP+w/7D/sP+w/7D/sP+w/7D/sP+w/7D/sP+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/67/rv+u/67/rv+u/67/rv+u/67/rv+u/67/rv+t/63/rf+t/63/rf+t/63/rf+t/63/rf+t/63/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6r/qv+q/6r/qv+q/6r/qv+q/6r/qv+q/6r/qv+q/6n/qf+p/6n/qf+p/6n/qf+p/6n/qf+p/6n/qf+p/6n/qP+o/6j/qP+o/6j/qP+o/6j/qP+o/6j/qP+o/6j/qP+o/6f/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6f/p/+m/6b/pv+m/6b/pv+m/6b/pv+m/6b/pv+m/6b/pv+m/6b/pv+m/6X/pf+l/6X/pf+l/6X/pf+l/6X/pf+l/6X/pf+l/6X/pf+l/6X/pf+k/6T/pP+k/6T/pP+k/6T/pP+k/6T/pP+k/6T/pP+k/6T/pP+k/6T/pP+k/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+i/6L/ov+i/6L/ov+i/6L/ov+i/6L/ov+i/6L/ov+i/6L/ov+i/6L/ov+i/6L/ov+i/6L/ov+h/6H/of+h/6H/of+h/6H/of+h/6H/of+h/6H/of+h/6H/of+h/6H/of+h/6H/of+h/6H/of+h/6H/of+h/6D/oP+g/6D/oP+g/6D/oP+g/6D/oP+g/6D/oP+g/6D/oP+g/6D/oP+g/6D/oP+g/6D/oP+g/6D/oP+g/6D/oP+g/6D/oP+g/6D/oP+g/6D/n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+e/57/nv+e/57/nv+e/57/nv+e/57/nv+e/57/nv+e/57/nv+e/57/nv+e/57/nv+e/57/nv+e/57/nv+e/57/nv+e/57/nv+e/57/nv+e/57/nv+e/57/nv+e/57/nv+e/57/nv+e/57/nv+e/57/nv+e/57/nv+e/57/nv+e/57/nv+e/57/nv+e/57/nv+e/57/nv+e/57/nv+e/57/nv+e/57/n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+g/6D/oP+g/6D/oP+g/6D/oP+g/6D/oP+g/6D/oP+g/6D/oP+g/6D/oP+g/6D/oP+g/6D/oP+g/6D/oP+g/6D/oP+g/6D/oP+g/6D/oP+h/6H/of+h/6H/of+h/6H/of+h/6H/of+h/6H/of+h/6H/of+h/6H/of+h/6H/of+h/6H/of+h/6H/of+h/6L/ov+i/6L/ov+i/6L/ov+i/6L/ov+i/6L/ov+i/6L/ov+i/6L/ov+i/6L/ov+i/6L/ov+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+k/6T/pP+k/6T/pP+k/6T/pP+k/6T/pP+k/6T/pP+k/6T/pP+k/6T/pP+l/6X/pf+l/6X/pf+l/6X/pf+l/6X/pf+l/6X/pf+l/6X/pf+l/6b/pv+m/6b/pv+m/6b/pv+m/6b/pv+m/6b/pv+m/6b/pv+m/6b/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6j/qP+o/6j/qP+o/6j/qP+o/6j/qP+o/6j/qP+o/6j/qf+p/6n/qf+p/6n/qf+p/6n/qf+p/6n/qf+p/6n/qf+q/6r/qv+q/6r/qv+q/6r/qv+q/6r/qv+q/6r/qv+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/63/rf+t/63/rf+t/63/rf+t/63/rf+t/63/rv+u/67/rv+u/67/rv+u/67/rv+u/67/rv+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/7D/sP+w/7D/sP+w/7D/sP+w/7D/sP+w/7H/sf+x/7H/sf+x/7H/sf+x/7H/sf+x/7L/sv+y/7L/sv+y/7L/sv+y/7L/sv+y/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+0/7T/tP+0/7T/tP+0/7T/tP+0/7T/tP+1/7X/tf+1/7X/tf+1/7X/tf+1/7X/tv+2/7b/tv+2/7b/tv+2/7b/tv+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/uP+4/7j/uP+4/7j/uP+4/7j/uP+5/7n/uf+5/7n/uf+5/7n/uf+5/7r/uv+6/7r/uv+6/7r/uv+6/7r/u/+7/7v/u/+7/7v/u/+7/7v/u/+8/7z/vP+8/7z/vP+8/7z/vP+8/73/vf+9/73/vf+9/73/vf+9/73/vv++/77/vv++/77/vv++/77/v/+//7//v/+//7//v/+//7//v//A/8D/wP/A/8D/wP/A/8D/wP/B/8H/wf/B/8H/wf/B/8H/wf/C/8L/wv/C/8L/wv/C/8L/wv/D/8P/w//D/8P/w//D/8P/w//E/8T/xP/E/8T/xP/E/8T/xP/F/8X/xf/F/8X/xf/F/8X/xf/G/8b/xv/G/8b/xv/G/8b/x//H/8f/x//H/8f/x//H/8f/yP/I/8j/yP/I/8j/yP/I/8n/yf/J/8n/yf/J/8n/yf/J/8r/yv/K/8r/yv/K/8r/yv/L/8v/y//L/8v/y//L/8v/zP/M/8z/zP/M/8z/zP/M/8z/zf/N/83/zf/N/83/zf/N/87/zv/O/87/zv/O/87/zv/P/8//z//P/8//z//P/8//0P/Q/9D/0P/Q/9D/0P/Q/9H/0f/R/9H/0f/R/9H/0f/S/9L/0v/S/9L/0v/S/9L/0//T/9P/0//T/9P/0//U/9T/1P/U/9T/1P/U/9T/1f/V/9X/1f/V/9X/1f/V/9b/1v/W/9b/1v/W/9b/1v/X/9f/1//X/9f/1//X/9j/2P/Y/9j/2P/Y/9j/2P/Z/9n/2f/Z/9n/2f/Z/9r/2v/a/9r/2v/a/9r/2v/b/9v/2//b/9v/2//b/9z/3P/c/9z/3P/c/9z/3P/d/93/3f/d/93/3f/d/97/3v/e/97/3v/e/97/3//f/9//3//f/9//3//f/+D/4P/g/+D/4P/g/+D/4f/h/+H/4f/h/+H/4f/i/+L/4v/i/+L/4v/i/+P/4//j/+P/4//j/+P/4//k/+T/5P/k/+T/5P/k/+X/5f/l/+X/5f/l/+X/5v/m/+b/5v/m/+b/5v/n/+f/5//n/+f/5//n/+j/6P/o/+j/6P/o/+j/6f/p/+n/6f/p/+n/6f/q/+r/6v/q/+r/6v/q/+v/6//r/+v/6//r/+v/7P/s/+z/7P/s/+z/7P/t/+3/7f/t/+3/7f/t/+7/7v/u/+7/7v/u/+7/7//v/+//7//v/+//7//w//D/8P/w//D/8P/w//H/8f/x//H/8f/x//H/8v/y//L/8v/y//L/8v/z//P/8//z//P/8//z//T/9P/0//T/9P/0//X/9f/1//X/9f/1//X/9v/2//b/9v/2//b/9v/3//f/9//3//f/9//3//j/+P/4//j/+P/4//j/+f/5//n/+f/5//n/+f/6//r/+v/6//r/+v/7//v/+//7//v/+//7//z//P/8//z//P/8//z//f/9//3//f/9//3//f/+//7//v/+//7//v///////////////////wAAAAAAAAAAAAAAAAAAAQABAAEAAQABAAEAAQACAAIAAgACAAIAAgADAAMAAwADAAMAAwADAAQABAAEAAQABAAEAAQABQAFAAUABQAFAAUABQAGAAYABgAGAAYABgAHAAcABwAHAAcABwAHAAgACAAIAAgACAAIAAgACQAJAAkACQAJAAkACgAKAAoACgAKAAoACgALAAsACwALAAsACwALAAwADAAMAAwADAAMAAwADQANAA0ADQANAA0ADgAOAA4ADgAOAA4ADgAPAA8ADwAPAA8ADwAPABAAEAAQABAAEAAQABAAEQARABEAEQARABEAEgASABIAEgASABIAEgATABMAEwATABMAEwATABQAFAAUABQAFAAUABQAFQAVABUAFQAVABUAFgAWABYAFgAWABYAFgAXABcAFwAXABcAFwAXABgAGAAYABgAGAAYABgAGQAZABkAGQAZABkAGQAaABoAGgAaABoAGgAbABsAGwAbABsAGwAbABwAHAAcABwAHAAcABwAHQAdAB0AHQAdAB0AHQAeAB4AHgAeAB4AHgAeAB8AHwAfAB8AHwAfAB8AIAAgACAAIAAgACAAIAAhACEAIQAhACEAIQAiACIAIgAiACIAIgAiACMAIwAjACMAIwAjACMAJAAkACQAJAAkACQAJAAlACUAJQAlACUAJQAlACYAJgAmACYAJgAmACYAJwAnACcAJwAnACcAJwAoACgAKAAoACgAKAAoACkAKQApACkAKQApACkAKQAqACoAKgAqACoAKgAqACsAKwArACsAKwArACsALAAsACwALAAsACwALAAtAC0ALQAtAC0ALQAtAC4ALgAuAC4ALgAuAC4ALwAvAC8ALwAvAC8ALwAvADAAMAAwADAAMAAwADAAMQAxADEAMQAxADEAMQAyADIAMgAyADIAMgAyADIAMwAzADMAMwAzADMAMwA0ADQANAA0ADQANAA0ADUANQA1ADUANQA1ADUANQA2ADYANgA2ADYANgA2ADcANwA3ADcANwA3ADcANwA4ADgAOAA4ADgAOAA4ADkAOQA5ADkAOQA5ADkAOQA6ADoAOgA6ADoAOgA6ADoAOwA7ADsAOwA7ADsAOwA8ADwAPAA8ADwAPAA8ADwAPQA9AD0APQA9AD0APQA9AD4APgA+AD4APgA+AD4APgA/AD8APwA/AD8APwA/AD8AQABAAEAAQABAAEAAQABAAEEAQQBBAEEAQQBBAEEAQQBCAEIAQgBCAEIAQgBCAEIAQwBDAEMAQwBDAEMAQwBDAEQARABEAEQARABEAEQARABFAEUARQBFAEUARQBFAEUARQBGAEYARgBGAEYARgBGAEYARwBHAEcARwBHAEcARwBHAEgASABIAEgASABIAEgASABIAEkASQBJAEkASQBJAEkASQBJAEoASgBKAEoASgBKAEoASgBLAEsASwBLAEsASwBLAEsASwBMAEwATABMAEwATABMAEwATABNAE0ATQBNAE0ATQBNAE0ATQBOAE4ATgBOAE4ATgBOAE4ATgBPAE8ATwBPAE8ATwBPAE8ATwBQAFAAUABQAFAAUABQAFAAUABQAFEAUQBRAFEAUQBRAFEAUQBRAFIAUgBSAFIAUgBSAFIAUgBSAFIAUwBTAFMAUwBTAFMAUwBTAFMAUwBUAFQAVABUAFQAVABUAFQAVABUAFUAVQBVAFUAVQBVAFUAVQBVAFUAVgBWAFYAVgBWAFYAVgBWAFYAVgBXAFcAVwBXAFcAVwBXAFcAVwBXAFgAWABYAFgAWABYAFgAWABYAFgAWABZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFsAWwBbAFsAWwBbAFsAWwBbAFsAWwBcAFwAXABcAFwAXABcAFwAXABcAFwAXABdAF0AXQBdAF0AXQBdAF0AXQBdAF0AXQBeAF4AXgBeAF4AXgBeAF4AXgBeAF4AXgBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGMAYwBjAGMAYwBjAGMAYwBjAGMAYwBjAGMAYwBjAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGUAZQBlAGUAZQBlAGUAZQBlAGUAZQBlAGUAZQBlAGYAZgBmAGYAZgBmAGYAZgBmAGYAZgBmAGYAZgBmAGYAZgBnAGcAZwBnAGcAZwBnAGcAZwBnAGcAZwBnAGcAZwBnAGcAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABpAGkAaQBpAGkAaQBpAGkAaQBpAGkAaQBpAGkAaQBpAGkAaQBpAGkAagBqAGoAagBqAGoAagBqAGoAagBqAGoAagBqAGoAagBqAGoAagBqAGoAagBrAGsAawBrAGsAawBrAGsAawBrAGsAawBrAGsAawBrAGsAawBrAGsAawBrAGsAawBrAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAG0AbQBtAG0AbQBtAG0AbQBtAG0AbQBtAG0AbQBtAG0AbQBtAG0AbQBtAG0AbQBtAG0AbQBtAG0AbQBtAG0AbQBtAG0AbQBtAG0AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbwBvAG8AbwBvAG8AbwBvAG8AbwBvAG8AbwBvAG8AbwBvAG8AbwBvAG8AbwBvAG8AbwBvAG8AbwBvAG8AbwBvAG8AbwBvAG8AbwBvAG8AbwBvAG8AbwBvAG8AbwBvAG8AbwBvAG8AbwBvAG8AbwBvAG8AbwBvAG8AbwBvAG8AbwBvAG8AbwBvAG8AbwBvAG8AbwBvAG8AbwBvAG8AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbQBtAG0AbQBtAG0AbQBtAG0AbQBtAG0AbQBtAG0AbQBtAG0AbQBtAG0AbQBtAG0AbQBtAG0AbQBtAG0AbQBtAG0AbQBtAG0AbQBsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAawBrAGsAawBrAGsAawBrAGsAawBrAGsAawBrAGsAawBrAGsAawBrAGsAawBrAGsAawBqAGoAagBqAGoAagBqAGoAagBqAGoAagBqAGoAagBqAGoAagBqAGoAagBqAGkAaQBpAGkAaQBpAGkAaQBpAGkAaQBpAGkAaQBpAGkAaQBpAGkAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABnAGcAZwBnAGcAZwBnAGcAZwBnAGcAZwBnAGcAZwBnAGcAZgBmAGYAZgBmAGYAZgBmAGYAZgBmAGYAZgBmAGYAZgBlAGUAZQBlAGUAZQBlAGUAZQBlAGUAZQBlAGUAZQBkAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGQAZABjAGMAYwBjAGMAYwBjAGMAYwBjAGMAYwBjAGMAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYABgAGAAYABgAGAAYABgAGAAYABgAGAAXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXgBeAF4AXgBeAF4AXgBeAF4AXgBeAF4AXQBdAF0AXQBdAF0AXQBdAF0AXQBdAF0AXABcAFwAXABcAFwAXABcAFwAXABcAFsAWwBbAFsAWwBbAFsAWwBbAFsAWwBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWQBZAFkAWQBZAFkAWQBZAFkAWQBYAFgAWABYAFgAWABYAFgAWABYAFcAVwBXAFcAVwBXAFcAVwBXAFcAVgBWAFYAVgBWAFYAVgBWAFYAVgBVAFUAVQBVAFUAVQBVAFUAVQBVAFQAVABUAFQAVABUAFQAVABUAFQAUwBTAFMAUwBTAFMAUwBTAFMAUgBSAFIAUgBSAFIAUgBSAFIAUQBRAFEAUQBRAFEAUQBRAFEAUABQAFAAUABQAFAAUABQAFAATwBPAE8ATwBPAE8ATwBPAE8ATgBOAE4ATgBOAE4ATgBOAE4ATQBNAE0ATQBNAE0ATQBNAEwATABMAEwATABMAEwATABMAEsASwBLAEsASwBLAEsASwBKAEoASgBKAEoASgBKAEoASgBJAEkASQBJAEkASQBJAEkASABIAEgASABIAEgASABIAEcARwBHAEcARwBHAEcARwBGAEYARgBGAEYARgBGAEYARQBFAEUARQBFAEUARQBFAEQARABEAEQARABEAEQARABDAEMAQwBDAEMAQwBDAEMAQgBCAEIAQgBCAEIAQgBBAEEAQQBBAEEAQQBBAEEAQABAAEAAQABAAEAAQABAAD8APwA/AD8APwA/AD8APgA+AD4APgA+AD4APgA+AD0APQA9AD0APQA9AD0APAA8ADwAPAA8ADwAPAA7ADsAOwA7ADsAOwA7ADsAOgA6ADoAOgA6ADoAOgA5ADkAOQA5ADkAOQA5ADgAOAA4ADgAOAA4ADgANwA3ADcANwA3ADcANwA2ADYANgA2ADYANgA2ADUANQA1ADUANQA1ADUANAA0ADQANAA0ADQANAAzADMAMwAzADMAMwAzADIAMgAyADIAMgAyADIAMQAxADEAMQAxADEAMQAwADAAMAAwADAAMAAwAC8ALwAvAC8ALwAvAC4ALgAuAC4ALgAuAC4ALQAtAC0ALQAtAC0ALQAsACwALAAsACwALAArACsAKwArACsAKwArACoAKgAqACoAKgAqACoAKQApACkAKQApACkAKAAoACgAKAAoACgAKAAnACcAJwAnACcAJwAmACYAJgAmACYAJgAmACUAJQAlACUAJQAlACQAJAAkACQAJAAkACQAIwAjACMAIwAjACMAIgAiACIAIgAiACIAIgAhACEAIQAhACEAIQAgACAAIAAgACAAIAAfAB8AHwAfAB8AHwAfAB4AHgAeAB4AHgAeAB0AHQAdAB0AHQAdABwAHAAcABwAHAAcABwAGwAbABsAGwAbABsAGgAaABoAGgAaABoAGQAZABkAGQAZABkAGAAYABgAGAAYABgAGAAXABcAFwAXABcAFwAWABYAFgAWABYAFgAVABUAFQAVABUAFQAUABQAFAAUABQAFAATABMAEwATABMAEwATABIAEgASABIAEgASABEAEQARABEAEQARABAAEAAQABAAEAAQAA8ADwAPAA8ADwAPAA4ADgAOAA4ADgAOAA0ADQANAA0ADQANAAwADAAMAAwADAAMAAsACwALAAsACwALAAoACgAKAAoACgAKAAkACQAJAAkACQAJAAgACAAIAAgACAAIAAcABwAHAAcABwAHAAYABgAGAAYABgAGAAUABQAFAAUABQAFAAQABAAEAAQABAAEAAMAAwADAAMAAwADAAMAAgACAAIAAgACAAIAAQABAAEAAQABAAEAAAAAAAAAAAAAAP////////////////7//v/+//7//v/+//3//f/9//3//f/9//z//P/8//z//P/8//v/+//7//v/+//7//r/+v/6//r/+v/6//n/+f/5//n/+f/5//j/+P/4//j/+P/4//f/9//3//f/9//3//b/9v/2//b/9v/2//X/9f/1//X/9f/1//T/9P/0//T/9P/0//P/8//z//P/8//z//L/8v/y//L/8v/y//H/8f/x//H/8f/x//D/8P/w//D/8P/w/+//7//v/+//7//v/+7/7v/u/+7/7v/u/+3/7f/t/+3/7f/t/+z/7P/s/+z/7P/s/+v/6//r/+v/6//r/+r/6v/q/+r/6v/q/+n/6f/p/+n/6f/p/+j/6P/o/+j/6P/o/+f/5//n/+f/5//n/+b/5v/m/+b/5v/m/+X/5f/l/+X/5f/l/+T/5P/k/+T/5P/k/+T/4//j/+P/4//j/+P/4v/i/+L/4v/i/+L/4f/h/+H/4f/h/+H/4P/g/+D/4P/g/+D/3//f/9//3//f/9//3v/e/97/3v/e/97/3f/d/93/3f/d/93/3P/c/9z/3P/c/9z/2//b/9v/2//b/9v/2//a/9r/2v/a/9r/2v/Z/9n/2f/Z/9n/2f/Y/9j/2P/Y/9j/2P/X/9f/1//X/9f/1//W/9b/1v/W/9b/1v/W/9X/1f/V/9X/1f/V/9T/1P/U/9T/1P/U/9P/0//T/9P/0//T/9P/0v/S/9L/0v/S/9L/0f/R/9H/0f/R/9H/0P/Q/9D/0P/Q/9D/0P/P/8//z//P/8//z//O/87/zv/O/87/zv/N/83/zf/N/83/zf/N/8z/zP/M/8z/zP/M/8v/y//L/8v/y//L/8v/yv/K/8r/yv/K/8r/yf/J/8n/yf/J/8n/yf/I/8j/yP/I/8j/yP/H/8f/x//H/8f/x//H/8b/xv/G/8b/xv/G/8X/xf/F/8X/xf/F/8X/xP/E/8T/xP/E/8T/xP/D/8P/w//D/8P/w//C/8L/wv/C/8L/wv/C/8H/wf/B/8H/wf/B/8H/wP/A/8D/wP/A/8D/wP+//7//v/+//7//v/+//77/vv++/77/vv++/77/vf+9/73/vf+9/73/vP+8/7z/vP+8/7z/vP+7/7v/u/+7/7v/u/+7/7r/uv+6/7r/uv+6/7r/uf+5/7n/uf+5/7n/uf+5/7j/uP+4/7j/uP+4/7j/t/+3/7f/t/+3/7f/t/+2/7b/tv+2/7b/tv+2/7X/tf+1/7X/tf+1/7X/tP+0/7T/tP+0/7T/tP+0/7P/s/+z/7P/s/+z/7P/sv+y/7L/sv+y/7L/sv+y/7H/sf+x/7H/sf+x/7H/sP+w/7D/sP+w/7D/sP+w/6//r/+v/6//r/+v/6//r/+u/67/rv+u/67/rv+u/63/rf+t/63/rf+t/63/rf+s/6z/rP+s/6z/rP+s/6z/q/+r/6v/q/+r/6v/q/+r/6r/qv+q/6r/qv+q/6r/qv+p/6n/qf+p/6n/qf+p/6n/qP+o/6j/qP+o/6j/qP+o/6f/p/+n/6f/p/+n/6f/p/+n/6b/pv+m/6b/pv+m/6b/pv+l/6X/pf+l/6X/pf+l/6X/pf+k/6T/pP+k/6T/pP+k/6T/o/+j/6P/o/+j/6P/o/+j/6P/ov+i/6L/ov+i/6L/ov+i/6L/of+h/6H/of+h/6H/of+h/6H/oP+g/6D/oP+g/6D/oP+g/6D/n/+f/5//n/+f/5//n/+f/5//nv+e/57/nv+e/57/nv+e/57/nv+d/53/nf+d/53/nf+d/53/nf+c/5z/nP+c/5z/nP+c/5z/nP+c/5v/m/+b/5v/m/+b/5v/m/+b/5v/mv+a/5r/mv+a/5r/mv+a/5r/mv+Z/5n/mf+Z/5n/mf+Z/5n/mf+Z/5n/mP+Y/5j/mP+Y/5j/mP+Y/5j/mP+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/lv+W/5b/lv+W/5b/lv+W/5b/lv+W/5X/lf+V/5X/lf+V/5X/lf+V/5X/lf+V/5T/lP+U/5T/lP+U/5T/lP+U/5T/lP+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kP+Q/5D/kP+Q/5D/kP+Q/5D/kP+Q/5D/kP+Q/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+O/47/jv+O/47/jv+O/47/jv+O/47/jv+O/47/jv+N/43/jf+N/43/jf+N/43/jf+N/43/jf+N/43/jf+M/4z/jP+M/4z/jP+M/4z/jP+M/4z/jP+M/4z/jP+M/4z/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4r/iv+K/4r/iv+K/4r/iv+K/4r/iv+K/4r/iv+K/4r/iv+K/4r/if+J/4n/if+J/4n/if+J/4n/if+J/4n/if+J/4n/if+J/4n/if+J/4n/iP+I/4j/iP+I/4j/iP+I/4j/iP+I/4j/iP+I/4j/iP+I/4j/iP+I/4j/iP+I/4j/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/hv+G/4b/hv+G/4b/hv+G/4b/hv+G/4b/hv+G/4b/hv+G/4b/hv+G/4b/hv+G/4b/hv+G/4b/hv+G/4b/hv+G/4b/hv+G/4b/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4T/hP+E/4T/hP+E/4T/hP+E/4T/hP+E/4T/hP+E/4T/hP+E/4T/hP+E/4T/hP+E/4T/hP+E/4T/hP+E/4T/hP+E/4T/hP+E/4T/hP+E/4T/hP+E/4T/hP+E/4T/hP+E/4T/hP+E/4T/hP+E/4T/hP+E/4T/hP+E/4T/hP+E/4T/hP+E/4T/hP+E/4T/hP+E/4T/hP+E/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+F/4X/hf+G/4b/hv+G/4b/hv+G/4b/hv+G/4b/hv+G/4b/hv+G/4b/hv+G/4b/hv+G/4b/hv+G/4b/hv+G/4b/hv+G/4b/hv+G/4b/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/iP+I/4j/iP+I/4j/iP+I/4j/iP+I/4j/iP+I/4j/iP+I/4j/iP+I/4j/iP+I/4j/if+J/4n/if+J/4n/if+J/4n/if+J/4n/if+J/4n/if+J/4n/if+J/4r/iv+K/4r/iv+K/4r/iv+K/4r/iv+K/4r/iv+K/4r/iv+K/4r/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/jP+M/4z/jP+M/4z/jP+M/4z/jP+M/4z/jP+M/4z/jP+N/43/jf+N/43/jf+N/43/jf+N/43/jf+N/43/jf+O/47/jv+O/47/jv+O/47/jv+O/47/jv+O/47/jv+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/5D/kP+Q/5D/kP+Q/5D/kP+Q/5D/kP+Q/5D/kP+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+U/5T/lP+U/5T/lP+U/5T/lP+U/5T/lP+V/5X/lf+V/5X/lf+V/5X/lf+V/5X/lv+W/5b/lv+W/5b/lv+W/5b/lv+W/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+Y/5j/mP+Y/5j/mP+Y/5j/mP+Y/5n/mf+Z/5n/mf+Z/5n/mf+Z/5n/mv+a/5r/mv+a/5r/mv+a/5r/mv+b/5v/m/+b/5v/m/+b/5v/m/+b/5z/nP+c/5z/nP+c/5z/nP+c/53/nf+d/53/nf+d/53/nf+d/57/nv+e/57/nv+e/57/nv+e/57/n/+f/5//n/+f/5//n/+f/5//oP+g/6D/oP+g/6D/oP+g/6H/of+h/6H/of+h/6H/of+h/6L/ov+i/6L/ov+i/6L/ov+i/6P/o/+j/6P/o/+j/6P/o/+k/6T/pP+k/6T/pP+k/6T/pP+l/6X/pf+l/6X/pf+l/6X/pv+m/6b/pv+m/6b/pv+m/6f/p/+n/6f/p/+n/6f/p/+o/6j/qP+o/6j/qP+o/6j/qf+p/6n/qf+p/6n/qf+p/6r/qv+q/6r/qv+q/6r/q/+r/6v/q/+r/6v/q/+r/6z/rP+s/6z/rP+s/6z/rP+t/63/rf+t/63/rf+t/67/rv+u/67/rv+u/67/rv+v/6//r/+v/6//r/+v/7D/sP+w/7D/sP+w/7D/sf+x/7H/sf+x/7H/sf+y/7L/sv+y/7L/sv+y/7L/s/+z/7P/s/+z/7P/s/+0/7T/tP+0/7T/tP+0/7X/tf+1/7X/tf+1/7X/tv+2/7b/tv+2/7b/tv+3/7f/t/+3/7f/t/+4/7j/uP+4/7j/uP+4/7n/uf+5/7n/uf+5/7n/uv+6/7r/uv+6/7r/uv+7/7v/u/+7/7v/u/+8/7z/vP+8/7z/vP+8/73/vf+9/73/vf+9/73/vv++/77/vv++/77/v/+//7//v/+//7//v//A/8D/wP/A/8D/wP/B/8H/wf/B/8H/wf/C/8L/wv/C/8L/wv/C/8P/w//D/8P/w//D/8T/xP/E/8T/xP/E/8X/xf/F/8X/xf/F/8X/xv/G/8b/xv/G/8b/x//H/8f/x//H/8f/yP/I/8j/yP/I/8j/yf/J/8n/yf/J/8n/yf/K/8r/yv/K/8r/yv/L/8v/y//L/8v/y//M/8z/zP/M/8z/zP/N/83/zf/N/83/zf/O/87/zv/O/87/zv/P/8//z//P/8//z//Q/9D/0P/Q/9D/0P/R/9H/0f/R/9H/0f/S/9L/0v/S/9L/0v/T/9P/0//T/9P/0//U/9T/1P/U/9T/1f/V/9X/1f/V/9X/1v/W/9b/1v/W/9b/1//X/9f/1//X/9f/2P/Y/9j/2P/Y/9j/2f/Z/9n/2f/Z/9n/2v/a/9r/2v/a/9v/2//b/9v/2//b/9z/3P/c/9z/3P/c/93/3f/d/93/3f/e/97/3v/e/97/3v/f/9//3//f/9//3//g/+D/4P/g/+D/4f/h/+H/4f/h/+H/4v/i/+L/4v/i/+L/4//j/+P/4//j/+T/5P/k/+T/5P/k/+X/5f/l/+X/5f/l/+b/5v/m/+b/5v/n/+f/5//n/+f/5//o/+j/6P/o/+j/6f/p/+n/6f/p/+n/6v/q/+r/6v/q/+v/6//r/+v/6//r/+z/7P/s/+z/7P/t/+3/7f/t/+3/7f/u/+7/7v/u/+7/7//v/+//7//v/+//8P/w//D/8P/w//H/8f/x//H/8f/x//L/8v/y//L/8v/z//P/8//z//P/8//0//T/9P/0//T/9f/1//X/9f/1//X/9v/2//b/9v/2//f/9//3//f/9//3//j/+P/4//j/+P/5//n/+f/5//n/+v/6//r/+v/6//r/+//7//v/+//7//z//P/8//z//P/8//3//f/9//3//f/+//7//v/+//7/////////////////AAAAAAAAAAAAAAEAAQABAAEAAQABAAIAAgACAAIAAgADAAMAAwADAAMABAAEAAQABAAEAAQABQAFAAUABQAFAAYABgAGAAYABgAGAAcABwAHAAcABwAIAAgACAAIAAgACQAJAAkACQAJAAkACgAKAAoACgAKAAsACwALAAsACwALAAwADAAMAAwADAANAA0ADQANAA0ADgAOAA4ADgAOAA4ADwAPAA8ADwAPABAAEAAQABAAEAAQABEAEQARABEAEQASABIAEgASABIAEgATABMAEwATABMAFAAUABQAFAAUABQAFQAVABUAFQAVABYAFgAWABYAFgAWABcAFwAXABcAFwAYABgAGAAYABgAGAAZABkAGQAZABkAGgAaABoAGgAaABoAGwAbABsAGwAbABsAHAAcABwAHAAcAB0AHQAdAB0AHQAdAB4AHgAeAB4AHgAfAB8AHwAfAB8AHwAgACAAIAAgACAAIAAhACEAIQAhACEAIgAiACIAIgAiACIAIwAjACMAIwAjACMAJAAkACQAJAAkACUAJQAlACUAJQAlACYAJgAmACYAJgAmACcAJwAnACcAJwAnACgAKAAoACgAKAApACkAKQApACkAKQAqACoAKgAqACoAKgArACsAKwArACsAKwAsACwALAAsACwALAAtAC0ALQAtAC0ALgAuAC4ALgAuAC4ALwAvAC8ALwAvAC8AMAAwADAAMAAwADAAMQAxADEAMQAxADEAMgAyADIAMgAyADIAMwAzADMAMwAzADMANAA0ADQANAA0ADQANQA1ADUANQA1ADUANgA2ADYANgA2ADYANwA3ADcANwA3ADcANwA4ADgAOAA4ADgAOAA5ADkAOQA5ADkAOQA6ADoAOgA6ADoAOgA7ADsAOwA7ADsAOwA8ADwAPAA8ADwAPAA8AD0APQA9AD0APQA9AD4APgA+AD4APgA+AD8APwA/AD8APwA/AD8AQABAAEAAQABAAEAAQQBBAEEAQQBBAEEAQQBCAEIAQgBCAEIAQgBDAEMAQwBDAEMAQwBDAEQARABEAEQARABEAEUARQBFAEUARQBFAEUARgBGAEYARgBGAEYARgBHAEcARwBHAEcARwBIAEgASABIAEgASABIAEkASQBJAEkASQBJAEkASgBKAEoASgBKAEoASgBLAEsASwBLAEsASwBLAEwATABMAEwATABMAEwATQBNAE0ATQBNAE0ATQBOAE4ATgBOAE4ATgBOAE8ATwBPAE8ATwBPAE8AUABQAFAAUABQAFAAUABRAFEAUQBRAFEAUQBRAFEAUgBSAFIAUgBSAFIAUgBTAFMAUwBTAFMAUwBTAFQAVABUAFQAVABUAFQAVABVAFUAVQBVAFUAVQBVAFUAVgBWAFYAVgBWAFYAVgBXAFcAVwBXAFcAVwBXAFcAWABYAFgAWABYAFgAWABYAFkAWQBZAFkAWQBZAFkAWQBaAFoAWgBaAFoAWgBaAFoAWwBbAFsAWwBbAFsAWwBbAFwAXABcAFwAXABcAFwAXABdAF0AXQBdAF0AXQBdAF0AXQBeAF4AXgBeAF4AXgBeAF4AXwBfAF8AXwBfAF8AXwBfAF8AYABgAGAAYABgAGAAYABgAGAAYQBhAGEAYQBhAGEAYQBhAGEAYgBiAGIAYgBiAGIAYgBiAGIAYwBjAGMAYwBjAGMAYwBjAGMAZABkAGQAZABkAGQAZABkAGQAZQBlAGUAZQBlAGUAZQBlAGUAZQBmAGYAZgBmAGYAZgBmAGYAZgBmAGcAZwBnAGcAZwBnAGcAZwBnAGcAaABoAGgAaABoAGgAaABoAGgAaABpAGkAaQBpAGkAaQBpAGkAaQBpAGkAagBqAGoAagBqAGoAagBqAGoAagBrAGsAawBrAGsAawBrAGsAawBrAGsAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbQBtAG0AbQBtAG0AbQBtAG0AbQBtAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBuAG8AbwBvAG8AbwBvAG8AbwBvAG8AbwBvAG8AcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABxAHEAcQBxAHEAcQBxAHEAcQBxAHEAcQBxAHEAcgByAHIAcgByAHIAcgByAHIAcgByAHIAcgByAHMAcwBzAHMAcwBzAHMAcwBzAHMAcwBzAHMAcwBzAHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdQB1AHUAdQB1AHUAdQB1AHUAdQB1AHUAdQB1AHUAdQB2AHYAdgB2AHYAdgB2AHYAdgB2AHYAdgB2AHYAdgB2AHYAdgB2AHcAdwB3AHcAdwB3AHcAdwB3AHcAdwB3AHcAdwB3AHcAdwB3AHcAdwB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHkAeQB5AHkAeQB5AHkAeQB5AHkAeQB5AHkAeQB5AHkAeQB5AHkAeQB5AHkAeQB5AHkAegB6AHoAegB6AHoAegB6AHoAegB6AHoAegB6AHoAegB6AHoAegB6AHoAegB6AHoAegB6AHoAegB6AHoAegB6AHsAewB7AHsAewB7AHsAewB7AHsAewB7AHsAewB7AHsAewB7AHsAewB7AHsAewB7AHsAewB7AHsAewB7AHsAewB7AHsAewB7AHsAewB7AHsAewB7AHsAewB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHsAewB7AHsAewB7AHsAewB7AHsAewB7AHsAewB7AHsAewB7AHsAewB7AHsAewB7AHsAewB7AHsAewB7AHsAewB7AHsAewB7AHsAewB7AHsAewB7AHsAewB7AHoAegB6AHoAegB6AHoAegB6AHoAegB6AHoAegB6AHoAegB6AHoAegB6AHoAegB6AHoAegB6AHoAegB6AHoAeQB5AHkAeQB5AHkAeQB5AHkAeQB5AHkAeQB5AHkAeQB5AHkAeQB5AHkAeQB5AHkAeQB5AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB3AHcAdwB3AHcAdwB3AHcAdwB3AHcAdwB3AHcAdwB3AHcAdwB3AHcAdgB2AHYAdgB2AHYAdgB2AHYAdgB2AHYAdgB2AHYAdgB2AHYAdQB1AHUAdQB1AHUAdQB1AHUAdQB1AHUAdQB1AHUAdQB1AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAcwBzAHMAcwBzAHMAcwBzAHMAcwBzAHMAcwBzAHMAcwByAHIAcgByAHIAcgByAHIAcgByAHIAcgByAHIAcQBxAHEAcQBxAHEAcQBxAHEAcQBxAHEAcQBxAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAbwBvAG8AbwBvAG8AbwBvAG8AbwBvAG8AbwBuAG4AbgBuAG4AbgBuAG4AbgBuAG4AbgBtAG0AbQBtAG0AbQBtAG0AbQBtAG0AbQBsAGwAbABsAGwAbABsAGwAbABsAGwAbABrAGsAawBrAGsAawBrAGsAawBrAGsAagBqAGoAagBqAGoAagBqAGoAagBqAGkAaQBpAGkAaQBpAGkAaQBpAGkAaQBoAGgAaABoAGgAaABoAGgAaABoAGgAZwBnAGcAZwBnAGcAZwBnAGcAZwBmAGYAZgBmAGYAZgBmAGYAZgBmAGUAZQBlAGUAZQBlAGUAZQBlAGUAZABkAGQAZABkAGQAZABkAGQAZABjAGMAYwBjAGMAYwBjAGMAYwBiAGIAYgBiAGIAYgBiAGIAYgBhAGEAYQBhAGEAYQBhAGEAYQBhAGAAYABgAGAAYABgAGAAYABgAF8AXwBfAF8AXwBfAF8AXwBfAF4AXgBeAF4AXgBeAF4AXgBeAF0AXQBdAF0AXQBdAF0AXQBcAFwAXABcAFwAXABcAFwAXABbAFsAWwBbAFsAWwBbAFsAWgBaAFoAWgBaAFoAWgBaAFoAWQBZAFkAWQBZAFkAWQBZAFgAWABYAFgAWABYAFgAWABXAFcAVwBXAFcAVwBXAFcAVgBWAFYAVgBWAFYAVgBWAFUAVQBVAFUAVQBVAFUAVQBUAFQAVABUAFQAVABUAFQAUwBTAFMAUwBTAFMAUwBTAFIAUgBSAFIAUgBSAFIAUQBRAFEAUQBRAFEAUQBRAFAAUABQAFAAUABQAFAAUABPAE8ATwBPAE8ATwBPAE4ATgBOAE4ATgBOAE4ATQBNAE0ATQBNAE0ATQBNAEwATABMAEwATABMAEwASwBLAEsASwBLAEsASwBKAEoASgBKAEoASgBKAEoASQBJAEkASQBJAEkASQBIAEgASABIAEgASABIAEcARwBHAEcARwBHAEcARgBGAEYARgBGAEYARgBFAEUARQBFAEUARQBFAEQARABEAEQARABEAEQAQwBDAEMAQwBDAEMAQwBCAEIAQgBCAEIAQgBCAEEAQQBBAEEAQQBBAEEAQABAAEAAQABAAEAAPwA/AD8APwA/AD8APwA+AD4APgA+AD4APgA+AD0APQA9AD0APQA9ADwAPAA8ADwAPAA8ADwAOwA7ADsAOwA7ADsAOwA6ADoAOgA6ADoAOgA5ADkAOQA5ADkAOQA5ADgAOAA4ADgAOAA4ADcANwA3ADcANwA3ADcANgA2ADYANgA2ADYANQA1ADUANQA1ADUANQA0ADQANAA0ADQANAAzADMAMwAzADMAMwAzADIAMgAyADIAMgAyADEAMQAxADEAMQAxADAAMAAwADAAMAAwADAALwAvAC8ALwAvAC8ALgAuAC4ALgAuAC4ALQAtAC0ALQAtAC0ALQAsACwALAAsACwALAArACsAKwArACsAKwAqACoAKgAqACoAKgApACkAKQApACkAKQApACgAKAAoACgAKAAoACcAJwAnACcAJwAnACYAJgAmACYAJgAmACUAJQAlACUAJQAlACQAJAAkACQAJAAkACMAIwAjACMAIwAjACIAIgAiACIAIgAiACIAIQAhACEAIQAhACEAIAAgACAAIAAgACAAHwAfAB8AHwAfAB8AHgAeAB4AHgAeAB4AHQAdAB0AHQAdAB0AHAAcABwAHAAcABwAGwAbABsAGwAbABsAGgAaABoAGgAaABoAGQAZABkAGQAZABkAGAAYABgAGAAYABgAFwAXABcAFwAXABcAFgAWABYAFgAWABYAFQAVABUAFQAVABUAFAAUABQAFAAUABQAEwATABMAEwATABMAEgASABIAEgASABIAEQARABEAEQARABEAEAAQABAAEAAQABAADwAPAA8ADwAPAA8ADgAOAA4ADgAOAA4ADQANAA0ADQANAA0ADAAMAAwADAAMAAwACwALAAsACwALAAsACgAKAAoACgAKAAoACQAJAAkACQAJAAkACAAIAAgACAAIAAgABwAHAAcABwAHAAcABgAGAAYABgAGAAYABQAFAAUABQAFAAUABAAEAAQABAAEAAQAAwADAAMAAwADAAMAAgACAAIAAgACAAIAAQABAAEAAQABAAEAAAAAAAAAAAAAAP////////////////7//v/+//7//v/+//3//f/9//3//f/9//z//P/8//z//P/8//v/+//7//v/+//7//r/+v/6//r/+v/6//n/+f/5//n/+f/5//j/+P/4//j/+P/4//f/9//3//f/9//3//b/9v/2//b/9v/2//b/9f/1//X/9f/1//X/9P/0//T/9P/0//T/8//z//P/8//z//P/8v/y//L/8v/y//L/8f/x//H/8f/x//H/8P/w//D/8P/w//D/7//v/+//7//v/+//7v/u/+7/7v/u/+7/7f/t/+3/7f/t/+3/7P/s/+z/7P/s/+z/6//r/+v/6//r/+v/6//q/+r/6v/q/+r/6v/p/+n/6f/p/+n/6f/o/+j/6P/o/+j/6P/n/+f/5//n/+f/5//m/+b/5v/m/+b/5v/m/+X/5f/l/+X/5f/l/+T/5P/k/+T/5P/k/+P/4//j/+P/4//j/+L/4v/i/+L/4v/i/+L/4f/h/+H/4f/h/+H/4P/g/+D/4P/g/+D/3//f/9//3//f/9//3//e/97/3v/e/97/3v/d/93/3f/d/93/3f/c/9z/3P/c/9z/3P/c/9v/2//b/9v/2//b/9r/2v/a/9r/2v/a/9r/2f/Z/9n/2f/Z/9n/2P/Y/9j/2P/Y/9j/2P/X/9f/1//X/9f/1//W/9b/1v/W/9b/1v/W/9X/1f/V/9X/1f/V/9X/1P/U/9T/1P/U/9T/0//T/9P/0//T/9P/0//S/9L/0v/S/9L/0v/S/9H/0f/R/9H/0f/R/9D/0P/Q/9D/0P/Q/9D/z//P/8//z//P/8//z//O/87/zv/O/87/zv/O/83/zf/N/83/zf/N/83/zP/M/8z/zP/M/8z/zP/L/8v/y//L/8v/y//L/8r/yv/K/8r/yv/K/8r/yf/J/8n/yf/J/8n/yf/I/8j/yP/I/8j/yP/I/8f/x//H/8f/x//H/8f/xv/G/8b/xv/G/8b/xv/F/8X/xf/F/8X/xf/F/8T/xP/E/8T/xP/E/8T/xP/D/8P/w//D/8P/w//D/8L/wv/C/8L/wv/C/8L/wf/B/8H/wf/B/8H/wf/B/8D/wP/A/8D/wP/A/8D/v/+//7//v/+//7//v/+//77/vv++/77/vv++/77/vv+9/73/vf+9/73/vf+9/7z/vP+8/7z/vP+8/7z/vP+7/7v/u/+7/7v/u/+7/7v/uv+6/7r/uv+6/7r/uv+6/7n/uf+5/7n/uf+5/7n/uf+4/7j/uP+4/7j/uP+4/7j/t/+3/7f/t/+3/7f/t/+3/7b/tv+2/7b/tv+2/7b/tv+2/7X/tf+1/7X/tf+1/7X/tf+0/7T/tP+0/7T/tP+0/7T/tP+z/7P/s/+z/7P/s/+z/7P/sv+y/7L/sv+y/7L/sv+y/7L/sf+x/7H/sf+x/7H/sf+x/7H/sP+w/7D/sP+w/7D/sP+w/7D/r/+v/6//r/+v/6//r/+v/6//rv+u/67/rv+u/67/rv+u/67/rf+t/63/rf+t/63/rf+t/63/rP+s/6z/rP+s/6z/rP+s/6z/rP+r/6v/q/+r/6v/q/+r/6v/q/+q/6r/qv+q/6r/qv+q/6r/qv+q/6n/qf+p/6n/qf+p/6n/qf+p/6n/qP+o/6j/qP+o/6j/qP+o/6j/qP+n/6f/p/+n/6f/p/+n/6f/p/+n/6f/pv+m/6b/pv+m/6b/pv+m/6b/pv+l/6X/pf+l/6X/pf+l/6X/pf+l/6X/pP+k/6T/pP+k/6T/pP+k/6T/pP+k/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6L/ov+i/6L/ov+i/6L/ov+i/6L/ov+h/6H/of+h/6H/of+h/6H/of+h/6H/of+g/6D/oP+g/6D/oP+g/6D/oP+g/6D/oP+g/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//nv+e/57/nv+e/57/nv+e/57/nv+e/57/nv+d/53/nf+d/53/nf+d/53/nf+d/53/nf+d/53/nP+c/5z/nP+c/5z/nP+c/5z/nP+c/5z/nP+c/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5r/mv+a/5r/mv+a/5r/mv+a/5r/mv+a/5r/mv+a/5r/mf+Z/5n/mf+Z/5n/mf+Z/5n/mf+Z/5n/mf+Z/5n/mf+Z/5j/mP+Y/5j/mP+Y/5j/mP+Y/5j/mP+Y/5j/mP+Y/5j/mP+Y/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/lv+W/5b/lv+W/5b/lv+W/5b/lv+W/5b/lv+W/5b/lv+W/5b/lv+W/5b/lf+V/5X/lf+V/5X/lf+V/5X/lf+V/5X/lf+V/5X/lf+V/5X/lf+V/5X/lf+V/5X/lP+U/5T/lP+U/5T/lP+U/5T/lP+U/5T/lP+U/5T/lP+U/5T/lP+U/5T/lP+U/5T/lP+U/5T/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kf+R/5H/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+S/5L/kv+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+U/5T/lP+U/5T/lP+U/5T/lP+U/5T/lP+U/5T/lP+U/5T/lP+U/5T/lP+U/5T/lP+U/5T/lP+U/5X/lf+V/5X/lf+V/5X/lf+V/5X/lf+V/5X/lf+V/5X/lf+V/5X/lf+V/5X/lf+V/5b/lv+W/5b/lv+W/5b/lv+W/5b/lv+W/5b/lv+W/5b/lv+W/5b/lv+W/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+Y/5j/mP+Y/5j/mP+Y/5j/mP+Y/5j/mP+Y/5j/mP+Y/5j/mP+Z/5n/mf+Z/5n/mf+Z/5n/mf+Z/5n/mf+Z/5n/mf+Z/5n/mv+a/5r/mv+a/5r/mv+a/5r/mv+a/5r/mv+a/5r/mv+a/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5z/nP+c/5z/nP+c/5z/nP+c/5z/nP+c/5z/nP+c/53/nf+d/53/nf+d/53/nf+d/53/nf+d/53/nf+e/57/nv+e/57/nv+e/57/nv+e/57/nv+e/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+g/6D/oP+g/6D/oP+g/6D/oP+g/6D/oP+h/6H/of+h/6H/of+h/6H/of+h/6H/of+h/6L/ov+i/6L/ov+i/6L/ov+i/6L/ov+i/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+k/6T/pP+k/6T/pP+k/6T/pP+k/6T/pP+l/6X/pf+l/6X/pf+l/6X/pf+l/6X/pv+m/6b/pv+m/6b/pv+m/6b/pv+m/6f/p/+n/6f/p/+n/6f/p/+n/6f/p/+o/6j/qP+o/6j/qP+o/6j/qP+o/6n/qf+p/6n/qf+p/6n/qf+p/6n/qf+q/6r/qv+q/6r/qv+q/6r/qv+q/6v/q/+r/6v/q/+r/6v/q/+r/6v/rP+s/6z/rP+s/6z/rP+s/6z/rP+t/63/rf+t/63/rf+t/63/rf+u/67/rv+u/67/rv+u/67/rv+u/6//r/+v/6//r/+v/6//r/+v/7D/sP+w/7D/sP+w/7D/sP+w/7D/sf+x/7H/sf+x/7H/sf+x/7H/sv+y/7L/sv+y/7L/sv+y/7L/s/+z/7P/s/+z/7P/s/+z/7P/tP+0/7T/tP+0/7T/tP+0/7T/tf+1/7X/tf+1/7X/tf+1/7X/tv+2/7b/tv+2/7b/tv+2/7f/t/+3/7f/t/+3/7f/t/+3/7j/uP+4/7j/uP+4/7j/uP+5/7n/uf+5/7n/uf+5/7n/uf+6/7r/uv+6/7r/uv+6/7r/u/+7/7v/u/+7/7v/u/+7/7z/vP+8/7z/vP+8/7z/vP+8/73/vf+9/73/vf+9/73/vf++/77/vv++/77/vv++/77/v/+//7//v/+//7//v/+//8D/wP/A/8D/wP/A/8D/wP/B/8H/wf/B/8H/wf/B/8H/wv/C/8L/wv/C/8L/wv/C/8P/w//D/8P/w//D/8P/xP/E/8T/xP/E/8T/xP/E/8X/xf/F/8X/xf/F/8X/xf/G/8b/xv/G/8b/xv/G/8f/x//H/8f/x//H/8f/x//I/8j/yP/I/8j/yP/I/8n/yf/J/8n/yf/J/8n/yf/K/8r/yv/K/8r/yv/K/8v/y//L/8v/y//L/8v/y//M/8z/zP/M/8z/zP/M/83/zf/N/83/zf/N/83/zf/O/87/zv/O/87/zv/O/8//z//P/8//z//P/8//0P/Q/9D/0P/Q/9D/0P/R/9H/0f/R/9H/0f/R/9H/0v/S/9L/0v/S/9L/0v/T/9P/0//T/9P/0//T/9T/1P/U/9T/1P/U/9T/1f/V/9X/1f/V/9X/1f/W/9b/1v/W/9b/1v/W/9f/1//X/9f/1//X/9f/2P/Y/9j/2P/Y/9j/2P/Z/9n/2f/Z/9n/2f/Z/9r/2v/a/9r/2v/a/9r/2//b/9v/2//b/9v/2//c/9z/3P/c/9z/3P/c/93/3f/d/93/3f/d/93/3v/e/97/3v/e/97/3v/f/9//3//f/9//3//f/+D/4P/g/+D/4P/g/+D/4f/h/+H/4f/h/+H/4f/i/+L/4v/i/+L/4v/i/+P/4//j/+P/4//j/+P/5P/k/+T/5P/k/+T/5f/l/+X/5f/l/+X/5f/m/+b/5v/m/+b/5v/m/+f/5//n/+f/5//n/+f/6P/o/+j/6P/o/+j/6P/p/+n/6f/p/+n/6f/q/+r/6v/q/+r/6v/q/+v/6//r/+v/6//r/+v/7P/s/+z/7P/s/+z/7P/t/+3/7f/t/+3/7f/u/+7/7v/u/+7/7v/u/+//7//v/+//7//v/+//8P/w//D/8P/w//D/8P/x//H/8f/x//H/8f/y//L/8v/y//L/8v/y//P/8//z//P/8//z//P/9P/0//T/9P/0//T/9f/1//X/9f/1//X/9f/2//b/9v/2//b/9v/2//f/9//3//f/9//3//j/+P/4//j/+P/4//j/+f/5//n/+f/5//n/+f/6//r/+v/6//r/+v/6//v/+//7//v/+//7//z//P/8//z//P/8//z//f/9//3//f/9//3//f/+//7//v/+//7//v///////////////////wAAAAAAAAAAAAAAAAAAAQABAAEAAQABAAEAAQACAAIAAgACAAIAAgADAAMAAwADAAMAAwADAAQABAAEAAQABAAEAAQABQAFAAUABQAFAAUABQAGAAYABgAGAAYABgAHAAcABwAHAAcABwAHAAgACAAIAAgACAAIAAgACQAJAAkACQAJAAkACQAKAAoACgAKAAoACgALAAsACwALAAsACwALAAwADAAMAAwADAAMAAwADQANAA0ADQANAA0ADQAOAA4ADgAOAA4ADgAOAA8ADwAPAA8ADwAPAA8AEAAQABAAEAAQABAAEAARABEAEQARABEAEQARABIAEgASABIAEgASABMAEwATABMAEwATABMAFAAUABQAFAAUABQAFAAVABUAFQAVABUAFQAVABYAFgAWABYAFgAWABYAFwAXABcAFwAXABcAFwAYABgAGAAYABgAGAAYABkAGQAZABkAGQAZABkAGgAaABoAGgAaABoAGgAaABsAGwAbABsAGwAbABsAHAAcABwAHAAcABwAHAAdAB0AHQAdAB0AHQAdAB4AHgAeAB4AHgAeAB4AHwAfAB8AHwAfAB8AHwAgACAAIAAgACAAIAAgACAAIQAhACEAIQAhACEAIQAiACIAIgAiACIAIgAiACMAIwAjACMAIwAjACMAIwAkACQAJAAkACQAJAAkACUAJQAlACUAJQAlACUAJgAmACYAJgAmACYAJgAmACcAJwAnACcAJwAnACcAKAAoACgAKAAoACgAKAAoACkAKQApACkAKQApACkAKQAqACoAKgAqACoAKgAqACsAKwArACsAKwArACsAKwAsACwALAAsACwALAAsACwALQAtAC0ALQAtAC0ALQAuAC4ALgAuAC4ALgAuAC4ALwAvAC8ALwAvAC8ALwAvADAAMAAwADAAMAAwADAAMAAxADEAMQAxADEAMQAxADEAMgAyADIAMgAyADIAMgAyADMAMwAzADMAMwAzADMAMwA0ADQANAA0ADQANAA0ADQANQA1ADUANQA1ADUANQA1ADUANgA2ADYANgA2ADYANgA2ADcANwA3ADcANwA3ADcANwA4ADgAOAA4ADgAOAA4ADgAOAA5ADkAOQA5ADkAOQA5ADkAOgA6ADoAOgA6ADoAOgA6ADoAOwA7ADsAOwA7ADsAOwA7ADsAPAA8ADwAPAA8ADwAPAA8AD0APQA9AD0APQA9AD0APQA9AD4APgA+AD4APgA+AD4APgA+AD8APwA/AD8APwA/AD8APwA/AEAAQABAAEAAQABAAEAAQABAAEAAQQBBAEEAQQBBAEEAQQBBAEEAQgBCAEIAQgBCAEIAQgBCAEIAQwBDAEMAQwBDAEMAQwBDAEMAQwBEAEQARABEAEQARABEAEQARABEAEUARQBFAEUARQBFAEUARQBFAEYARgBGAEYARgBGAEYARgBGAEYARwBHAEcARwBHAEcARwBHAEcARwBHAEgASABIAEgASABIAEgASABIAEgASQBJAEkASQBJAEkASQBJAEkASQBKAEoASgBKAEoASgBKAEoASgBKAEoASwBLAEsASwBLAEsASwBLAEsASwBLAEwATABMAEwATABMAEwATABMAEwATABNAE0ATQBNAE0ATQBNAE0ATQBNAE0ATgBOAE4ATgBOAE4ATgBOAE4ATgBOAE4ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8AUABQAFAAUABQAFAAUABQAFAAUABQAFAAUQBRAFEAUQBRAFEAUQBRAFEAUQBRAFEAUQBSAFIAUgBSAFIAUgBSAFIAUgBSAFIAUgBTAFMAUwBTAFMAUwBTAFMAUwBTAFMAUwBTAFMAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBWAFYAVgBWAFYAVgBWAFYAVgBWAFYAVgBWAFYAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWwBbAFsAWwBbAFsAWwBbAFsAWwBbAFsAWwBbAFsAWwBbAFsAWwBbAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABdAF0AXQBdAF0AXQBdAF0AXQBdAF0AXQBdAF0AXQBdAF0AXQBdAF0AXQBdAF0AXgBeAF4AXgBeAF4AXgBeAF4AXgBeAF4AXgBeAF4AXgBeAF4AXgBeAF4AXgBeAF4AXgBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBiAGIAYgBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYQBhAGEAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXgBeAF4AXgBeAF4AXgBeAF4AXgBeAF4AXgBeAF4AXgBeAF4AXgBeAF4AXgBeAF4AXgBeAF0AXQBdAF0AXQBdAF0AXQBdAF0AXQBdAF0AXQBdAF0AXQBdAF0AXQBdAF0AXQBcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABbAFsAWwBbAFsAWwBbAFsAWwBbAFsAWwBbAFsAWwBbAFsAWwBbAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBWAFYAVgBWAFYAVgBWAFYAVgBWAFYAVgBWAFYAVgBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAUwBTAFMAUwBTAFMAUwBTAFMAUwBTAFMAUwBTAFIAUgBSAFIAUgBSAFIAUgBSAFIAUgBSAFIAUQBRAFEAUQBRAFEAUQBRAFEAUQBRAFEAUQBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE4ATgBOAE4ATgBOAE4ATgBOAE4ATgBOAE0ATQBNAE0ATQBNAE0ATQBNAE0ATQBNAEwATABMAEwATABMAEwATABMAEwATABLAEsASwBLAEsASwBLAEsASwBLAEsASwBKAEoASgBKAEoASgBKAEoASgBKAEoASQBJAEkASQBJAEkASQBJAEkASQBJAEgASABIAEgASABIAEgASABIAEgASABHAEcARwBHAEcARwBHAEcARwBHAEYARgBGAEYARgBGAEYARgBGAEYARgBFAEUARQBFAEUARQBFAEUARQBFAEQARABEAEQARABEAEQARABEAEQAQwBDAEMAQwBDAEMAQwBDAEMAQwBCAEIAQgBCAEIAQgBCAEIAQgBCAEEAQQBBAEEAQQBBAEEAQQBBAEEAQABAAEAAQABAAEAAQABAAEAAQAA/AD8APwA/AD8APwA/AD8APwA+AD4APgA+AD4APgA+AD4APgA+AD0APQA9AD0APQA9AD0APQA9ADwAPAA8ADwAPAA8ADwAPAA8ADwAOwA7ADsAOwA7ADsAOwA7ADsAOgA6ADoAOgA6ADoAOgA6ADoAOQA5ADkAOQA5ADkAOQA5ADkAOAA4ADgAOAA4ADgAOAA4ADgANwA3ADcANwA3ADcANwA3ADcANgA2ADYANgA2ADYANgA2ADYANQA1ADUANQA1ADUANQA1ADUANAA0ADQANAA0ADQANAA0ADMAMwAzADMAMwAzADMAMwAzADIAMgAyADIAMgAyADIAMgAyADEAMQAxADEAMQAxADEAMQAwADAAMAAwADAAMAAwADAAMAAvAC8ALwAvAC8ALwAvAC8ALgAuAC4ALgAuAC4ALgAuAC4ALQAtAC0ALQAtAC0ALQAtACwALAAsACwALAAsACwALAArACsAKwArACsAKwArACsAKwAqACoAKgAqACoAKgAqACoAKQApACkAKQApACkAKQApACgAKAAoACgAKAAoACgAKAAnACcAJwAnACcAJwAnACcAJgAmACYAJgAmACYAJgAmACUAJQAlACUAJQAlACUAJQAlACQAJAAkACQAJAAkACQAJAAjACMAIwAjACMAIwAjACMAIgAiACIAIgAiACIAIgAiACEAIQAhACEAIQAhACEAIAAgACAAIAAgACAAIAAgAB8AHwAfAB8AHwAfAB8AHwAeAB4AHgAeAB4AHgAeAB4AHQAdAB0AHQAdAB0AHQAdABwAHAAcABwAHAAcABwAHAAbABsAGwAbABsAGwAbABsAGgAaABoAGgAaABoAGgAaABkAGQAZABkAGQAZABkAGAAYABgAGAAYABgAGAAYABcAFwAXABcAFwAXABcAFwAWABYAFgAWABYAFgAWABYAFQAVABUAFQAVABUAFQAUABQAFAAUABQAFAAUABQAEwATABMAEwATABMAEwATABIAEgASABIAEgASABIAEQARABEAEQARABEAEQARABAAEAAQABAAEAAQABAAEAAPAA8ADwAPAA8ADwAPAA4ADgAOAA4ADgAOAA4ADgANAA0ADQANAA0ADQANAA0ADAAMAAwADAAMAAwADAALAAsACwALAAsACwALAAsACgAKAAoACgAKAAoACgAKAAkACQAJAAkACQAJAAkACAAIAAgACAAIAAgACAAIAAcABwAHAAcABwAHAAcABwAGAAYABgAGAAYABgAGAAUABQAFAAUABQAFAAUABQAEAAQABAAEAAQABAAEAAQAAwADAAMAAwADAAMAAwACAAIAAgACAAIAAgACAAIAAQABAAEAAQABAAEAAQABAAAAAAAAAAAAAAAAAAAA//////////////////////7//v/+//7//v/+//7//v/9//3//f/9//3//f/9//z//P/8//z//P/8//z//P/7//v/+//7//v/+//7//v/+v/6//r/+v/6//r/+v/6//n/+f/5//n/+f/5//n/+P/4//j/+P/4//j/+P/4//f/9//3//f/9//3//f/9//2//b/9v/2//b/9v/2//b/9f/1//X/9f/1//X/9f/1//T/9P/0//T/9P/0//T/8//z//P/8//z//P/8//z//L/8v/y//L/8v/y//L/8v/x//H/8f/x//H/8f/x//H/8P/w//D/8P/w//D/8P/w/+//7//v/+//7//v/+//7//u/+7/7v/u/+7/7v/u/+7/7f/t/+3/7f/t/+3/7f/t/+z/7P/s/+z/7P/s/+z/7P/r/+v/6//r/+v/6//r/+v/6v/q/+r/6v/q/+r/6v/q/+n/6f/p/+n/6f/p/+n/6f/o/+j/6P/o/+j/6P/o/+j/6P/n/+f/5//n/+f/5//n/+f/5v/m/+b/5v/m/+b/5v/m/+X/5f/l/+X/5f/l/+X/5f/k/+T/5P/k/+T/5P/k/+T/5P/j/+P/4//j/+P/4//j/+P/4v/i/+L/4v/i/+L/4v/i/+H/4f/h/+H/4f/h/+H/4f/h/+D/4P/g/+D/4P/g/+D/4P/f/9//3//f/9//3//f/9//3//e/97/3v/e/97/3v/e/97/3v/d/93/3f/d/93/3f/d/93/3P/c/9z/3P/c/9z/3P/c/9z/2//b/9v/2//b/9v/2//b/9v/2v/a/9r/2v/a/9r/2v/a/9r/2f/Z/9n/2f/Z/9n/2f/Z/9j/2P/Y/9j/2P/Y/9j/2P/Y/9f/1//X/9f/1//X/9f/1//X/9f/1v/W/9b/1v/W/9b/1v/W/9b/1f/V/9X/1f/V/9X/1f/V/9X/1P/U/9T/1P/U/9T/1P/U/9T/0//T/9P/0//T/9P/0//T/9P/0//S/9L/0v/S/9L/0v/S/9L/0v/R/9H/0f/R/9H/0f/R/9H/0f/R/9D/0P/Q/9D/0P/Q/9D/0P/Q/8//z//P/8//z//P/8//z//P/8//zv/O/87/zv/O/87/zv/O/87/zv/N/83/zf/N/83/zf/N/83/zf/N/8z/zP/M/8z/zP/M/8z/zP/M/8z/y//L/8v/y//L/8v/y//L/8v/y//K/8r/yv/K/8r/yv/K/8r/yv/K/8r/yf/J/8n/yf/J/8n/yf/J/8n/yf/I/8j/yP/I/8j/yP/I/8j/yP/I/8j/x//H/8f/x//H/8f/x//H/8f/x//G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xP/E/8T/xP/E/8T/xP/E/8T/xP/E/8P/w//D/8P/w//D/8P/w//D/8P/w//C/8L/wv/C/8L/wv/C/8L/wv/C/8L/wv/B/8H/wf/B/8H/wf/B/8H/wf/B/8H/wf/A/8D/wP/A/8D/wP/A/8D/wP/A/8D/wP+//7//v/+//7//v/+//7//v/+//7//v/+//77/vv++/77/vv++/77/vv++/77/vv++/77/vf+9/73/vf+9/73/vf+9/73/vf+9/73/vf+8/7z/vP+8/7z/vP+8/7z/vP+8/7z/vP+8/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+2/7b/tv+2/7b/tv+2/7b/tv+2/7b/tv+2/7b/tv+2/7b/tf+1/7X/tf+1/7X/tf+1/7X/tf+1/7X/tf+1/7X/tf+1/7T/tP+0/7T/tP+0/7T/tP+0/7T/tP+0/7T/tP+0/7T/tP+0/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+y/7L/sv+y/7L/sv+y/7L/sv+y/7L/sv+y/7L/sv+y/7L/sv+y/7L/sf+x/7H/sf+x/7H/sf+x/7H/sf+x/7H/sf+x/7H/sf+x/7H/sf+x/7H/sf+w/7D/sP+w/7D/sP+w/7D/sP+w/7D/sP+w/7D/sP+w/7D/sP+w/7D/sP+w/7D/sP+w/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/67/rv+u/67/rv+u/67/rv+u/67/rv+u/67/rv+u/67/rv+u/67/rv+u/67/rv+u/67/rv+u/67/rv+u/67/rf+t/63/rf+t/63/rf+t/63/rf+t/63/rf+t/63/rf+t/63/rf+t/63/rf+t/63/rf+t/63/rf+t/63/rf+t/63/rf+t/63/rf+t/63/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rP+s/6z/rf+t/63/rf+t/63/rf+t/63/rf+t/63/rf+t/63/rf+t/63/rf+t/63/rf+t/63/rf+t/63/rf+t/63/rf+t/63/rf+t/63/rf+t/63/rv+u/67/rv+u/67/rv+u/67/rv+u/67/rv+u/67/rv+u/67/rv+u/67/rv+u/67/rv+u/67/rv+u/67/rv+u/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//sP+w/7D/sP+w/7D/sP+w/7D/sP+w/7D/sP+w/7D/sP+w/7D/sP+w/7D/sP+w/7D/sP+x/7H/sf+x/7H/sf+x/7H/sf+x/7H/sf+x/7H/sf+x/7H/sf+x/7H/sf+x/7H/sv+y/7L/sv+y/7L/sv+y/7L/sv+y/7L/sv+y/7L/sv+y/7L/sv+y/7L/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7T/tP+0/7T/tP+0/7T/tP+0/7T/tP+0/7T/tP+0/7T/tP+0/7X/tf+1/7X/tf+1/7X/tf+1/7X/tf+1/7X/tf+1/7X/tf+1/7b/tv+2/7b/tv+2/7b/tv+2/7b/tv+2/7b/tv+2/7b/tv+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+4/7j/uP+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+5/7n/uf+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+6/7r/uv+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/vP+8/7z/vP+8/7z/vP+8/7z/vP+8/7z/vP+8/73/vf+9/73/vf+9/73/vf+9/73/vf+9/73/vf++/77/vv++/77/vv++/77/vv++/77/vv++/77/v/+//7//v/+//7//v/+//7//v/+//7//v//A/8D/wP/A/8D/wP/A/8D/wP/A/8D/wP/A/8H/wf/B/8H/wf/B/8H/wf/B/8H/wf/B/8L/wv/C/8L/wv/C/8L/wv/C/8L/wv/C/8L/w//D/8P/w//D/8P/w//D/8P/w//D/8P/xP/E/8T/xP/E/8T/xP/E/8T/xP/E/8T/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8j/yP/I/8j/yP/I/8j/yP/I/8j/yP/J/8n/yf/J/8n/yf/J/8n/yf/J/8n/yv/K/8r/yv/K/8r/yv/K/8r/yv/K/8v/y//L/8v/y//L/8v/y//L/8v/y//M/8z/zP/M/8z/zP/M/8z/zP/M/8z/zf/N/83/zf/N/83/zf/N/83/zf/N/87/zv/O/87/zv/O/87/zv/O/87/z//P/8//z//P/8//z//P/8//z//P/9D/0P/Q/9D/0P/Q/9D/0P/Q/9D/0f/R/9H/0f/R/9H/0f/R/9H/0f/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0//T/9P/0//T/9P/0//T/9P/0//U/9T/1P/U/9T/1P/U/9T/1P/U/9X/1f/V/9X/1f/V/9X/1f/V/9X/1v/W/9b/1v/W/9b/1v/W/9b/1v/X/9f/1//X/9f/1//X/9f/1//Y/9j/2P/Y/9j/2P/Y/9j/2P/Y/9n/2f/Z/9n/2f/Z/9n/2f/Z/9n/2v/a/9r/2v/a/9r/2v/a/9r/2v/b/9v/2//b/9v/2//b/9v/2//c/9z/3P/c/9z/3P/c/9z/3P/c/93/3f/d/93/3f/d/93/3f/d/97/3v/e/97/3v/e/97/3v/e/97/3//f/9//3//f/9//3//f/9//4P/g/+D/4P/g/+D/4P/g/+D/4f/h/+H/4f/h/+H/4f/h/+H/4f/i/+L/4v/i/+L/4v/i/+L/4v/j/+P/4//j/+P/4//j/+P/4//k/+T/5P/k/+T/5P/k/+T/5P/l/+X/5f/l/+X/5f/l/+X/5f/l/+b/5v/m/+b/5v/m/+b/5v/m/+f/5//n/+f/5//n/+f/5//n/+j/6P/o/+j/6P/o/+j/6P/o/+n/6f/p/+n/6f/p/+n/6f/p/+r/6v/q/+r/6v/q/+r/6v/q/+v/6//r/+v/6//r/+v/6//r/+z/7P/s/+z/7P/s/+z/7P/s/+3/7f/t/+3/7f/t/+3/7f/t/+7/7v/u/+7/7v/u/+7/7v/u/+//7//v/+//7//v/+//7//v//D/8P/w//D/8P/w//D/8P/w//H/8f/x//H/8f/x//H/8f/x//L/8v/y//L/8v/y//L/8v/y//P/8//z//P/8//z//P/8//z//T/9P/0//T/9P/0//T/9P/0//X/9f/1//X/9f/1//X/9f/1//b/9v/2//b/9v/2//b/9v/2//f/9//3//f/9//3//f/9//3//j/+P/4//j/+P/4//j/+P/4//n/+f/5//n/+f/5//n/+f/6//r/+v/6//r/+v/6//r/+v/7//v/+//7//v/+//7//v/+//8//z//P/8//z//P/8//z//P/9//3//f/9//3//f/9//3//f/+//7//v/+//7//v/+//7//v////////////////////////8AAAAAAAAAAAAAAAAAAAAAAAABAAEAAQABAAEAAQABAAEAAQACAAIAAgACAAIAAgACAAIAAgADAAMAAwADAAMAAwADAAMAAwAEAAQABAAEAAQABAAEAAQABAAFAAUABQAFAAUABQAFAAUABQAGAAYABgAGAAYABgAGAAYABgAHAAcABwAHAAcABwAHAAcABwAIAAgACAAIAAgACAAIAAgACAAJAAkACQAJAAkACQAJAAkACQAKAAoACgAKAAoACgAKAAoACgAKAAsACwALAAsACwALAAsACwALAAwADAAMAAwADAAMAAwADAAMAA0ADQANAA0ADQANAA0ADQANAA4ADgAOAA4ADgAOAA4ADgAOAA4ADwAPAA8ADwAPAA8ADwAPAA8AEAAQABAAEAAQABAAEAAQABAAEQARABEAEQARABEAEQARABEAEQASABIAEgASABIAEgASABIAEgATABMAEwATABMAEwATABMAEwATABQAFAAUABQAFAAUABQAFAAUABUAFQAVABUAFQAVABUAFQAVABUAFgAWABYAFgAWABYAFgAWABYAFwAXABcAFwAXABcAFwAXABcAFwAYABgAGAAYABgAGAAYABgAGAAYABkAGQAZABkAGQAZABkAGQAZABkAGgAaABoAGgAaABoAGgAaABoAGgAbABsAGwAbABsAGwAbABsAGwAbABwAHAAcABwAHAAcABwAHAAcABwAHQAdAB0AHQAdAB0AHQAdAB0AHQAeAB4AHgAeAB4AHgAeAB4AHgAeAB8AHwAfAB8AHwAfAB8AHwAfAB8AIAAgACAAIAAgACAAIAAgACAAIAAgACEAIQAhACEAIQAhACEAIQAhACEAIgAiACIAIgAiACIAIgAiACIAIgAiACMAIwAjACMAIwAjACMAIwAjACMAJAAkACQAJAAkACQAJAAkACQAJAAkACUAJQAlACUAJQAlACUAJQAlACUAJQAmACYAJgAmACYAJgAmACYAJgAmACYAJwAnACcAJwAnACcAJwAnACcAJwAnACgAKAAoACgAKAAoACgAKAAoACgAKAApACkAKQApACkAKQApACkAKQApACkAKQAqACoAKgAqACoAKgAqACoAKgAqACoAKwArACsAKwArACsAKwArACsAKwArACsALAAsACwALAAsACwALAAsACwALAAsACwALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALwAvAC8ALwAvAC8ALwAvAC8ALwAvAC8AMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAxADEAMQAxADEAMQAxADEAMQAxADEAMQAxADIAMgAyADIAMgAyADIAMgAyADIAMgAyADIAMwAzADMAMwAzADMAMwAzADMAMwAzADMAMwA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANQA1ADUANQA1ADUANQA1ADUANQA1ADUANQA1ADYANgA2ADYANgA2ADYANgA2ADYANgA2ADYANgA3ADcANwA3ADcANwA3ADcANwA3ADcANwA3ADcANwA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA9AD0APQA9AD0APQA9AD0APQA9AD0APQA9AD0APQA9AD0APQA+AD4APgA+AD4APgA+AD4APgA+AD4APgA+AD4APgA+AD4APgA/AD8APwA/AD8APwA/AD8APwA/AD8APwA/AD8APwA/AD8APwA/AD8AQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEIAQgBCAEIAQgBCAEIAQgBCAEIAQgBCAEIAQgBCAEIAQgBCAEIAQgBCAEIAQgBCAEMAQwBDAEMAQwBDAEMAQwBDAEMAQwBDAEMAQwBDAEMAQwBDAEMAQwBDAEMAQwBDAEMAQwBEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABFAEUARQBFAEUARQBFAEUARQBFAEUARQBFAEUARQBFAEUARQBFAEUARQBFAEUARQBFAEUARQBFAEUARQBFAEUARQBFAEYARgBGAEYARgBGAEYARgBGAEYARgBGAEYARgBGAEYARgBGAEYARgBGAEYARgBGAEYARgBGAEYARgBGAEYARgBGAEYARgBGAEYARgBGAEYARgBGAEYARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARwBHAEcARgBGAEYARgBGAEYARgBGAEYARgBGAEYARgBGAEYARgBGAEYARgBGAEYARgBGAEYARgBGAEYARgBGAEYARgBGAEYARgBGAEYARgBGAEYARgBGAEYARgBGAEUARQBFAEUARQBFAEUARQBFAEUARQBFAEUARQBFAEUARQBFAEUARQBFAEUARQBFAEUARQBFAEUARQBFAEUARQBFAEUARQBEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABDAEMAQwBDAEMAQwBDAEMAQwBDAEMAQwBDAEMAQwBDAEMAQwBDAEMAQwBDAEMAQwBDAEMAQwBCAEIAQgBCAEIAQgBCAEIAQgBCAEIAQgBCAEIAQgBCAEIAQgBCAEIAQgBCAEIAQgBCAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAD8APwA/AD8APwA/AD8APwA/AD8APwA/AD8APwA/AD8APwA/AD8APwA/AD4APgA+AD4APgA+AD4APgA+AD4APgA+AD4APgA+AD4APgA+AD4APgA9AD0APQA9AD0APQA9AD0APQA9AD0APQA9AD0APQA9AD0APQA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA7ADsAOwA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOgA6ADoAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA5ADkAOQA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADcANwA3ADcANwA3ADcANwA3ADcANwA3ADcANwA3ADcANgA2ADYANgA2ADYANgA2ADYANgA2ADYANgA2ADYANQA1ADUANQA1ADUANQA1ADUANQA1ADUANQA1ADUANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADMAMwAzADMAMwAzADMAMwAzADMAMwAzADMAMwAzADIAMgAyADIAMgAyADIAMgAyADIAMgAyADIAMgAxADEAMQAxADEAMQAxADEAMQAxADEAMQAxADEAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAvAC8ALwAvAC8ALwAvAC8ALwAvAC8ALwAvAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtACwALAAsACwALAAsACwALAAsACwALAAsACsAKwArACsAKwArACsAKwArACsAKwArACsAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgApACkAKQApACkAKQApACkAKQApACkAKQAoACgAKAAoACgAKAAoACgAKAAoACgAKAAnACcAJwAnACcAJwAnACcAJwAnACcAJwAmACYAJgAmACYAJgAmACYAJgAmACYAJgAlACUAJQAlACUAJQAlACUAJQAlACUAJQAkACQAJAAkACQAJAAkACQAJAAkACQAJAAjACMAIwAjACMAIwAjACMAIwAjACMAIwAiACIAIgAiACIAIgAiACIAIgAiACIAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIAAgACAAIAAgACAAIAAgACAAIAAgAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHAAcABwAHAAcABwAHAAcABwAHAAcABwAGwAbABsAGwAbABsAGwAbABsAGwAbABoAGgAaABoAGgAaABoAGgAaABoAGgAZABkAGQAZABkAGQAZABkAGQAZABkAGAAYABgAGAAYABgAGAAYABgAGAAYABcAFwAXABcAFwAXABcAFwAXABcAFwAWABYAFgAWABYAFgAWABYAFgAWABYAFQAVABUAFQAVABUAFQAVABUAFQAVABQAFAAUABQAFAAUABQAFAAUABQAFAATABMAEwATABMAEwATABMAEwATABIAEgASABIAEgASABIAEgASABIAEgARABEAEQARABEAEQARABEAEQARABEAEAAQABAAEAAQABAAEAAQABAAEAAQAA8ADwAPAA8ADwAPAA8ADwAPAA8ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA0ADQANAA0ADQANAA0ADQANAA0ADQAMAAwADAAMAAwADAAMAAwADAAMAAwACwALAAsACwALAAsACwALAAsACwAKAAoACgAKAAoACgAKAAoACgAKAAoACQAJAAkACQAJAAkACQAJAAkACQAJAAgACAAIAAgACAAIAAgACAAIAAgABwAHAAcABwAHAAcABwAHAAcABwAHAAYABgAGAAYABgAGAAYABgAGAAYABgAFAAUABQAFAAUABQAFAAUABQAFAAQABAAEAAQABAAEAAQABAAEAAQABAADAAMAAwADAAMAAwADAAMAAwADAAMAAgACAAIAAgACAAIAAgACAAIAAgABAAEAAQABAAEAAQABAAEAAQABAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/////////////////////////////+//7//v/+//7//v/+//7//v/+//3//f/9//3//f/9//3//f/9//3//f/8//z//P/8//z//P/8//z//P/8//z/+//7//v/+//7//v/+//7//v/+//7//r/+v/6//r/+v/6//r/+v/6//r/+v/5//n/+f/5//n/+f/5//n/+f/5//n/+P/4//j/+P/4//j/+P/4//j/+P/4//f/9//3//f/9//3//f/9//3//f/9//2//b/9v/2//b/9v/2//b/9v/2//b/9f/1//X/9f/1//X/9f/1//X/9f/1//T/9P/0//T/9P/0//T/9P/0//T/9P/0//P/8//z//P/8//z//P/8//z//P/8//y//L/8v/y//L/8v/y//L/8v/y//L/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8P/w//D/8P/w//D/8P/w//D/8P/w/+//7//v/+//7//v/+//7//v/+//7//v/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/r/+v/6//r/+v/6//r/+v/6//r/+v/6//q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6f/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/n/+f/5//n/+f/5//n/+f/5//n/+f/5//m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/9//3//f/9//3//f/9//3//f/9//3//f/9//3//e/97/3v/e/97/3v/e/97/3v/e/97/3v/e/93/3f/d/93/3f/d/93/3f/d/93/3f/d/93/3f/d/9z/3P/c/9z/3P/c/9z/3P/c/9z/3P/c/9z/3P/b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2v/a/9r/2v/a/9r/2v/a/9r/2v/a/9r/2v/a/9r/2f/Z/9n/2f/Z/9n/2f/Z/9n/2f/Z/9n/2f/Z/9n/2f/Y/9j/2P/Y/9j/2P/Y/9j/2P/Y/9j/2P/Y/9j/2P/X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9b/1v/W/9b/1v/W/9b/1v/W/9b/1v/W/9b/1v/W/9b/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9H/0f/R/9H/0f/R/9H/0f/R/9H/0f/R/9H/0f/R/9H/0f/R/9H/0P/Q/9D/0P/Q/9D/0P/Q/9D/0P/Q/9D/0P/Q/9D/0P/Q/9D/0P/Q/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//O/87/zv/O/87/zv/O/87/zv/O/87/zv/O/87/zv/O/87/zv/O/87/zv/O/83/zf/N/83/zf/N/83/zf/N/83/zf/N/83/zf/N/83/zf/N/83/zf/N/83/zf/M/8z/zP/M/8z/zP/M/8z/zP/M/8z/zP/M/8z/zP/M/8z/zP/M/8z/zP/M/8z/zP/M/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8r/yv/K/8r/yv/K/8r/yv/K/8r/yv/K/8r/yv/K/8r/yv/K/8r/yv/K/8r/yv/K/8r/yv/K/8r/yv/J/8n/yf/J/8n/yf/J/8n/yf/J/8n/yf/J/8n/yf/J/8n/yf/J/8n/yf/J/8n/yf/J/8n/yf/J/8n/yf/J/8n/yf/I/8j/yP/I/8j/yP/I/8j/yP/I/8j/yP/I/8j/yP/I/8j/yP/I/8j/yP/I/8j/yP/I/8j/yP/I/8j/yP/I/8j/yP/I/8j/yP/I/8j/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8b/xv/G/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8j/yP/I/8j/yP/I/8j/yP/I/8j/yP/I/8j/yP/I/8j/yP/I/8j/yP/I/8j/yP/I/8j/yP/I/8j/yP/I/8j/yP/I/8j/yP/I/8j/yP/I/8n/yf/J/8n/yf/J/8n/yf/J/8n/yf/J/8n/yf/J/8n/yf/J/8n/yf/J/8n/yf/J/8n/yf/J/8n/yf/J/8n/yf/J/8n/yv/K/8r/yv/K/8r/yv/K/8r/yv/K/8r/yv/K/8r/yv/K/8r/yv/K/8r/yv/K/8r/yv/K/8r/yv/K/8r/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//M/8z/zP/M/8z/zP/M/8z/zP/M/8z/zP/M/8z/zP/M/8z/zP/M/8z/zP/M/8z/zP/M/8z/zf/N/83/zf/N/83/zf/N/83/zf/N/83/zf/N/83/zf/N/83/zf/N/83/zf/N/83/zf/O/87/zv/O/87/zv/O/87/zv/O/87/zv/O/87/zv/O/87/zv/O/87/zv/O/87/z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//Q/9D/0P/Q/9D/0P/Q/9D/0P/Q/9D/0P/Q/9D/0P/Q/9D/0P/Q/9D/0P/R/9H/0f/R/9H/0f/R/9H/0f/R/9H/0f/R/9H/0f/R/9H/0f/R/9H/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9L/0v/S/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/U/9T/1P/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/V/9X/1f/W/9b/1v/W/9b/1v/W/9b/1v/W/9b/1v/W/9b/1v/W/9b/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/2P/Y/9j/2P/Y/9j/2P/Y/9j/2P/Y/9j/2P/Y/9j/2P/Y/9n/2f/Z/9n/2f/Z/9n/2f/Z/9n/2f/Z/9n/2f/Z/9n/2v/a/9r/2v/a/9r/2v/a/9r/2v/a/9r/2v/a/9r/2v/b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9z/3P/c/9z/3P/c/9z/3P/c/9z/3P/c/9z/3P/c/9z/3f/d/93/3f/d/93/3f/d/93/3f/d/93/3f/d/93/3f/e/97/3v/e/97/3v/e/97/3v/e/97/3v/e/97/3v/f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+n/6f/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6f/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7//v/+//7//v/+//7//v/+//7//v/+//7//w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8//z//P/8//z//P/8//z//P/8//z//P/8//0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//f/9//3//f/9//3//f/9//3//f/9//3//f/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/7//v/+//7//v/+//7//v/+//7//v/+//7//z//P/8//z//P/8//z//P/8//z//P/8//z//P/9//3//f/9//3//f/9//3//f/9//3//f/9//7//v/+//7//v/+//7//v/+//7//v/+//7//////////////////////////////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACwALAAsACwALAAsACwALAAsACwALAAsACwALAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAZABkAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACIAIgAiACIAIgAiACIAIgAiACIAIgAiACIAIgAiACIAIgAiACIAIgAiACMAIwAjACMAIwAjACMAIwAjACMAIwAjACMAIwAjACMAIwAjACMAIwAjACMAIwAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAmACYAJgAmACYAJgAmACYAJgAmACYAJgAmACYAJgAmACYAJgAmACYAJgAmACYAJgAmACYAJgAnACcAJwAnACcAJwAnACcAJwAnACcAJwAnACcAJwAnACcAJwAnACcAJwAnACcAJwAnACcAJwAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC4ALgAuAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAJwAnACcAJwAnACcAJwAnACcAJwAnACcAJwAnACcAJwAnACcAJwAnACcAJwAnACcAJwAnACcAJwAnACcAJgAmACYAJgAmACYAJgAmACYAJgAmACYAJgAmACYAJgAmACYAJgAmACYAJgAmACYAJgAmACYAJgAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAIwAjACMAIwAjACMAIwAjACMAIwAjACMAIwAjACMAIwAjACMAIwAjACMAIwAjACMAIgAiACIAIgAiACIAIgAiACIAIgAiACIAIgAiACIAIgAiACIAIgAiACIAIgAiACIAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAfAB8AHwAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABkAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAVABUAFQAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////////////////////////////////////////////v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6f/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4P/g/+D/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+H/4f/h/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4v/i/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/k/+T/5P/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/l/+X/5f/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/m/+b/5v/n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6P/o/+j/6f/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6f/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+r/6v/q/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/s/+z/7P/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+3/7f/t/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7v/u/+7/7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/w//D/8P/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8f/x//H/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8v/y//L/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/0//T/9P/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/2//b/9v/3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v////////////////////////////////////////////////////////////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEwATABMAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABIAEgASABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABEAEQARABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/4//j/+P/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/5//n/+f/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF9QTVi2EwAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxMzcgNzkuMTU5NzY4LCAyMDE2LzA4LzExLTEzOjI0OjQyICAgICAgICAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp4bXBETT0iaHR0cDovL25zLmFkb2JlLmNvbS94bXAvMS4wL0R5bmFtaWNNZWRpYS8iCiAgICAgICAgICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIKICAgICAgICAgICAgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iCiAgICAgICAgICAgIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiCiAgICAgICAgICAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyI+CiAgICAgICAgIDx4bXBETTpUcmFja3M+CiAgICAgICAgICAgIDxyZGY6QmFnPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHhtcERNOnRyYWNrTmFtZT5DdWVQb2ludCBNYXJrZXJzPC94bXBETTp0cmFja05hbWU+CiAgICAgICAgICAgICAgICAgIDx4bXBETTp0cmFja1R5cGU+Q3VlPC94bXBETTp0cmFja1R5cGU+CiAgICAgICAgICAgICAgICAgIDx4bXBETTpmcmFtZVJhdGU+ZjQ0MTAwPC94bXBETTpmcmFtZVJhdGU+CiAgICAgICAgICAgICAgIDwvcmRmOmxpPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHhtcERNOnRyYWNrTmFtZT5DRCBUcmFjayBNYXJrZXJzPC94bXBETTp0cmFja05hbWU+CiAgICAgICAgICAgICAgICAgIDx4bXBETTp0cmFja1R5cGU+VHJhY2s8L3htcERNOnRyYWNrVHlwZT4KICAgICAgICAgICAgICAgICAgPHhtcERNOmZyYW1lUmF0ZT5mNDQxMDA8L3htcERNOmZyYW1lUmF0ZT4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICA8eG1wRE06dHJhY2tOYW1lPlN1YmNsaXAgTWFya2VyczwveG1wRE06dHJhY2tOYW1lPgogICAgICAgICAgICAgICAgICA8eG1wRE06dHJhY2tUeXBlPkluT3V0PC94bXBETTp0cmFja1R5cGU+CiAgICAgICAgICAgICAgICAgIDx4bXBETTpmcmFtZVJhdGU+ZjQ0MTAwPC94bXBETTpmcmFtZVJhdGU+CiAgICAgICAgICAgICAgIDwvcmRmOmxpPgogICAgICAgICAgICA8L3JkZjpCYWc+CiAgICAgICAgIDwveG1wRE06VHJhY2tzPgogICAgICAgICA8eG1wOk1ldGFkYXRhRGF0ZT4yMDE3LTA0LTE0VDE0OjQxOjM5KzAyOjAwPC94bXA6TWV0YWRhdGFEYXRlPgogICAgICAgICA8eG1wOk1vZGlmeURhdGU+MjAxNy0wNC0xNFQxNDo0MTozOSswMjowMDwveG1wOk1vZGlmeURhdGU+CiAgICAgICAgIDx4bXBNTTpJbnN0YW5jZUlEPnhtcC5paWQ6MzJkNTc5ZjAtMjIyZi00YjIyLThmZTUtNmNlZWY2YjJhYzMwPC94bXBNTTpJbnN0YW5jZUlEPgogICAgICAgICA8eG1wTU06RG9jdW1lbnRJRD54bXAuZGlkOjYzOGI4M2Y5LTA5ZWItNDk5Mi1hZDdjLWRkN2UwOWEwMzgyZDwveG1wTU06RG9jdW1lbnRJRD4KICAgICAgICAgPHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD54bXAuZGlkOjYzOGI4M2Y5LTA5ZWItNDk5Mi1hZDdjLWRkN2UwOWEwMzgyZDwveG1wTU06T3JpZ2luYWxEb2N1bWVudElEPgogICAgICAgICA8eG1wTU06SGlzdG9yeT4KICAgICAgICAgICAgPHJkZjpTZXE+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6YWN0aW9uPnNhdmVkPC9zdEV2dDphY3Rpb24+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDppbnN0YW5jZUlEPnhtcC5paWQ6NjM4YjgzZjktMDllYi00OTkyLWFkN2MtZGQ3ZTA5YTAzODJkPC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDE3LTA0LTE0VDE0OjQxOjM5KzAyOjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBBdWRpdGlvbiBDQyAyMDE3LjAgKE1hY2ludG9zaCk8L3N0RXZ0OnNvZnR3YXJlQWdlbnQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpjaGFuZ2VkPi9tZXRhZGF0YTwvc3RFdnQ6Y2hhbmdlZD4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6YWN0aW9uPnNhdmVkPC9zdEV2dDphY3Rpb24+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDppbnN0YW5jZUlEPnhtcC5paWQ6MzJkNTc5ZjAtMjIyZi00YjIyLThmZTUtNmNlZWY2YjJhYzMwPC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDE3LTA0LTE0VDE0OjQxOjM5KzAyOjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBBdWRpdGlvbiBDQyAyMDE3LjAgKE1hY2ludG9zaCk8L3N0RXZ0OnNvZnR3YXJlQWdlbnQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpjaGFuZ2VkPi88L3N0RXZ0OmNoYW5nZWQ+CiAgICAgICAgICAgICAgIDwvcmRmOmxpPgogICAgICAgICAgICA8L3JkZjpTZXE+CiAgICAgICAgIDwveG1wTU06SGlzdG9yeT4KICAgICAgICAgPGRjOmZvcm1hdD5hdWRpby94LXdhdjwvZGM6Zm9ybWF0PgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIAo8P3hwYWNrZXQgZW5kPSJ3Ij8+"></audio>
-</body>
-</html>

local-cli/server/util/external/xsel

Binary file local-cli/server/util/external/xsel has changed

local-cli/server/util/jsPackagerClient.js

@@ -1,122 +0,0 @@
-/**
- * Copyright (c) 2013-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const WebSocket = require('ws');
-
-const parseMessage = require('./messageSocket').parseMessage;
-
-const PROTOCOL_VERSION = 2;
-const TARGET_SERVER = 'server';
-
-function getMessageId() {
- return `${Date.now()}:${Math.random()}`;
-}
-
-class JsPackagerClient {
- constructor(url) {
- this.ws = new WebSocket(url);
- this.msgCallbacks = new Map();
-
- this.openPromise = new Promise((resolve, reject) => {
- this.ws.on('error', error => reject(error));
- this.ws.on('open', resolve);
- });
-
- this.ws.on('message', (data, flags) => {
- const message = parseMessage(data, flags.binary);
- const msgCallback = this.msgCallbacks.get(message.id);
- if (message === undefined || message.id === undefined) {
- // gracefully ignore wrong messages or broadcasts
- } else if (msgCallback === undefined) {
- console.warn(`Response with non-existing message id: '${message.id}'`);
- } else {
- if (message.error === undefined) {
- msgCallback.resolve(message.result);
- } else {
- msgCallback.reject(message.error);
- }
- }
- });
- }
-
- sendRequest(method, target, params) {
- return this.openPromise.then(
- () =>
- new Promise((resolve, reject) => {
- const messageId = getMessageId();
- this.msgCallbacks.set(messageId, {resolve: resolve, reject: reject});
- this.ws.send(
- JSON.stringify({
- version: PROTOCOL_VERSION,
- target: target,
- method: method,
- id: messageId,
- params: params,
- }),
- error => {
- if (error !== undefined) {
- this.msgCallbacks.delete(messageId);
- reject(error);
- }
- },
- );
- }),
- );
- }
-
- sendNotification(method, target, params) {
- return this.openPromise.then(
- () =>
- new Promise((resolve, reject) => {
- this.ws.send(
- JSON.stringify({
- version: PROTOCOL_VERSION,
- target: target,
- method: method,
- params: params,
- }),
- error => {
- if (error !== undefined) {
- reject(error);
- } else {
- resolve();
- }
- },
- );
- }),
- );
- }
-
- sendBroadcast(method, params) {
- return this.sendNotification(method, undefined, params);
- }
-
- getPeers() {
- return new Promise((resolve, reject) => {
- this.sendRequest('getpeers', TARGET_SERVER, undefined).then(response => {
- if (!response instanceof Map) {
- reject(
- 'Results received from server are of wrong format:\n' +
- JSON.stringify(response),
- );
- } else {
- resolve(response);
- }
- }, reject);
- });
- }
-
- getId() {
- return this.sendRequest('getid', TARGET_SERVER, undefined);
- }
-}
-
-module.exports = JsPackagerClient;

local-cli/server/util/launchChrome.js

@@ -1,62 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow
- */
-
-'use strict';
-
-/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
- * found when Flow v0.54 was deployed. To see the error delete this comment and
- * run Flow. */
-const opn = require('opn');
-const execSync = require('child_process').execSync;
-
-function commandExistsUnixSync(commandName, callback) {
- try {
- var stdout = execSync(
- 'command -v ' +
- commandName +
- ' 2>/dev/null' +
- " && { echo >&1 '" +
- commandName +
- " found'; exit 0; }",
- );
- return !!stdout;
- } catch (error) {
- return false;
- }
-}
-
-function getChromeAppName(): string {
- switch (process.platform) {
- case 'darwin':
- return 'google chrome';
- case 'win32':
- return 'chrome';
- case 'linux':
- if (commandExistsUnixSync('google-chrome')) {
- return 'google-chrome';
- } else if (commandExistsUnixSync('chromium-browser')) {
- return 'chromium-browser';
- } else {
- return 'chromium';
- }
- default:
- return 'google-chrome';
- }
-}
-
-function launchChrome(url: string) {
- opn(url, {app: [getChromeAppName()]}, function(err) {
- if (err) {
- console.error('Google Chrome exited with error:', err);
- }
- });
-}
-
-module.exports = launchChrome;

local-cli/server/util/launchEditor.js

@@ -1,216 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-var chalk = require('chalk');
-var fs = require('fs');
-var path = require('path');
-var child_process = require('child_process');
-const isAbsolutePath = require('absolute-path');
-const shellQuote = require('shell-quote');
-
-function isTerminalEditor(editor) {
- switch (editor) {
- case 'vim':
- case 'emacs':
- case 'nano':
- return true;
- }
- return false;
-}
-
-// Map from full process name to binary that starts the process
-// We can't just re-use full process name, because it will spawn a new instance
-// of the app every time
-var COMMON_EDITORS = {
- '/Applications/Atom.app/Contents/MacOS/Atom': 'atom',
- '/Applications/Atom Beta.app/Contents/MacOS/Atom Beta':
- '/Applications/Atom Beta.app/Contents/MacOS/Atom Beta',
- '/Applications/IntelliJ IDEA.app/Contents/MacOS/idea': 'idea',
- '/Applications/Sublime Text.app/Contents/MacOS/Sublime Text':
- '/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl',
- '/Applications/Sublime Text 2.app/Contents/MacOS/Sublime Text 2':
- '/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl',
- '/Applications/Visual Studio Code.app/Contents/MacOS/Electron': 'code',
- '/Applications/WebStorm.app/Contents/MacOS/webstorm': 'webstorm',
-};
-
-function addWorkspaceToArgumentsIfExists(args, workspace) {
- if (workspace) {
- args.unshift(workspace);
- }
- return args;
-}
-
-function getArgumentsForLineNumber(editor, fileName, lineNumber, workspace) {
- switch (path.basename(editor)) {
- case 'vim':
- case 'mvim':
- return [fileName, '+' + lineNumber];
- case 'atom':
- case 'Atom':
- case 'Atom Beta':
- case 'subl':
- case 'sublime':
- case 'webstorm':
- case 'wstorm':
- case 'appcode':
- case 'charm':
- case 'idea':
- return [fileName + ':' + lineNumber];
- case 'joe':
- case 'emacs':
- case 'emacsclient':
- return ['+' + lineNumber, fileName];
- case 'rmate':
- case 'mate':
- case 'mine':
- return ['--line', lineNumber, fileName];
- case 'code':
- return addWorkspaceToArgumentsIfExists(
- ['-g', fileName + ':' + lineNumber],
- workspace,
- );
- }
-
- // For all others, drop the lineNumber until we have
- // a mapping above, since providing the lineNumber incorrectly
- // can result in errors or confusing behavior.
- return [fileName];
-}
-
-function guessEditor() {
- // Explicit config always wins
- if (process.env.REACT_EDITOR) {
- return shellQuote.parse(process.env.REACT_EDITOR);
- }
-
- // Using `ps x` on OSX we can find out which editor is currently running.
- // Potentially we could use similar technique for Windows and Linux
- if (process.platform === 'darwin') {
- try {
- var output = child_process.execSync('ps x').toString();
- var processNames = Object.keys(COMMON_EDITORS);
- for (var i = 0; i < processNames.length; i++) {
- var processName = processNames[i];
- if (output.indexOf(processName) !== -1) {
- return [COMMON_EDITORS[processName]];
- }
- }
- } catch (error) {
- // Ignore...
- }
- }
-
- // Last resort, use old skool env vars
- if (process.env.VISUAL) {
- return [process.env.VISUAL];
- } else if (process.env.EDITOR) {
- return [process.env.EDITOR];
- }
-
- return [null];
-}
-
-function printInstructions(title) {
- console.log(
- [
- '',
- chalk.bgBlue.white.bold(' ' + title + ' '),
- ' When you see Red Box with stack trace, you can click any ',
- ' stack frame to jump to the source file. The packager will launch your ',
- ' editor of choice. It will first look at REACT_EDITOR environment ',
- ' variable, then at EDITOR. To set it up, you can add something like ',
- ' export REACT_EDITOR=atom to your ~/.bashrc or ~/.zshrc depending on ',
- ' which shell you use.',
- '',
- ].join('\n'),
- );
-}
-
-function transformToAbsolutePathIfNeeded(pathName) {
- if (!isAbsolutePath(pathName)) {
- pathName = path.resolve(process.cwd(), pathName);
- }
- return pathName;
-}
-
-function findRootForFile(projectRoots, fileName) {
- fileName = transformToAbsolutePathIfNeeded(fileName);
- return projectRoots.find(root => {
- root = transformToAbsolutePathIfNeeded(root);
- return fileName.startsWith(root + path.sep);
- });
-}
-
-var _childProcess = null;
-function launchEditor(fileName, lineNumber, projectRoots) {
- if (!fs.existsSync(fileName)) {
- return;
- }
-
- // Sanitize lineNumber to prevent malicious use on win32
- // via: https://github.com/nodejs/node/blob/c3bb4b1aa5e907d489619fb43d233c3336bfc03d/lib/child_process.js#L333
- if (lineNumber && isNaN(lineNumber)) {
- return;
- }
-
- let [editor, ...args] = guessEditor();
- if (!editor) {
- printInstructions('PRO TIP');
- return;
- }
-
- var workspace = findRootForFile(projectRoots, fileName);
- if (lineNumber) {
- args = args.concat(
- getArgumentsForLineNumber(editor, fileName, lineNumber, workspace),
- );
- } else {
- args.push(fileName);
- }
- console.log(
- 'Opening ' + chalk.underline(fileName) + ' with ' + chalk.bold(editor),
- );
-
- if (_childProcess && isTerminalEditor(editor)) {
- // There's an existing editor process already and it's attached
- // to the terminal, so go kill it. Otherwise two separate editor
- // instances attach to the stdin/stdout which gets confusing.
- _childProcess.kill('SIGKILL');
- }
-
- if (process.platform === 'win32') {
- // On Windows, launch the editor in a shell because spawn can only
- // launch .exe files.
- _childProcess = child_process.spawn(
- 'cmd.exe',
- ['/C', editor].concat(args),
- {stdio: 'inherit'},
- );
- } else {
- _childProcess = child_process.spawn(editor, args, {stdio: 'inherit'});
- }
- _childProcess.on('exit', function(errorCode) {
- _childProcess = null;
-
- if (errorCode) {
- console.log(chalk.red('Your editor exited with an error!'));
- printInstructions('Keep these instructions in mind:');
- }
- });
-
- _childProcess.on('error', function(error) {
- console.log(chalk.red(error.message));
- printInstructions('How to fix:');
- });
-}
-
-module.exports = launchEditor;

local-cli/server/util/messageSocket.js

@@ -1,235 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const url = require('url');
-const WebSocketServer = require('ws').Server;
-const PROTOCOL_VERSION = 2;
-const notifier = require('node-notifier');
-
-function parseMessage(data, binary) {
- if (binary) {
- console.error('Expected text message, got binary!');
- return undefined;
- }
- try {
- const message = JSON.parse(data);
- if (message.version === PROTOCOL_VERSION) {
- return message;
- }
- console.error(
- 'Received message had wrong protocol version: ' + message.version,
- );
- } catch (e) {
- console.error('Failed to parse the message as JSON:\n' + data);
- }
- return undefined;
-}
-
-function isBroadcast(message) {
- return (
- typeof message.method === 'string' &&
- message.id === undefined &&
- message.target === undefined
- );
-}
-
-function isRequest(message) {
- return (
- typeof message.method === 'string' && typeof message.target === 'string'
- );
-}
-
-function isResponse(message) {
- return (
- typeof message.id === 'object' &&
- typeof message.id.requestId !== undefined &&
- typeof message.id.clientId === 'string' &&
- (message.result !== undefined || message.error !== undefined)
- );
-}
-
-function attachToServer(server, path) {
- const wss = new WebSocketServer({
- server: server,
- path: path,
- });
- const clients = new Map();
- let nextClientId = 0;
-
- function getClientWs(clientId) {
- const clientWs = clients.get(clientId);
- if (clientWs === undefined) {
- throw `could not find id "${clientId}" while forwarding request`;
- }
- return clientWs;
- }
-
- function handleSendBroadcast(broadcasterId, message) {
- const forwarded = {
- version: PROTOCOL_VERSION,
- method: message.method,
- params: message.params,
- };
- if (clients.size === 0) {
- notifier.notify({
- title: 'React Native: No apps connected',
- message:
- `Sending '${message.method}' to all React Native apps ` +
- 'failed. Make sure your app is running in the simulator ' +
- 'or on a phone connected via USB.',
- });
- }
- for (const [otherId, otherWs] of clients) {
- if (otherId !== broadcasterId) {
- try {
- otherWs.send(JSON.stringify(forwarded));
- } catch (e) {
- console.error(
- `Failed to send broadcast to client: '${otherId}' ` +
- `due to:\n ${e.toString()}`,
- );
- }
- }
- }
- }
-
- wss.on('connection', function(clientWs) {
- const clientId = `client#${nextClientId++}`;
-
- function handleCaughtError(message, error) {
- const errorMessage = {
- id: message.id,
- method: message.method,
- target: message.target,
- error: message.error === undefined ? 'undefined' : 'defined',
- params: message.params === undefined ? 'undefined' : 'defined',
- result: message.result === undefined ? 'undefined' : 'defined',
- };
-
- if (message.id === undefined) {
- console.error(
- `Handling message from ${clientId} failed with:\n${error}\n` +
- `message:\n${JSON.stringify(errorMessage)}`,
- );
- } else {
- try {
- clientWs.send(
- JSON.stringify({
- version: PROTOCOL_VERSION,
- error: error,
- id: message.id,
- }),
- );
- } catch (e) {
- console.error(
- `Failed to reply to ${clientId} with error:\n${error}` +
- `\nmessage:\n${JSON.stringify(errorMessage)}` +
- `\ndue to error: ${e.toString()}`,
- );
- }
- }
- }
-
- function handleServerRequest(message) {
- let result = null;
- switch (message.method) {
- case 'getid':
- result = clientId;
- break;
- case 'getpeers':
- result = {};
- clients.forEach((otherWs, otherId) => {
- if (clientId !== otherId) {
- result[otherId] = url.parse(otherWs.upgradeReq.url, true).query;
- }
- });
- break;
- default:
- throw `unknown method: ${message.method}`;
- }
-
- clientWs.send(
- JSON.stringify({
- version: PROTOCOL_VERSION,
- result: result,
- id: message.id,
- }),
- );
- }
-
- function forwardRequest(message) {
- getClientWs(message.target).send(
- JSON.stringify({
- version: PROTOCOL_VERSION,
- method: message.method,
- params: message.params,
- id:
- message.id === undefined
- ? undefined
- : {requestId: message.id, clientId: clientId},
- }),
- );
- }
-
- function forwardResponse(message) {
- getClientWs(message.id.clientId).send(
- JSON.stringify({
- version: PROTOCOL_VERSION,
- result: message.result,
- error: message.error,
- id: message.id.requestId,
- }),
- );
- }
-
- clients.set(clientId, clientWs);
- clientWs.onclose = clientWs.onerror = () => {
- clientWs.onmessage = null;
- clients.delete(clientId);
- };
- clientWs.onmessage = event => {
- const message = parseMessage(event.data, event.binary);
- if (message === undefined) {
- console.error('Received message not matching protocol');
- return;
- }
-
- try {
- if (isBroadcast(message)) {
- handleSendBroadcast(clientId, message);
- } else if (isRequest(message)) {
- if (message.target === 'server') {
- handleServerRequest(message);
- } else {
- forwardRequest(message);
- }
- } else if (isResponse(message)) {
- forwardResponse(message);
- } else {
- throw 'Invalid message, did not match the protocol';
- }
- } catch (e) {
- handleCaughtError(message, e.toString());
- }
- };
- });
-
- return {
- broadcast: (method, params) => {
- handleSendBroadcast(null, {method: method, params: params});
- },
- };
-}
-
-module.exports = {
- attachToServer: attachToServer,
- parseMessage: parseMessage,
-};

local-cli/server/util/webSocketProxy.js

@@ -1,75 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-function attachToServer(server, path) {
- var WebSocketServer = require('ws').Server;
- var wss = new WebSocketServer({
- server: server,
- path: path,
- });
- var debuggerSocket, clientSocket;
-
- function send(dest, message) {
- if (!dest) {
- return;
- }
-
- try {
- dest.send(message);
- } catch (e) {
- console.warn(e);
- // Sometimes this call throws 'not opened'
- }
- }
-
- wss.on('connection', function(ws) {
- const {url} = ws.upgradeReq;
-
- if (url.indexOf('role=debugger') > -1) {
- if (debuggerSocket) {
- ws.close(1011, 'Another debugger is already connected');
- return;
- }
- debuggerSocket = ws;
- debuggerSocket.onerror = debuggerSocket.onclose = () => {
- debuggerSocket = null;
- if (clientSocket) {
- clientSocket.close(1011, 'Debugger was disconnected');
- }
- };
- debuggerSocket.onmessage = ({data}) => send(clientSocket, data);
- } else if (url.indexOf('role=client') > -1) {
- if (clientSocket) {
- clientSocket.onerror = clientSocket.onclose = clientSocket.onmessage = null;
- clientSocket.close(1011, 'Another client connected');
- }
- clientSocket = ws;
- clientSocket.onerror = clientSocket.onclose = () => {
- clientSocket = null;
- send(debuggerSocket, JSON.stringify({method: '$disconnected'}));
- };
- clientSocket.onmessage = ({data}) => send(debuggerSocket, data);
- } else {
- ws.close(1011, 'Missing role param');
- }
- });
-
- return {
- server: wss,
- isChromeConnected: function() {
- return !!debuggerSocket;
- },
- };
-}
-
-module.exports = {
- attachToServer: attachToServer,
-};

local-cli/setup_env.bat

@@ -1,4 +0,0 @@
-:: Copyright (c) 2015-present, Facebook, Inc.
-::
-:: This source code is licensed under the MIT license found in the
-:: LICENSE file in the root directory of this source tree.

local-cli/setup_env.sh

@@ -1,8 +0,0 @@
-#!/usr/bin/env bash
-# Copyright (c) 2015-present, Facebook, Inc.
-#
-# This source code is licensed under the MIT license found in the
-# LICENSE file in the root directory of this source tree.
-
-# 2048 is the max for non root users on Mac
-ulimit -n 2048

local-cli/templates/HelloNavigation/App.js

@@ -1,27 +0,0 @@
-/**
- * This is an example React Native app demonstrates ListViews, text input and
- * navigation between a few screens.
- * https://github.com/facebook/react-native
- *
- * @format
- */
-
-import React, {Component} from 'react';
-import {StackNavigator} from 'react-navigation';
-
-import HomeScreenTabNavigator from './views/HomeScreenTabNavigator';
-import ChatScreen from './views/chat/ChatScreen';
-
-/**
- * Top-level navigator. Renders the application UI.
- */
-const App = StackNavigator({
- Home: {
- screen: HomeScreenTabNavigator,
- },
- Chat: {
- screen: ChatScreen,
- },
-});
-
-export default App;

local-cli/templates/HelloNavigation/components/KeyboardSpacer.js

@@ -1,120 +0,0 @@
-/**
- * Copyright (c) 2013-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-/* @flow */
-
-import React, {Component} from 'react';
-import PropTypes from 'prop-types';
-import {Platform, View, Keyboard, LayoutAnimation} from 'react-native';
-
-type Props = {
- offset?: number,
-};
-
-type State = {
- keyboardHeight: number,
-};
-
-// Consider contributing this to the popular library:
-// https://github.com/Andr3wHur5t/react-native-keyboard-spacer
-
-/**
- * On iOS, the software keyboard covers the screen by default.
- * This is not desirable if there are TextInputs near the bottom of the screen -
- * they would be covered by the keyboard and the user cannot see what they
- * are typing.
- * To get around this problem, place a `<KeyboardSpacer />` at the bottom
- * of the screen, after your TextInputs. The keyboard spacer has size 0 and
- * when the keyboard is shown it will grow to the same size as the keyboard,
- * shifting all views above it and therefore making them visible.
- *
- * On Android, this component is not needed because resizing the UI when
- * the keyboard is shown is supported by the OS.
- * Simply set the `android:windowSoftInputMode="adjustResize"` attribute
- * on the <activity> element in your AndroidManifest.xml.
- *
- * How is this different from KeyboardAvoidingView?
- * The KeyboardAvoidingView doesn't work when used together with
- * a ScrollView/ListView.
- */
-const KeyboardSpacer = () =>
- Platform.OS === 'ios' ? <KeyboardSpacerIOS /> : null;
-
-class KeyboardSpacerIOS extends Component<Props, State> {
- static propTypes = {
- offset: PropTypes.number,
- };
-
- static defaultProps = {
- offset: 0,
- };
-
- state: State = {
- keyboardHeight: 0,
- };
-
- UNSAFE_componentWillMount() {
- this._registerEvents();
- }
-
- componentWillUnmount() {
- this._unRegisterEvents();
- }
-
- _keyboardWillShowSubscription: {+remove: Function};
- _keyboardWillHideSubscription: {+remove: Function};
-
- _registerEvents = () => {
- this._keyboardWillShowSubscription = Keyboard.addListener(
- 'keyboardWillShow',
- this._keyboardWillShow,
- );
- this._keyboardWillHideSubscription = Keyboard.addListener(
- 'keyboardWillHide',
- this._keyboardWillHide,
- );
- };
-
- _unRegisterEvents = () => {
- this._keyboardWillShowSubscription.remove();
- this._keyboardWillHideSubscription.remove();
- };
-
- _configureLayoutAnimation = () => {
- // Any duration is OK here. The `type: 'keyboard defines the animation.
- LayoutAnimation.configureNext({
- duration: 100,
- update: {
- type: 'keyboard',
- },
- });
- };
-
- _keyboardWillShow = (e: any) => {
- this._configureLayoutAnimation();
- this.setState({
- keyboardHeight: e.endCoordinates.height - (this.props.offset || 0),
- });
- };
-
- _keyboardWillHide = () => {
- this._configureLayoutAnimation();
- this.setState({
- keyboardHeight: 0,
- });
- };
-
- render() {
- return <View style={{height: this.state.keyboardHeight}} />;
- }
-}
-
-export default KeyboardSpacer;

local-cli/templates/HelloNavigation/components/ListItem.js

@@ -1,56 +0,0 @@
-/** @format */
-
-'use strict';
-
-import React, {Component} from 'react';
-import {
- Platform,
- StyleSheet,
- Text,
- TouchableHighlight,
- TouchableNativeFeedback,
- View,
-} from 'react-native';
-
-/**
- * Renders the right type of Touchable for the list item, based on platform.
- */
-const Touchable = ({onPress, children}) => {
- const child = React.Children.only(children);
- if (Platform.OS === 'android') {
- return (
- <TouchableNativeFeedback onPress={onPress}>
- {child}
- </TouchableNativeFeedback>
- );
- } else {
- return (
- <TouchableHighlight onPress={onPress} underlayColor="#ddd">
- {child}
- </TouchableHighlight>
- );
- }
-};
-
-const ListItem = ({label, onPress}) => (
- <Touchable onPress={onPress}>
- <View style={styles.item}>
- <Text style={styles.label}>{label}</Text>
- </View>
- </Touchable>
-);
-
-const styles = StyleSheet.create({
- item: {
- height: 48,
- justifyContent: 'center',
- paddingLeft: 12,
- borderBottomWidth: StyleSheet.hairlineWidth,
- borderBottomColor: '#ddd',
- },
- label: {
- fontSize: 16,
- },
-});
-
-export default ListItem;

local-cli/templates/HelloNavigation/dependencies.json

@@ -1,3 +0,0 @@
-{
- "react-navigation": "1.0.0-beta.11"
-}

local-cli/templates/HelloNavigation/lib/Backend.js

@@ -1,117 +0,0 @@
-/** @format */
-
-'use strict';
-
-// This file just a dummy example of a HTTP API to talk to the backend.
-// The state of the "database" that would normally live on the server
-// is simply held here in memory.
-
-const backendStateForLoggedInPerson = {
- chats: [
- {
- name: 'Claire',
- messages: [
- {
- name: 'Claire',
- text: 'I ❤️ React Native!',
- },
- ],
- },
- {
- name: 'John',
- messages: [
- {
- name: 'John',
- text: 'I ❤️ React Native!',
- },
- ],
- },
- ],
-};
-
-/**
- * Randomly simulate network failures.
- * It is useful to enable this during development to make sure our app works
- * in real-world conditions.
- */
-function isNetworkFailure() {
- const chanceOfFailure = 0; // 0..1
- return Math.random() < chanceOfFailure;
-}
-
-/**
- * Helper for the other functions in this file.
- * Simulates a short delay and then returns a provided value or failure.
- * This is just a dummy example. Normally we'd make a HTTP request,
- * see http://facebook.github.io/react-native/docs/network.html
- */
-function _makeSimulatedNetworkRequest(getValue) {
- const durationMs = 400;
- return new Promise(function(resolve, reject) {
- setTimeout(function() {
- if (isNetworkFailure()) {
- reject(new Error('Network failure'));
- } else {
- getValue(resolve, reject);
- }
- }, durationMs);
- });
-}
-
-/**
- * Fetch a list of all chats for the logged in person.
- */
-async function fetchChatList() {
- return _makeSimulatedNetworkRequest((resolve, reject) => {
- resolve(backendStateForLoggedInPerson.chats.map(chat => chat.name));
- });
-}
-
-/**
- * Fetch a single chat.
- */
-async function fetchChat(name) {
- return _makeSimulatedNetworkRequest((resolve, reject) => {
- resolve(
- backendStateForLoggedInPerson.chats.find(chat => chat.name === name),
- );
- });
-}
-
-/**
- * Send given message to given person.
- */
-async function sendMessage({name, message}) {
- return _makeSimulatedNetworkRequest((resolve, reject) => {
- const chatForName = backendStateForLoggedInPerson.chats.find(
- chat => chat.name === name,
- );
- if (chatForName) {
- chatForName.messages.push({
- name: 'Me',
- text: message,
- });
- resolve();
- } else {
- reject(new Error('Uknown person: ' + name));
- }
- });
-}
-
-const Backend = {
- fetchChatList,
- fetchChat,
- sendMessage,
-};
-
-export default Backend;
-
-// In case you are looking into using Redux for state management,
-// this is how network requests are done in the f8 app which uses Redux:
-// - To load some data, a Component fires a Redux action, such as loadSession()
-// - That action makes the HTTP requests and then dispatches a redux action
-// {type: 'LOADED_SESSIONS', results}
-// - Then all reducers get called and one of them updates a part of the application
-// state by storing the results
-// - Redux re-renders the connected Components
-// See https://github.com/fbsamples/f8app/search?utf8=%E2%9C%93&q=loaded_sessions

local-cli/templates/HelloNavigation/README.md

@@ -1,41 +0,0 @@
-# App template for new React Native apps
-
-This is a simple React Native app template which demonstrates a few basics concepts such as navigation between a few screens, FlatLists, and handling text input.
-
-<img src="https://cloud.githubusercontent.com/assets/346214/22697898/ced66f52-ed4a-11e6-9b90-df6daef43199.gif" alt="Android Example" height="800" style="float: left"/>
-
-<img src="https://cloud.githubusercontent.com/assets/346214/22697901/cfeab3e4-ed4a-11e6-8552-d76585317ac2.gif" alt="iOS Example" height="800"/>
-
-## Purpose
-
-The idea is to make it easier for people to get started with React Native. Currently `react-native init` creates a very simple app that contains one screen with static text. Everyone new to React Native then needs to figure out how to do very basic things such as:
-- Rendering a list of items fetched from a server
-- Navigating between screens
-- Handling text input and the software keyboard
-
-This app serves as a template used by `react-native init` so it is easier for anyone to get up and running quickly by having an app with a few screens and a FlatList ready to go.
-
-### Best practices
-
-Another purpose of this app is to define best practices such as the folder structure of a standalone React Native app and naming conventions.
-
-## Not using Redux
-
-This template intentionally doesn't use Redux. After discussing with a few people who have experience using Redux we concluded that adding Redux to this app targeted at beginners would make the code more confusing, and wouldn't clearly show the benefits of Redux (because the app is too small). There are already a few concepts to grasp - the React component lifecycle, rendering lists, using async / await, handling the software keyboard. We thought that's the maximum amount of things to learn at once. It's better for everyone to see patterns in their codebase as the app grows and decide for themselves whether and when they need Redux. See also the post [You Might Not Need Redux](https://medium.com/@dan_abramov/you-might-not-need-redux-be46360cf367#.f3q7kq4b3) by [Dan Abramov](https://twitter.com/dan_abramov).
-
-## Not using Flow (for now)
-
-Many people are new to React Native, some are new to ES6 and most people will be new to Flow. Therefore we didn't want to introduce all these concepts all at once in a single codebase. However, it might make sense to later introduce a separate version of this template that uses Flow annotations.
-
-## Provide feedback
-
-We need your feedback. Do you have a lot of experience building React Native apps? If so, please carefully read the code of the template and if you think something should be done differently, use issues in the repo [mkonicek/AppTemplateFeedback](https://github.com/mkonicek/AppTemplateFeedback) to discuss what should be done differently.
-
-## How to use the template
-
-```
-$ react-native init MyApp --template navigation
-$ cd MyApp
-$ react-native run-android
-$ react-native run-ios
-```

local-cli/templates/HelloNavigation/views/chat/chat-icon.png

Binary file local-cli/templates/HelloNavigation/views/chat/chat-icon.png has changed

local-cli/templates/HelloNavigation/views/chat/ChatListScreen.js

@@ -1,91 +0,0 @@
-/** @format */
-
-import React, {Component} from 'react';
-import {
- ActivityIndicator,
- Image,
- FlatList,
- Platform,
- StyleSheet,
- View,
-} from 'react-native';
-import ListItem from '../../components/ListItem';
-import Backend from '../../lib/Backend';
-
-export default class ChatListScreen extends Component {
- static navigationOptions = {
- title: 'Chats',
- header: Platform.OS === 'ios' ? undefined : null,
- tabBarIcon: ({tintColor}) => (
- <Image
- // Using react-native-vector-icons works here too
- source={require('./chat-icon.png')}
- style={[styles.icon, {tintColor: tintColor}]}
- />
- ),
- };
-
- constructor(props) {
- super(props);
- this.state = {
- isLoading: true,
- };
- }
-
- async componentDidMount() {
- const chatList = await Backend.fetchChatList();
- this.setState(prevState => ({
- chatList,
- isLoading: false,
- }));
- }
-
- // Binding the function so it can be passed to FlatList below
- // and 'this' works properly inside renderItem
- renderItem = ({item}) => {
- return (
- <ListItem
- label={item}
- onPress={() => {
- // Start fetching in parallel with animating
- this.props.navigation.navigate('Chat', {
- name: item,
- });
- }}
- />
- );
- };
-
- render() {
- if (this.state.isLoading) {
- return (
- <View style={styles.loadingScreen}>
- <ActivityIndicator />
- </View>
- );
- }
- return (
- <FlatList
- data={this.state.chatList}
- renderItem={this.renderItem}
- keyExtractor={(item, index) => index}
- style={styles.listView}
- />
- );
- }
-}
-
-const styles = StyleSheet.create({
- loadingScreen: {
- backgroundColor: 'white',
- paddingTop: 8,
- flex: 1,
- },
- listView: {
- backgroundColor: 'white',
- },
- icon: {
- width: 30,
- height: 26,
- },
-});

local-cli/templates/HelloNavigation/views/chat/ChatScreen.js

@@ -1,170 +0,0 @@
-/** @format */
-
-import React, {Component} from 'react';
-import {
- ActivityIndicator,
- Button,
- FlatList,
- StyleSheet,
- Text,
- TextInput,
- View,
-} from 'react-native';
-import KeyboardSpacer from '../../components/KeyboardSpacer';
-import Backend from '../../lib/Backend';
-
-export default class ChatScreen extends Component {
- static navigationOptions = ({navigation}) => ({
- title: `Chat with ${navigation.state.params.name}`,
- });
- constructor(props) {
- super(props);
- this.state = {
- messages: [],
- myMessage: '',
- isLoading: true,
- };
- }
-
- async componentDidMount() {
- let chat;
- try {
- chat = await Backend.fetchChat(this.props.navigation.state.params.name);
- } catch (err) {
- // Here we would handle the fact the request failed, e.g.
- // set state to display "Messages could not be loaded".
- // We should also check network connection first before making any
- // network requests - maybe we're offline? See React Native's NetInfo
- // module.
- this.setState({
- isLoading: false,
- });
- return;
- }
- this.setState(prevState => ({
- messages: chat.messages,
- isLoading: false,
- }));
- }
-
- onAddMessage = async () => {
- // Optimistically update the UI
- this.addMessageLocal();
- // Send the request
- try {
- await Backend.sendMessage({
- name: this.props.navigation.state.params.name,
- // TODO Is reading state like this outside of setState OK?
- // Can it contain a stale value?
- message: this.state.myMessage,
- });
- } catch (err) {
- // Here we would handle the request failure, e.g. call setState
- // to display a visual hint showing the message could not be sent.
- }
- };
-
- addMessageLocal = () => {
- this.setState(prevState => {
- if (!prevState.myMessage) {
- return prevState;
- }
- const messages = [
- ...prevState.messages,
- {
- name: 'Me',
- text: prevState.myMessage,
- },
- ];
- return {
- messages: messages,
- myMessage: '',
- };
- });
- this.textInput.clear();
- };
-
- onMyMessageChange = event => {
- this.setState({myMessage: event.nativeEvent.text});
- };
-
- renderItem = ({item}) => (
- <View style={styles.bubble}>
- <Text style={styles.name}>{item.name}</Text>
- <Text>{item.text}</Text>
- </View>
- );
-
- render() {
- if (this.state.isLoading) {
- return (
- <View style={styles.container}>
- <ActivityIndicator />
- </View>
- );
- }
- return (
- <View style={styles.container}>
- <FlatList
- data={this.state.messages}
- renderItem={this.renderItem}
- keyExtractor={(item, index) => index}
- style={styles.listView}
- />
-
- <View style={styles.composer}>
- <TextInput
- ref={textInput => {
- this.textInput = textInput;
- }}
- style={styles.textInput}
- placeholder="Type a message..."
- text={this.state.myMessage}
- onSubmitEditing={this.onAddMessage}
- onChange={this.onMyMessageChange}
- />
- {this.state.myMessage !== '' && (
- <Button title="Send" onPress={this.onAddMessage} />
- )}
- </View>
- <KeyboardSpacer />
- </View>
- );
- }
-}
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- padding: 8,
- backgroundColor: 'white',
- },
- listView: {
- flex: 1,
- alignSelf: 'stretch',
- },
- bubble: {
- alignSelf: 'flex-end',
- backgroundColor: '#d6f3fc',
- padding: 12,
- borderRadius: 4,
- marginBottom: 4,
- },
- name: {
- fontWeight: 'bold',
- },
- composer: {
- flexDirection: 'row',
- alignItems: 'center',
- height: 36,
- },
- textInput: {
- flex: 1,
- borderColor: '#ddd',
- borderWidth: 1,
- padding: 4,
- height: 30,
- fontSize: 13,
- marginRight: 8,
- },
-});

local-cli/templates/HelloNavigation/views/HomeScreenTabNavigator.js

@@ -1,20 +0,0 @@
-/** @format */
-
-import {TabNavigator} from 'react-navigation';
-
-import ChatListScreen from './chat/ChatListScreen';
-import WelcomeScreen from './welcome/WelcomeScreen';
-
-/**
- * Screen with tabs shown on app startup.
- */
-const HomeScreenTabNavigator = TabNavigator({
- Welcome: {
- screen: WelcomeScreen,
- },
- Chats: {
- screen: ChatListScreen,
- },
-});
-
-export default HomeScreenTabNavigator;

local-cli/templates/HelloNavigation/views/welcome/welcome-icon.png

Binary file local-cli/templates/HelloNavigation/views/welcome/welcome-icon.png has changed

local-cli/templates/HelloNavigation/views/welcome/WelcomeScreen.js

@@ -1,33 +0,0 @@
-/** @format */
-
-import React, {Component} from 'react';
-import {Image, Platform, StyleSheet} from 'react-native';
-
-import ListItem from '../../components/ListItem';
-import WelcomeText from './WelcomeText';
-
-export default class WelcomeScreen extends Component {
- static navigationOptions = {
- title: 'Welcome',
- // You can now set header: null on any component to hide the header
- header: Platform.OS === 'ios' ? undefined : null,
- tabBarIcon: ({tintColor}) => (
- <Image
- // Using react-native-vector-icons works here too
- source={require('./welcome-icon.png')}
- style={[styles.icon, {tintColor: tintColor}]}
- />
- ),
- };
-
- render() {
- return <WelcomeText />;
- }
-}
-
-const styles = StyleSheet.create({
- icon: {
- width: 30,
- height: 26,
- },
-});

local-cli/templates/HelloNavigation/views/welcome/WelcomeText.android.js

@@ -1,46 +0,0 @@
-/** @format */
-
-import React, {Component} from 'react';
-import {StyleSheet, Text, View} from 'react-native';
-
-export default class WelcomeText extends Component {
- render() {
- return (
- <View style={styles.container}>
- <Text style={styles.welcome}>Welcome to React Native!</Text>
- <Text style={styles.instructions}>
- This app shows the basics of navigating between a few screens, working
- with ListView and handling text input.
- </Text>
- <Text style={styles.instructions}>
- Modify any files to get started. For example try changing the file
- views/welcome/WelcomeText.android.js.
- </Text>
- <Text style={styles.instructions}>
- Double tap R on your keyboard to reload,{'\n'}
- Shake or press menu button for dev menu.
- </Text>
- </View>
- );
- }
-}
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- justifyContent: 'center',
- alignItems: 'center',
- backgroundColor: 'white',
- padding: 20,
- },
- welcome: {
- fontSize: 20,
- textAlign: 'center',
- margin: 16,
- },
- instructions: {
- textAlign: 'center',
- color: '#333333',
- marginBottom: 12,
- },
-});

local-cli/templates/HelloNavigation/views/welcome/WelcomeText.ios.js

@@ -1,47 +0,0 @@
-/** @format */
-
-import React, {Component} from 'react';
-import {StyleSheet, Text, View} from 'react-native';
-
-export default class WelcomeText extends Component {
- render() {
- return (
- <View style={styles.container}>
- <Text style={styles.welcome}>Welcome to React Native!</Text>
- <Text style={styles.instructions}>
- This app shows the basics of navigating between a few screens, working
- with ListView and handling text input.
- </Text>
- <Text style={styles.instructions}>
- Modify any files to get started. For example try changing the file{
- '\n'
- }views/welcome/WelcomeText.ios.js.
- </Text>
- <Text style={styles.instructions}>
- Press Cmd+R to reload,{'\n'}
- Cmd+D or shake for dev menu.
- </Text>
- </View>
- );
- }
-}
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- justifyContent: 'center',
- alignItems: 'center',
- backgroundColor: 'white',
- padding: 20,
- },
- welcome: {
- fontSize: 20,
- textAlign: 'center',
- margin: 16,
- },
- instructions: {
- textAlign: 'center',
- color: '#333333',
- marginBottom: 12,
- },
-});

local-cli/templates/HelloWorld/android/app/BUCK

@@ -1,65 +0,0 @@
-# To learn about Buck see [Docs](https://buckbuild.com/).
-# To run your application with Buck:
-# - install Buck
-# - `npm start` - to start the packager
-# - `cd android`
-# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
-# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
-# - `buck install -r android/app` - compile, install and run application
-#
-
-lib_deps = []
-
-for jarfile in glob(['libs/*.jar']):
- name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')]
- lib_deps.append(':' + name)
- prebuilt_jar(
- name = name,
- binary_jar = jarfile,
- )
-
-for aarfile in glob(['libs/*.aar']):
- name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')]
- lib_deps.append(':' + name)
- android_prebuilt_aar(
- name = name,
- aar = aarfile,
- )
-
-android_library(
- name = "all-libs",
- exported_deps = lib_deps,
-)
-
-android_library(
- name = "app-code",
- srcs = glob([
- "src/main/java/**/*.java",
- ]),
- deps = [
- ":all-libs",
- ":build_config",
- ":res",
- ],
-)
-
-android_build_config(
- name = "build_config",
- package = "com.helloworld",
-)
-
-android_resource(
- name = "res",
- package = "com.helloworld",
- res = "src/main/res",
-)
-
-android_binary(
- name = "app",
- keystore = "//android/keystores:debug",
- manifest = "src/main/AndroidManifest.xml",
- package_type = "debug",
- deps = [
- ":app-code",
- ],
-)

local-cli/templates/HelloWorld/android/app/build.gradle

@@ -1,150 +0,0 @@
-apply plugin: "com.android.application"
-
-import com.android.build.OutputFile
-
-/**
- * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
- * and bundleReleaseJsAndAssets).
- * These basically call `react-native bundle` with the correct arguments during the Android build
- * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
- * bundle directly from the development server. Below you can see all the possible configurations
- * and their defaults. If you decide to add a configuration block, make sure to add it before the
- * `apply from: "../../node_modules/react-native/react.gradle"` line.
- *
- * project.ext.react = [
- * // the name of the generated asset file containing your JS bundle
- * bundleAssetName: "index.android.bundle",
- *
- * // the entry file for bundle generation
- * entryFile: "index.android.js",
- *
- * // whether to bundle JS and assets in debug mode
- * bundleInDebug: false,
- *
- * // whether to bundle JS and assets in release mode
- * bundleInRelease: true,
- *
- * // whether to bundle JS and assets in another build variant (if configured).
- * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
- * // The configuration property can be in the following formats
- * // 'bundleIn${productFlavor}${buildType}'
- * // 'bundleIn${buildType}'
- * // bundleInFreeDebug: true,
- * // bundleInPaidRelease: true,
- * // bundleInBeta: true,
- *
- * // whether to disable dev mode in custom build variants (by default only disabled in release)
- * // for example: to disable dev mode in the staging build type (if configured)
- * devDisabledInStaging: true,
- * // The configuration property can be in the following formats
- * // 'devDisabledIn${productFlavor}${buildType}'
- * // 'devDisabledIn${buildType}'
- *
- * // the root of your project, i.e. where "package.json" lives
- * root: "../../",
- *
- * // where to put the JS bundle asset in debug mode
- * jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
- *
- * // where to put the JS bundle asset in release mode
- * jsBundleDirRelease: "$buildDir/intermediates/assets/release",
- *
- * // where to put drawable resources / React Native assets, e.g. the ones you use via
- * // require('./image.png')), in debug mode
- * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
- *
- * // where to put drawable resources / React Native assets, e.g. the ones you use via
- * // require('./image.png')), in release mode
- * resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
- *
- * // by default the gradle tasks are skipped if none of the JS files or assets change; this means
- * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
- * // date; if you have any other folders that you want to ignore for performance reasons (gradle
- * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
- * // for example, you might want to remove it from here.
- * inputExcludes: ["android/**", "ios/**"],
- *
- * // override which node gets called and with what additional arguments
- * nodeExecutableAndArgs: ["node"],
- *
- * // supply additional arguments to the packager
- * extraPackagerArgs: []
- * ]
- */
-
-project.ext.react = [
- entryFile: "index.js"
-]
-
-apply from: "../../node_modules/react-native/react.gradle"
-
-/**
- * Set this to true to create two separate APKs instead of one:
- * - An APK that only works on ARM devices
- * - An APK that only works on x86 devices
- * The advantage is the size of the APK is reduced by about 4MB.
- * Upload all the APKs to the Play Store and people will download
- * the correct one based on the CPU architecture of their device.
- */
-def enableSeparateBuildPerCPUArchitecture = false
-
-/**
- * Run Proguard to shrink the Java bytecode in release builds.
- */
-def enableProguardInReleaseBuilds = false
-
-android {
- compileSdkVersion rootProject.ext.compileSdkVersion
- buildToolsVersion rootProject.ext.buildToolsVersion
-
- defaultConfig {
- applicationId "com.helloworld"
- minSdkVersion rootProject.ext.minSdkVersion
- targetSdkVersion rootProject.ext.targetSdkVersion
- versionCode 1
- versionName "1.0"
- ndk {
- abiFilters "armeabi-v7a", "x86"
- }
- }
- splits {
- abi {
- reset()
- enable enableSeparateBuildPerCPUArchitecture
- universalApk false // If true, also generate a universal APK
- include "armeabi-v7a", "x86"
- }
- }
- buildTypes {
- release {
- minifyEnabled enableProguardInReleaseBuilds
- proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
- }
- }
- // applicationVariants are e.g. debug, release
- applicationVariants.all { variant ->
- variant.outputs.each { output ->
- // For each separate APK per architecture, set a unique version code as described here:
- // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
- def versionCodes = ["armeabi-v7a":1, "x86":2]
- def abi = output.getFilter(OutputFile.ABI)
- if (abi != null) { // null for the universal-debug, universal-release variants
- output.versionCodeOverride =
- versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
- }
- }
- }
-}
-
-dependencies {
- implementation fileTree(dir: "libs", include: ["*.jar"])
- implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
- implementation "com.facebook.react:react-native:+" // From node_modules
-}
-
-// Run this once to be able to run the application with BUCK
-// puts all compile dependencies into folder libs for BUCK to use
-task copyDownloadableDepsToLibs(type: Copy) {
- from configurations.compile
- into 'libs'
-}

local-cli/templates/HelloWorld/android/app/proguard-rules.pro

@@ -1,17 +0,0 @@
-# Add project specific ProGuard rules here.
-# By default, the flags in this file are appended to flags specified
-# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
-# You can edit the include path and order by changing the proguardFiles
-# directive in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# Add any project specific keep options here:
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}

local-cli/templates/HelloWorld/android/app/src/main/AndroidManifest.xml

@@ -1,26 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.helloworld">
-
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
-
- <application
- android:name=".MainApplication"
- android:label="@string/app_name"
- android:icon="@mipmap/ic_launcher"
- android:allowBackup="false"
- android:theme="@style/AppTheme">
- <activity
- android:name=".MainActivity"
- android:label="@string/app_name"
- android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
- android:windowSoftInputMode="adjustResize">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
- </application>
-
-</manifest>

local-cli/templates/HelloWorld/android/app/src/main/java/com/helloworld/MainActivity.java

@@ -1,15 +0,0 @@
-package com.helloworld;
-
-import com.facebook.react.ReactActivity;
-
-public class MainActivity extends ReactActivity {
-
- /**
- * Returns the name of the main component registered from JavaScript.
- * This is used to schedule rendering of the component.
- */
- @Override
- protected String getMainComponentName() {
- return "HelloWorld";
- }
-}

local-cli/templates/HelloWorld/android/app/src/main/java/com/helloworld/MainApplication.java

@@ -1,45 +0,0 @@
-package com.helloworld;
-
-import android.app.Application;
-
-import com.facebook.react.ReactApplication;
-import com.facebook.react.ReactNativeHost;
-import com.facebook.react.ReactPackage;
-import com.facebook.react.shell.MainReactPackage;
-import com.facebook.soloader.SoLoader;
-
-import java.util.Arrays;
-import java.util.List;
-
-public class MainApplication extends Application implements ReactApplication {
-
- private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
- @Override
- public boolean getUseDeveloperSupport() {
- return BuildConfig.DEBUG;
- }
-
- @Override
- protected List<ReactPackage> getPackages() {
- return Arrays.<ReactPackage>asList(
- new MainReactPackage()
- );
- }
-
- @Override
- protected String getJSMainModuleName() {
- return "index";
- }
- };
-
- @Override
- public ReactNativeHost getReactNativeHost() {
- return mReactNativeHost;
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- SoLoader.init(this, /* native exopackage */ false);
- }
-}

local-cli/templates/HelloWorld/android/app/src/main/res/mipmap-hdpi/ic_launcher.png

Binary file local-cli/templates/HelloWorld/android/app/src/main/res/mipmap-hdpi/ic_launcher.png has changed

local-cli/templates/HelloWorld/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png

Binary file local-cli/templates/HelloWorld/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png has changed

local-cli/templates/HelloWorld/android/app/src/main/res/mipmap-mdpi/ic_launcher.png

Binary file local-cli/templates/HelloWorld/android/app/src/main/res/mipmap-mdpi/ic_launcher.png has changed

local-cli/templates/HelloWorld/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png

Binary file local-cli/templates/HelloWorld/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png has changed

local-cli/templates/HelloWorld/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png

Binary file local-cli/templates/HelloWorld/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png has changed

local-cli/templates/HelloWorld/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png

Binary file local-cli/templates/HelloWorld/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png has changed

local-cli/templates/HelloWorld/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png

Binary file local-cli/templates/HelloWorld/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png has changed

local-cli/templates/HelloWorld/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png

Binary file local-cli/templates/HelloWorld/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png has changed

local-cli/templates/HelloWorld/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png

Binary file local-cli/templates/HelloWorld/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png has changed

local-cli/templates/HelloWorld/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png

Binary file local-cli/templates/HelloWorld/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png has changed

local-cli/templates/HelloWorld/android/app/src/main/res/values/strings.xml

@@ -1,3 +0,0 @@
-<resources>
- <string name="app_name">Hello App Display Name</string>
-</resources>

local-cli/templates/HelloWorld/android/app/src/main/res/values/styles.xml

@@ -1,8 +0,0 @@
-<resources>
-
- <!-- Base application theme. -->
- <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
- <!-- Customize your theme here. -->
- </style>
-
-</resources>

local-cli/templates/HelloWorld/android/build.gradle

@@ -1,39 +0,0 @@
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
-
-buildscript {
- ext {
- buildToolsVersion = "27.0.3"
- minSdkVersion = 16
- compileSdkVersion = 27
- targetSdkVersion = 26
- supportLibVersion = "27.1.1"
- }
- repositories {
- google()
- jcenter()
- }
- dependencies {
- classpath 'com.android.tools.build:gradle:3.1.4'
-
- // NOTE: Do not place your application dependencies here; they belong
- // in the individual module build.gradle files
- }
-}
-
-allprojects {
- repositories {
- mavenLocal()
- google()
- jcenter()
- maven {
- // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
- url "$rootDir/../node_modules/react-native/android"
- }
- }
-}
-
-
-task wrapper(type: Wrapper) {
- gradleVersion = '4.4'
- distributionUrl = distributionUrl.replace("bin", "all")
-}

local-cli/templates/HelloWorld/android/gradle/wrapper/gradle-wrapper.jar

Binary file local-cli/templates/HelloWorld/android/gradle/wrapper/gradle-wrapper.jar has changed

local-cli/templates/HelloWorld/android/gradle/wrapper/gradle-wrapper.properties

@@ -1,5 +0,0 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip

local-cli/templates/HelloWorld/android/gradle.properties

@@ -1,18 +0,0 @@
-# Project-wide Gradle settings.
-
-# IDE (e.g. Android Studio) users:
-# Gradle settings configured through the IDE *will override*
-# any settings specified in this file.
-
-# For more details on how to configure your build environment visit
-# http://www.gradle.org/docs/current/userguide/build_environment.html
-
-# Specifies the JVM arguments used for the daemon process.
-# The setting is particularly useful for tweaking memory settings.
-# Default value: -Xmx10248m -XX:MaxPermSize=256m
-# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
-
-# When configured, Gradle will run in incubating parallel mode.
-# This option should only be used with decoupled projects. More details, visit
-# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
-# org.gradle.parallel=true

local-cli/templates/HelloWorld/android/gradlew

@@ -1,172 +0,0 @@
-#!/usr/bin/env sh
-
-##############################################################################
-##
-## Gradle start up script for UN*X
-##
-##############################################################################
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
-
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
-
-warn () {
- echo "$*"
-}
-
-die () {
- echo
- echo "$*"
- echo
- exit 1
-}
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-nonstop=false
-case "`uname`" in
- CYGWIN* )
- cygwin=true
- ;;
- Darwin* )
- darwin=true
- ;;
- MINGW* )
- msys=true
- ;;
- NONSTOP* )
- nonstop=true
- ;;
-esac
-
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
-# Determine the Java command to use to start the JVM.
-if [ -n "$JAVA_HOME" ] ; then
- if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
- # IBM's JDK on AIX uses strange locations for the executables
- JAVACMD="$JAVA_HOME/jre/sh/java"
- else
- JAVACMD="$JAVA_HOME/bin/java"
- fi
- if [ ! -x "$JAVACMD" ] ; then
- die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
- fi
-else
- JAVACMD="java"
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-fi
-
-# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
- MAX_FD_LIMIT=`ulimit -H -n`
- if [ $? -eq 0 ] ; then
- if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
- MAX_FD="$MAX_FD_LIMIT"
- fi
- ulimit -n $MAX_FD
- if [ $? -ne 0 ] ; then
- warn "Could not set maximum file descriptor limit: $MAX_FD"
- fi
- else
- warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
- fi
-fi
-
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
- GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
-
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
- APP_HOME=`cygpath --path --mixed "$APP_HOME"`
- CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
- JAVACMD=`cygpath --unix "$JAVACMD"`
-
- # We build the pattern for arguments to be converted via cygpath
- ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
- SEP=""
- for dir in $ROOTDIRSRAW ; do
- ROOTDIRS="$ROOTDIRS$SEP$dir"
- SEP="|"
- done
- OURCYGPATTERN="(^($ROOTDIRS))"
- # Add a user-defined pattern to the cygpath arguments
- if [ "$GRADLE_CYGPATTERN" != "" ] ; then
- OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
- fi
- # Now convert the arguments - kludge to limit ourselves to /bin/sh
- i=0
- for arg in "$@" ; do
- CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
- CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
-
- if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
- eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
- else
- eval `echo args$i`="\"$arg\""
- fi
- i=$((i+1))
- done
- case $i in
- (0) set -- ;;
- (1) set -- "$args0" ;;
- (2) set -- "$args0" "$args1" ;;
- (3) set -- "$args0" "$args1" "$args2" ;;
- (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
- esac
-fi
-
-# Escape application args
-save () {
- for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
- echo " "
-}
-APP_ARGS=$(save "$@")
-
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
-
-# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
-if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
- cd "$(dirname "$0")"
-fi
-
-exec "$JAVACMD" "$@"

local-cli/templates/HelloWorld/android/gradlew.bat

@@ -1,84 +0,0 @@
-@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto init
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega

local-cli/templates/HelloWorld/android/keystores/BUCK

@@ -1,8 +0,0 @@
-keystore(
- name = "debug",
- properties = "debug.keystore.properties",
- store = "debug.keystore",
- visibility = [
- "PUBLIC",
- ],
-)

local-cli/templates/HelloWorld/android/keystores/debug.keystore.properties

@@ -1,4 +0,0 @@
-key.store=debug.keystore
-key.alias=androiddebugkey
-key.store.password=android
-key.alias.password=android

local-cli/templates/HelloWorld/android/settings.gradle

@@ -1,3 +0,0 @@
-rootProject.name = 'HelloWorld'
-
-include ':app'

local-cli/templates/HelloWorld/App.js

@@ -1,49 +0,0 @@
-/**
- * Sample React Native App
- * https://github.com/facebook/react-native
- *
- * @format
- * @flow
- */
-
-import React, {Component} from 'react';
-import {Platform, StyleSheet, Text, View} from 'react-native';
-
-const instructions = Platform.select({
- ios: 'Press Cmd+R to reload,\n' + 'Cmd+D or shake for dev menu',
- android:
- 'Double tap R on your keyboard to reload,\n' +
- 'Shake or press menu button for dev menu',
-});
-
-type Props = {};
-export default class App extends Component<Props> {
- render() {
- return (
- <View style={styles.container}>
- <Text style={styles.welcome}>Welcome to React Native!</Text>
- <Text style={styles.instructions}>To get started, edit App.js</Text>
- <Text style={styles.instructions}>{instructions}</Text>
- </View>
- );
- }
-}
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- justifyContent: 'center',
- alignItems: 'center',
- backgroundColor: '#F5FCFF',
- },
- welcome: {
- fontSize: 20,
- textAlign: 'center',
- margin: 10,
- },
- instructions: {
- textAlign: 'center',
- color: '#333333',
- marginBottom: 5,
- },
-});

local-cli/templates/HelloWorld/app.json

@@ -1,4 +0,0 @@
-{
- "name": "HelloWorld",
- "displayName": "HelloWorld"
-}
\ No newline at end of file

local-cli/templates/HelloWorld/_babelrc

@@ -1,3 +0,0 @@
-{
- "presets": ["module:metro-react-native-babel-preset"]
-}

local-cli/templates/HelloWorld/_buckconfig

@@ -1,6 +0,0 @@
-
-[android]
- target = Google Inc.:Google APIs:23
-
-[maven_repositories]
- central = https://repo1.maven.org/maven2

local-cli/templates/HelloWorld/_flowconfig

@@ -1,70 +0,0 @@
-[ignore]
-; We fork some components by platform
-.*/*[.]android.js
-
-; Ignore "BUCK" generated dirs
-<PROJECT_ROOT>/\.buckd/
-
-; Ignore unexpected extra "@providesModule"
-.*/node_modules/.*/node_modules/fbjs/.*
-
-; Ignore duplicate module providers
-; For RN Apps installed via npm, "Libraries" folder is inside
-; "node_modules/react-native" but in the source repo it is in the root
-.*/Libraries/react-native/React.js
-
-; Ignore polyfills
-.*/Libraries/polyfills/.*
-
-; Ignore metro
-.*/node_modules/metro/.*
-
-[include]
-
-[libs]
-node_modules/react-native/Libraries/react-native/react-native-interface.js
-node_modules/react-native/flow/
-node_modules/react-native/flow-github/
-
-[options]
-emoji=true
-
-esproposal.optional_chaining=enable
-esproposal.nullish_coalescing=enable
-
-module.system=haste
-module.system.haste.use_name_reducers=true
-# get basename
-module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1'
-# strip .js or .js.flow suffix
-module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1'
-# strip .ios suffix
-module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1'
-module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1'
-module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1'
-module.system.haste.paths.blacklist=.*/__tests__/.*
-module.system.haste.paths.blacklist=.*/__mocks__/.*
-module.system.haste.paths.blacklist=<PROJECT_ROOT>/node_modules/react-native/Libraries/Animated/src/polyfills/.*
-module.system.haste.paths.whitelist=<PROJECT_ROOT>/node_modules/react-native/Libraries/.*
-
-munge_underscores=true
-
-module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
-
-module.file_ext=.js
-module.file_ext=.jsx
-module.file_ext=.json
-module.file_ext=.native.js
-
-suppress_type=$FlowIssue
-suppress_type=$FlowFixMe
-suppress_type=$FlowFixMeProps
-suppress_type=$FlowFixMeState
-
-suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
-suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
-suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
-suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
-
-[version]
-^0.78.0

local-cli/templates/HelloWorld/_gitattributes

@@ -1 +0,0 @@
-*.pbxproj -text

local-cli/templates/HelloWorld/_gitignore

@@ -1,56 +0,0 @@
-# OSX
-#
-.DS_Store
-
-# Xcode
-#
-build/
-*.pbxuser
-!default.pbxuser
-*.mode1v3
-!default.mode1v3
-*.mode2v3
-!default.mode2v3
-*.perspectivev3
-!default.perspectivev3
-xcuserdata
-*.xccheckout
-*.moved-aside
-DerivedData
-*.hmap
-*.ipa
-*.xcuserstate
-project.xcworkspace
-
-# Android/IntelliJ
-#
-build/
-.idea
-.gradle
-local.properties
-*.iml
-
-# node.js
-#
-node_modules/
-npm-debug.log
-yarn-error.log
-
-# BUCK
-buck-out/
-\.buckd/
-*.keystore
-
-# fastlane
-#
-# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
-# screenshots whenever they are needed.
-# For more information about the recommended setup visit:
-# https://docs.fastlane.tools/best-practices/source-control/
-
-*/fastlane/report.xml
-*/fastlane/Preview.html
-*/fastlane/screenshots
-
-# Bundle artifact
-*.jsbundle

local-cli/templates/HelloWorld/index.js

@@ -1,7 +0,0 @@
-/** @format */
-
-import {AppRegistry} from 'react-native';
-import App from './App';
-import {name as appName} from './app.json';
-
-AppRegistry.registerComponent(appName, () => App);

local-cli/templates/HelloWorld/ios/HelloWorld/AppDelegate.h

@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#import <UIKit/UIKit.h>
-
-@interface AppDelegate : UIResponder <UIApplicationDelegate>
-
-@property (nonatomic, strong) UIWindow *window;
-
-@end

local-cli/templates/HelloWorld/ios/HelloWorld/AppDelegate.m

@@ -1,39 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#import "AppDelegate.h"
-
-#import <React/RCTBundleURLProvider.h>
-#import <React/RCTRootView.h>
-
-@implementation AppDelegate
-
-- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
-{
- NSURL *jsCodeLocation;
-
- #ifdef DEBUG
- jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
- #else
- jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
- #endif
-
- RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
- moduleName:@"HelloWorld"
- initialProperties:nil
- launchOptions:launchOptions];
- rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
-
- self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
- UIViewController *rootViewController = [UIViewController new];
- rootViewController.view = rootView;
- self.window.rootViewController = rootViewController;
- [self.window makeKeyAndVisible];
- return YES;
-}
-
-@end

local-cli/templates/HelloWorld/ios/HelloWorld/Base.lproj/LaunchScreen.xib

@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7702" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
- <dependencies>
- <deployment identifier="iOS"/>
- <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7701"/>
- <capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
- </dependencies>
- <objects>
- <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
- <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
- <view contentMode="scaleToFill" id="iN0-l3-epB">
- <rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
- <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
- <subviews>
- <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Powered by React Native" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
- <rect key="frame" x="20" y="439" width="441" height="21"/>
- <fontDescription key="fontDescription" type="system" pointSize="17"/>
- <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
- <nil key="highlightedColor"/>
- </label>
- <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="HelloWorld" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
- <rect key="frame" x="20" y="140" width="441" height="43"/>
- <fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
- <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
- <nil key="highlightedColor"/>
- </label>
- </subviews>
- <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
- <constraints>
- <constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
- <constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
- <constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
- <constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
- <constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
- <constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
- </constraints>
- <nil key="simulatedStatusBarMetrics"/>
- <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
- <point key="canvasLocation" x="548" y="455"/>
- </view>
- </objects>
-</document>

local-cli/templates/HelloWorld/ios/HelloWorld/Images.xcassets/AppIcon.appiconset/Contents.json

@@ -1,38 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "iphone",
- "size" : "29x29",
- "scale" : "2x"
- },
- {
- "idiom" : "iphone",
- "size" : "29x29",
- "scale" : "3x"
- },
- {
- "idiom" : "iphone",
- "size" : "40x40",
- "scale" : "2x"
- },
- {
- "idiom" : "iphone",
- "size" : "40x40",
- "scale" : "3x"
- },
- {
- "idiom" : "iphone",
- "size" : "60x60",
- "scale" : "2x"
- },
- {
- "idiom" : "iphone",
- "size" : "60x60",
- "scale" : "3x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}
\ No newline at end of file

local-cli/templates/HelloWorld/ios/HelloWorld/Images.xcassets/Contents.json

@@ -1,6 +0,0 @@
-{
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}

local-cli/templates/HelloWorld/ios/HelloWorld/Info.plist

@@ -1,60 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>CFBundleDevelopmentRegion</key>
- <string>en</string>
- <key>CFBundleDisplayName</key>
- <string>Hello App Display Name</string>
- <key>CFBundleExecutable</key>
- <string>$(EXECUTABLE_NAME)</string>
- <key>CFBundleIdentifier</key>
- <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
- <key>CFBundleName</key>
- <string>$(PRODUCT_NAME)</string>
- <key>CFBundlePackageType</key>
- <string>APPL</string>
- <key>CFBundleShortVersionString</key>
- <string>1.0</string>
- <key>CFBundleSignature</key>
- <string>????</string>
- <key>CFBundleVersion</key>
- <string>1</string>
- <key>LSRequiresIPhoneOS</key>
- <true/>
- <key>NSLocationWhenInUseUsageDescription</key>
- <string></string>
- <key>UILaunchStoryboardName</key>
- <string>LaunchScreen</string>
- <key>UIRequiredDeviceCapabilities</key>
- <array>
- <string>armv7</string>
- </array>
- <key>UISupportedInterfaceOrientations</key>
- <array>
- <string>UIInterfaceOrientationPortrait</string>
- <string>UIInterfaceOrientationLandscapeLeft</string>
- <string>UIInterfaceOrientationLandscapeRight</string>
- </array>
- <key>UIViewControllerBasedStatusBarAppearance</key>
- <false/>
- <key>NSLocationWhenInUseUsageDescription</key>
- <string></string>
- <key>NSAppTransportSecurity</key>
- <!--See http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/ -->
- <dict>
- <key>NSAllowsArbitraryLoads</key>
- <true/>
- <key>NSExceptionDomains</key>
- <dict>
- <key>localhost</key>
- <dict>
- <key>NSExceptionAllowsInsecureHTTPLoads</key>
- <true/>
- </dict>
- </dict>
- </dict>
-</dict>
-</plist>

local-cli/templates/HelloWorld/ios/HelloWorld/main.m

@@ -1,16 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#import <UIKit/UIKit.h>
-
-#import "AppDelegate.h"
-
-int main(int argc, char * argv[]) {
- @autoreleasepool {
- return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
- }
-}

local-cli/templates/HelloWorld/ios/HelloWorldTests/HelloWorldTests.m

@@ -1,68 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#import <UIKit/UIKit.h>
-#import <XCTest/XCTest.h>
-
-#import <React/RCTLog.h>
-#import <React/RCTRootView.h>
-
-#define TIMEOUT_SECONDS 600
-#define TEXT_TO_LOOK_FOR @"Welcome to React Native!"
-
-@interface HelloWorldTests : XCTestCase
-
-@end
-
-@implementation HelloWorldTests
-
-- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
-{
- if (test(view)) {
- return YES;
- }
- for (UIView *subview in [view subviews]) {
- if ([self findSubviewInView:subview matching:test]) {
- return YES;
- }
- }
- return NO;
-}
-
-- (void)testRendersWelcomeScreen
-{
- UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController];
- NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
- BOOL foundElement = NO;
-
- __block NSString *redboxError = nil;
- RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
- if (level >= RCTLogLevelError) {
- redboxError = message;
- }
- });
-
- while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
- [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
- [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
-
- foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
- if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
- return YES;
- }
- return NO;
- }];
- }
-
- RCTSetLogFunction(RCTDefaultLogFunction);
-
- XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
- XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
-}
-
-
-@end

local-cli/templates/HelloWorld/ios/HelloWorldTests/Info.plist

@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>CFBundleDevelopmentRegion</key>
- <string>en</string>
- <key>CFBundleExecutable</key>
- <string>$(EXECUTABLE_NAME)</string>
- <key>CFBundleIdentifier</key>
- <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
- <key>CFBundleName</key>
- <string>$(PRODUCT_NAME)</string>
- <key>CFBundlePackageType</key>
- <string>BNDL</string>
- <key>CFBundleShortVersionString</key>
- <string>1.0</string>
- <key>CFBundleSignature</key>
- <string>????</string>
- <key>CFBundleVersion</key>
- <string>1</string>
-</dict>
-</plist>

local-cli/templates/HelloWorld/ios/HelloWorld-tvOS/Info.plist

@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>CFBundleDevelopmentRegion</key>
- <string>en</string>
- <key>CFBundleExecutable</key>
- <string>$(EXECUTABLE_NAME)</string>
- <key>CFBundleIdentifier</key>
- <string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
- <key>CFBundleName</key>
- <string>$(PRODUCT_NAME)</string>
- <key>CFBundlePackageType</key>
- <string>APPL</string>
- <key>CFBundleShortVersionString</key>
- <string>1.0</string>
- <key>CFBundleSignature</key>
- <string>????</string>
- <key>CFBundleVersion</key>
- <string>1</string>
- <key>LSRequiresIPhoneOS</key>
- <true/>
- <key>UILaunchStoryboardName</key>
- <string>LaunchScreen</string>
- <key>UIRequiredDeviceCapabilities</key>
- <array>
- <string>armv7</string>
- </array>
- <key>UISupportedInterfaceOrientations</key>
- <array>
- <string>UIInterfaceOrientationPortrait</string>
- <string>UIInterfaceOrientationLandscapeLeft</string>
- <string>UIInterfaceOrientationLandscapeRight</string>
- </array>
- <key>UIViewControllerBasedStatusBarAppearance</key>
- <false/>
- <key>NSLocationWhenInUseUsageDescription</key>
- <string></string>
- <key>NSAppTransportSecurity</key>
- <!--See http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/ -->
- <dict>
- <key>NSExceptionDomains</key>
- <dict>
- <key>localhost</key>
- <dict>
- <key>NSExceptionAllowsInsecureHTTPLoads</key>
- <true/>
- </dict>
- </dict>
- </dict>
-</dict>
-</plist>

local-cli/templates/HelloWorld/ios/HelloWorld-tvOSTests/Info.plist

@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>CFBundleDevelopmentRegion</key>
- <string>en</string>
- <key>CFBundleExecutable</key>
- <string>$(EXECUTABLE_NAME)</string>
- <key>CFBundleIdentifier</key>
- <string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
- <key>CFBundleName</key>
- <string>$(PRODUCT_NAME)</string>
- <key>CFBundlePackageType</key>
- <string>BNDL</string>
- <key>CFBundleShortVersionString</key>
- <string>1.0</string>
- <key>CFBundleSignature</key>
- <string>????</string>
- <key>CFBundleVersion</key>
- <string>1</string>
-</dict>
-</plist>

local-cli/templates/HelloWorld/ios/HelloWorld.xcodeproj/project.pbxproj

@@ -1,1494 +0,0 @@
-// !$*UTF8*$!
-{
- archiveVersion = 1;
- classes = {
- };
- objectVersion = 46;
- objects = {
-
-/* Begin PBXBuildFile section */
- 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; };
- 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; };
- 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */; };
- 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; };
- 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; };
- 00E356F31AD99517003FC87E /* HelloWorldTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* HelloWorldTests.m */; };
- 11D1A2F320CAFA9E000508D9 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */; };
- 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; };
- 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; };
- 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */; };
- 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
- 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
- 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
- 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
- 140ED2AC1D01E1AD002B40FF /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
- 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
- 2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
- 2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
- 2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
- 2D02E4C21E0B4AEC006451C7 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation.a */; };
- 2D02E4C31E0B4AEC006451C7 /* libRCTImage-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */; };
- 2D02E4C41E0B4AEC006451C7 /* libRCTLinking-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */; };
- 2D02E4C51E0B4AEC006451C7 /* libRCTNetwork-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */; };
- 2D02E4C61E0B4AEC006451C7 /* libRCTSettings-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */; };
- 2D02E4C71E0B4AEC006451C7 /* libRCTText-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */; };
- 2D02E4C81E0B4AEC006451C7 /* libRCTWebSocket-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */; };
- 2D16E6881FA4F8E400B85C8A /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D16E6891FA4F8E400B85C8A /* libReact.a */; };
- 2DCD954D1E0B4F2C00145EB5 /* HelloWorldTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* HelloWorldTests.m */; };
- 2DF0FFEE2056DD460020B375 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3EA31DF850E9000B6D8A /* libReact.a */; };
- 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
- ADBDB9381DFEBF1600ED6528 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXContainerItemProxy section */
- 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 134814201AA4EA6300B7C361;
- remoteInfo = RCTActionSheet;
- };
- 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 134814201AA4EA6300B7C361;
- remoteInfo = RCTGeolocation;
- };
- 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 58B5115D1A9E6B3D00147676;
- remoteInfo = RCTImage;
- };
- 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 58B511DB1A9E6C8500147676;
- remoteInfo = RCTNetwork;
- };
- 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 832C81801AAF6DEF007FA2F7;
- remoteInfo = RCTVibration;
- };
- 00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 13B07F861A680F5B00A75B9A;
- remoteInfo = HelloWorld;
- };
- 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 134814201AA4EA6300B7C361;
- remoteInfo = RCTSettings;
- };
- 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 3C86DF461ADF2C930047B81A;
- remoteInfo = RCTWebSocket;
- };
- 146834031AC3E56700842450 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192;
- remoteInfo = React;
- };
- 2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 2D02E47A1E0B4A5D006451C7;
- remoteInfo = "HelloWorld-tvOS";
- };
- 2D16E6711FA4F8DC00B85C8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = ADD01A681E09402E00F6D226;
- remoteInfo = "RCTBlob-tvOS";
- };
- 2D16E6831FA4F8DC00B85C8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 3DBE0D001F3B181A0099AA32;
- remoteInfo = fishhook;
- };
- 2D16E6851FA4F8DC00B85C8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 3DBE0D0D1F3B181C0099AA32;
- remoteInfo = "fishhook-tvOS";
- };
- 2DF0FFDE2056DD460020B375 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = EBF21BDC1FC498900052F4D5;
- remoteInfo = jsinspector;
- };
- 2DF0FFE02056DD460020B375 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = EBF21BFA1FC4989A0052F4D5;
- remoteInfo = "jsinspector-tvOS";
- };
- 2DF0FFE22056DD460020B375 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 139D7ECE1E25DB7D00323FB7;
- remoteInfo = "third-party";
- };
- 2DF0FFE42056DD460020B375 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 3D383D3C1EBD27B6005632C8;
- remoteInfo = "third-party-tvOS";
- };
- 2DF0FFE62056DD460020B375 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 139D7E881E25C6D100323FB7;
- remoteInfo = "double-conversion";
- };
- 2DF0FFE82056DD460020B375 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 3D383D621EBD27B9005632C8;
- remoteInfo = "double-conversion-tvOS";
- };
- 2DF0FFEA2056DD460020B375 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 9936F3131F5F2E4B0010BF04;
- remoteInfo = privatedata;
- };
- 2DF0FFEC2056DD460020B375 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 9936F32F1F5F2E5B0010BF04;
- remoteInfo = "privatedata-tvOS";
- };
- 3DAD3E831DF850E9000B6D8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 2D2A283A1D9B042B00D4039D;
- remoteInfo = "RCTImage-tvOS";
- };
- 3DAD3E871DF850E9000B6D8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 2D2A28471D9B043800D4039D;
- remoteInfo = "RCTLinking-tvOS";
- };
- 3DAD3E8B1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 2D2A28541D9B044C00D4039D;
- remoteInfo = "RCTNetwork-tvOS";
- };
- 3DAD3E8F1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 2D2A28611D9B046600D4039D;
- remoteInfo = "RCTSettings-tvOS";
- };
- 3DAD3E931DF850E9000B6D8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 2D2A287B1D9B048500D4039D;
- remoteInfo = "RCTText-tvOS";
- };
- 3DAD3E981DF850E9000B6D8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 2D2A28881D9B049200D4039D;
- remoteInfo = "RCTWebSocket-tvOS";
- };
- 3DAD3EA21DF850E9000B6D8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 2D2A28131D9B038B00D4039D;
- remoteInfo = "React-tvOS";
- };
- 3DAD3EA41DF850E9000B6D8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 3D3C059A1DE3340900C268FA;
- remoteInfo = yoga;
- };
- 3DAD3EA61DF850E9000B6D8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 3D3C06751DE3340C00C268FA;
- remoteInfo = "yoga-tvOS";
- };
- 3DAD3EA81DF850E9000B6D8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 3D3CD9251DE5FBEC00167DC4;
- remoteInfo = cxxreact;
- };
- 3DAD3EAA1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 3D3CD9321DE5FBEE00167DC4;
- remoteInfo = "cxxreact-tvOS";
- };
- 3DAD3EAC1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 3D3CD90B1DE5FBD600167DC4;
- remoteInfo = jschelpers;
- };
- 3DAD3EAE1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 3D3CD9181DE5FBD800167DC4;
- remoteInfo = "jschelpers-tvOS";
- };
- 5E9157321DD0AC6500FF2AA8 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 134814201AA4EA6300B7C361;
- remoteInfo = RCTAnimation;
- };
- 5E9157341DD0AC6500FF2AA8 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 2D2A28201D9B03D100D4039D;
- remoteInfo = "RCTAnimation-tvOS";
- };
- 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 134814201AA4EA6300B7C361;
- remoteInfo = RCTLinking;
- };
- 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 58B5119B1A9E6C1200147676;
- remoteInfo = RCTText;
- };
- ADBDB9261DFEBF0700ED6528 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 358F4ED71D1E81A9004DF814;
- remoteInfo = RCTBlob;
- };
-/* End PBXContainerItemProxy section */
-
-/* Begin PBXFileReference section */
- 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = "<group>"; };
- 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = "../node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj"; sourceTree = "<group>"; };
- 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = "../node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj"; sourceTree = "<group>"; };
- 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = "../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj"; sourceTree = "<group>"; };
- 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = "../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj"; sourceTree = "<group>"; };
- 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = "../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj"; sourceTree = "<group>"; };
- 00E356EE1AD99517003FC87E /* HelloWorldTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HelloWorldTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
- 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
- 00E356F21AD99517003FC87E /* HelloWorldTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HelloWorldTests.m; sourceTree = "<group>"; };
- 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = "../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj"; sourceTree = "<group>"; };
- 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = "../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj"; sourceTree = "<group>"; };
- 13B07F961A680F5B00A75B9A /* HelloWorld.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloWorld.app; sourceTree = BUILT_PRODUCTS_DIR; };
- 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = HelloWorld/AppDelegate.h; sourceTree = "<group>"; };
- 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = HelloWorld/AppDelegate.m; sourceTree = "<group>"; };
- 13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
- 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = HelloWorld/Images.xcassets; sourceTree = "<group>"; };
- 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = HelloWorld/Info.plist; sourceTree = "<group>"; };
- 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = HelloWorld/main.m; sourceTree = "<group>"; };
- 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = "<group>"; };
- 2D02E47B1E0B4A5D006451C7 /* HelloWorld-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "HelloWorld-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
- 2D02E4901E0B4A5D006451C7 /* HelloWorld-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "HelloWorld-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
- 2D16E6891FA4F8E400B85C8A /* libReact.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libReact.a; sourceTree = BUILT_PRODUCTS_DIR; };
- 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = "<group>"; };
- 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = "<group>"; };
- 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = "<group>"; };
- ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTBlob.xcodeproj; path = "../node_modules/react-native/Libraries/Blob/RCTBlob.xcodeproj"; sourceTree = "<group>"; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
- 00E356EB1AD99517003FC87E /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 140ED2AC1D01E1AD002B40FF /* libReact.a in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- ADBDB9381DFEBF1600ED6528 /* libRCTBlob.a in Frameworks */,
- 11D1A2F320CAFA9E000508D9 /* libRCTAnimation.a in Frameworks */,
- 146834051AC3E58100842450 /* libReact.a in Frameworks */,
- 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */,
- 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */,
- 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */,
- 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */,
- 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */,
- 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */,
- 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */,
- 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */,
- 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 2D02E4781E0B4A5D006451C7 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 2D16E6881FA4F8E400B85C8A /* libReact.a in Frameworks */,
- 2D02E4C21E0B4AEC006451C7 /* libRCTAnimation.a in Frameworks */,
- 2D02E4C31E0B4AEC006451C7 /* libRCTImage-tvOS.a in Frameworks */,
- 2D02E4C41E0B4AEC006451C7 /* libRCTLinking-tvOS.a in Frameworks */,
- 2D02E4C51E0B4AEC006451C7 /* libRCTNetwork-tvOS.a in Frameworks */,
- 2D02E4C61E0B4AEC006451C7 /* libRCTSettings-tvOS.a in Frameworks */,
- 2D02E4C71E0B4AEC006451C7 /* libRCTText-tvOS.a in Frameworks */,
- 2D02E4C81E0B4AEC006451C7 /* libRCTWebSocket-tvOS.a in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 2D02E48D1E0B4A5D006451C7 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 2DF0FFEE2056DD460020B375 /* libReact.a in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
- 00C302A81ABCB8CE00DB3ED1 /* Products */ = {
- isa = PBXGroup;
- children = (
- 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */,
- );
- name = Products;
- sourceTree = "<group>";
- };
- 00C302B61ABCB90400DB3ED1 /* Products */ = {
- isa = PBXGroup;
- children = (
- 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */,
- );
- name = Products;
- sourceTree = "<group>";
- };
- 00C302BC1ABCB91800DB3ED1 /* Products */ = {
- isa = PBXGroup;
- children = (
- 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */,
- 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */,
- );
- name = Products;
- sourceTree = "<group>";
- };
- 00C302D41ABCB9D200DB3ED1 /* Products */ = {
- isa = PBXGroup;
- children = (
- 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */,
- 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */,
- );
- name = Products;
- sourceTree = "<group>";
- };
- 00C302E01ABCB9EE00DB3ED1 /* Products */ = {
- isa = PBXGroup;
- children = (
- 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */,
- );
- name = Products;
- sourceTree = "<group>";
- };
- 00E356EF1AD99517003FC87E /* HelloWorldTests */ = {
- isa = PBXGroup;
- children = (
- 00E356F21AD99517003FC87E /* HelloWorldTests.m */,
- 00E356F01AD99517003FC87E /* Supporting Files */,
- );
- path = HelloWorldTests;
- sourceTree = "<group>";
- };
- 00E356F01AD99517003FC87E /* Supporting Files */ = {
- isa = PBXGroup;
- children = (
- 00E356F11AD99517003FC87E /* Info.plist */,
- );
- name = "Supporting Files";
- sourceTree = "<group>";
- };
- 139105B71AF99BAD00B5F7CC /* Products */ = {
- isa = PBXGroup;
- children = (
- 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */,
- 3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */,
- );
- name = Products;
- sourceTree = "<group>";
- };
- 139FDEE71B06529A00C62182 /* Products */ = {
- isa = PBXGroup;
- children = (
- 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */,
- 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */,
- 2D16E6841FA4F8DC00B85C8A /* libfishhook.a */,
- 2D16E6861FA4F8DC00B85C8A /* libfishhook-tvOS.a */,
- );
- name = Products;
- sourceTree = "<group>";
- };
- 13B07FAE1A68108700A75B9A /* HelloWorld */ = {
- isa = PBXGroup;
- children = (
- 008F07F21AC5B25A0029DE68 /* main.jsbundle */,
- 13B07FAF1A68108700A75B9A /* AppDelegate.h */,
- 13B07FB01A68108700A75B9A /* AppDelegate.m */,
- 13B07FB51A68108700A75B9A /* Images.xcassets */,
- 13B07FB61A68108700A75B9A /* Info.plist */,
- 13B07FB11A68108700A75B9A /* LaunchScreen.xib */,
- 13B07FB71A68108700A75B9A /* main.m */,
- );
- name = HelloWorld;
- sourceTree = "<group>";
- };
- 146834001AC3E56700842450 /* Products */ = {
- isa = PBXGroup;
- children = (
- 146834041AC3E56700842450 /* libReact.a */,
- 3DAD3EA31DF850E9000B6D8A /* libReact.a */,
- 3DAD3EA51DF850E9000B6D8A /* libyoga.a */,
- 3DAD3EA71DF850E9000B6D8A /* libyoga.a */,
- 3DAD3EA91DF850E9000B6D8A /* libcxxreact.a */,
- 3DAD3EAB1DF850E9000B6D8A /* libcxxreact.a */,
- 3DAD3EAD1DF850E9000B6D8A /* libjschelpers.a */,
- 3DAD3EAF1DF850E9000B6D8A /* libjschelpers.a */,
- 2DF0FFDF2056DD460020B375 /* libjsinspector.a */,
- 2DF0FFE12056DD460020B375 /* libjsinspector-tvOS.a */,
- 2DF0FFE32056DD460020B375 /* libthird-party.a */,
- 2DF0FFE52056DD460020B375 /* libthird-party.a */,
- 2DF0FFE72056DD460020B375 /* libdouble-conversion.a */,
- 2DF0FFE92056DD460020B375 /* libdouble-conversion.a */,
- 2DF0FFEB2056DD460020B375 /* libprivatedata.a */,
- 2DF0FFED2056DD460020B375 /* libprivatedata-tvOS.a */,
- );
- name = Products;
- sourceTree = "<group>";
- };
- 2D16E6871FA4F8E400B85C8A /* Frameworks */ = {
- isa = PBXGroup;
- children = (
- 2D16E6891FA4F8E400B85C8A /* libReact.a */,
- );
- name = Frameworks;
- sourceTree = "<group>";
- };
- 5E91572E1DD0AC6500FF2AA8 /* Products */ = {
- isa = PBXGroup;
- children = (
- 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */,
- 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation.a */,
- );
- name = Products;
- sourceTree = "<group>";
- };
- 78C398B11ACF4ADC00677621 /* Products */ = {
- isa = PBXGroup;
- children = (
- 78C398B91ACF4ADC00677621 /* libRCTLinking.a */,
- 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */,
- );
- name = Products;
- sourceTree = "<group>";
- };
- 832341AE1AAA6A7D00B99B32 /* Libraries */ = {
- isa = PBXGroup;
- children = (
- 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */,
- 146833FF1AC3E56700842450 /* React.xcodeproj */,
- 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */,
- ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */,
- 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */,
- 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */,
- 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */,
- 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */,
- 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */,
- 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */,
- 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */,
- 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */,
- );
- name = Libraries;
- sourceTree = "<group>";
- };
- 832341B11AAA6A8300B99B32 /* Products */ = {
- isa = PBXGroup;
- children = (
- 832341B51AAA6A8300B99B32 /* libRCTText.a */,
- 3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */,
- );
- name = Products;
- sourceTree = "<group>";
- };
- 83CBB9F61A601CBA00E9B192 = {
- isa = PBXGroup;
- children = (
- 13B07FAE1A68108700A75B9A /* HelloWorld */,
- 832341AE1AAA6A7D00B99B32 /* Libraries */,
- 00E356EF1AD99517003FC87E /* HelloWorldTests */,
- 83CBBA001A601CBA00E9B192 /* Products */,
- 2D16E6871FA4F8E400B85C8A /* Frameworks */,
- );
- indentWidth = 2;
- sourceTree = "<group>";
- tabWidth = 2;
- usesTabs = 0;
- };
- 83CBBA001A601CBA00E9B192 /* Products */ = {
- isa = PBXGroup;
- children = (
- 13B07F961A680F5B00A75B9A /* HelloWorld.app */,
- 00E356EE1AD99517003FC87E /* HelloWorldTests.xctest */,
- 2D02E47B1E0B4A5D006451C7 /* HelloWorld-tvOS.app */,
- 2D02E4901E0B4A5D006451C7 /* HelloWorld-tvOSTests.xctest */,
- );
- name = Products;
- sourceTree = "<group>";
- };
- ADBDB9201DFEBF0600ED6528 /* Products */ = {
- isa = PBXGroup;
- children = (
- ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */,
- 2D16E6721FA4F8DC00B85C8A /* libRCTBlob-tvOS.a */,
- );
- name = Products;
- sourceTree = "<group>";
- };
-/* End PBXGroup section */
-
-/* Begin PBXNativeTarget section */
- 00E356ED1AD99517003FC87E /* HelloWorldTests */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "HelloWorldTests" */;
- buildPhases = (
- 00E356EA1AD99517003FC87E /* Sources */,
- 00E356EB1AD99517003FC87E /* Frameworks */,
- 00E356EC1AD99517003FC87E /* Resources */,
- );
- buildRules = (
- );
- dependencies = (
- 00E356F51AD99517003FC87E /* PBXTargetDependency */,
- );
- name = HelloWorldTests;
- productName = HelloWorldTests;
- productReference = 00E356EE1AD99517003FC87E /* HelloWorldTests.xctest */;
- productType = "com.apple.product-type.bundle.unit-test";
- };
- 13B07F861A680F5B00A75B9A /* HelloWorld */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "HelloWorld" */;
- buildPhases = (
- 13B07F871A680F5B00A75B9A /* Sources */,
- 13B07F8C1A680F5B00A75B9A /* Frameworks */,
- 13B07F8E1A680F5B00A75B9A /* Resources */,
- 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = HelloWorld;
- productName = "Hello World";
- productReference = 13B07F961A680F5B00A75B9A /* HelloWorld.app */;
- productType = "com.apple.product-type.application";
- };
- 2D02E47A1E0B4A5D006451C7 /* HelloWorld-tvOS */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "HelloWorld-tvOS" */;
- buildPhases = (
- 2D02E4771E0B4A5D006451C7 /* Sources */,
- 2D02E4781E0B4A5D006451C7 /* Frameworks */,
- 2D02E4791E0B4A5D006451C7 /* Resources */,
- 2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = "HelloWorld-tvOS";
- productName = "HelloWorld-tvOS";
- productReference = 2D02E47B1E0B4A5D006451C7 /* HelloWorld-tvOS.app */;
- productType = "com.apple.product-type.application";
- };
- 2D02E48F1E0B4A5D006451C7 /* HelloWorld-tvOSTests */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "HelloWorld-tvOSTests" */;
- buildPhases = (
- 2D02E48C1E0B4A5D006451C7 /* Sources */,
- 2D02E48D1E0B4A5D006451C7 /* Frameworks */,
- 2D02E48E1E0B4A5D006451C7 /* Resources */,
- );
- buildRules = (
- );
- dependencies = (
- 2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */,
- );
- name = "HelloWorld-tvOSTests";
- productName = "HelloWorld-tvOSTests";
- productReference = 2D02E4901E0B4A5D006451C7 /* HelloWorld-tvOSTests.xctest */;
- productType = "com.apple.product-type.bundle.unit-test";
- };
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
- 83CBB9F71A601CBA00E9B192 /* Project object */ = {
- isa = PBXProject;
- attributes = {
- LastUpgradeCheck = 0940;
- ORGANIZATIONNAME = Facebook;
- TargetAttributes = {
- 00E356ED1AD99517003FC87E = {
- CreatedOnToolsVersion = 6.2;
- TestTargetID = 13B07F861A680F5B00A75B9A;
- };
- 2D02E47A1E0B4A5D006451C7 = {
- CreatedOnToolsVersion = 8.2.1;
- ProvisioningStyle = Automatic;
- };
- 2D02E48F1E0B4A5D006451C7 = {
- CreatedOnToolsVersion = 8.2.1;
- ProvisioningStyle = Automatic;
- TestTargetID = 2D02E47A1E0B4A5D006451C7;
- };
- };
- };
- buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "HelloWorld" */;
- compatibilityVersion = "Xcode 3.2";
- developmentRegion = English;
- hasScannedForEncodings = 0;
- knownRegions = (
- en,
- Base,
- );
- mainGroup = 83CBB9F61A601CBA00E9B192;
- productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
- projectDirPath = "";
- projectReferences = (
- {
- ProductGroup = 00C302A81ABCB8CE00DB3ED1 /* Products */;
- ProjectRef = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */;
- },
- {
- ProductGroup = 5E91572E1DD0AC6500FF2AA8 /* Products */;
- ProjectRef = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */;
- },
- {
- ProductGroup = ADBDB9201DFEBF0600ED6528 /* Products */;
- ProjectRef = ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */;
- },
- {
- ProductGroup = 00C302B61ABCB90400DB3ED1 /* Products */;
- ProjectRef = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */;
- },
- {
- ProductGroup = 00C302BC1ABCB91800DB3ED1 /* Products */;
- ProjectRef = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
- },
- {
- ProductGroup = 78C398B11ACF4ADC00677621 /* Products */;
- ProjectRef = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;
- },
- {
- ProductGroup = 00C302D41ABCB9D200DB3ED1 /* Products */;
- ProjectRef = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */;
- },
- {
- ProductGroup = 139105B71AF99BAD00B5F7CC /* Products */;
- ProjectRef = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */;
- },
- {
- ProductGroup = 832341B11AAA6A8300B99B32 /* Products */;
- ProjectRef = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
- },
- {
- ProductGroup = 00C302E01ABCB9EE00DB3ED1 /* Products */;
- ProjectRef = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */;
- },
- {
- ProductGroup = 139FDEE71B06529A00C62182 /* Products */;
- ProjectRef = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
- },
- {
- ProductGroup = 146834001AC3E56700842450 /* Products */;
- ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */;
- },
- );
- projectRoot = "";
- targets = (
- 13B07F861A680F5B00A75B9A /* HelloWorld */,
- 00E356ED1AD99517003FC87E /* HelloWorldTests */,
- 2D02E47A1E0B4A5D006451C7 /* HelloWorld-tvOS */,
- 2D02E48F1E0B4A5D006451C7 /* HelloWorld-tvOSTests */,
- );
- };
-/* End PBXProject section */
-
-/* Begin PBXReferenceProxy section */
- 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libRCTActionSheet.a;
- remoteRef = 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libRCTGeolocation.a;
- remoteRef = 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libRCTImage.a;
- remoteRef = 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libRCTNetwork.a;
- remoteRef = 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libRCTVibration.a;
- remoteRef = 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libRCTSettings.a;
- remoteRef = 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libRCTWebSocket.a;
- remoteRef = 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 146834041AC3E56700842450 /* libReact.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libReact.a;
- remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 2D16E6721FA4F8DC00B85C8A /* libRCTBlob-tvOS.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libRCTBlob-tvOS.a";
- remoteRef = 2D16E6711FA4F8DC00B85C8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 2D16E6841FA4F8DC00B85C8A /* libfishhook.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libfishhook.a;
- remoteRef = 2D16E6831FA4F8DC00B85C8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 2D16E6861FA4F8DC00B85C8A /* libfishhook-tvOS.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libfishhook-tvOS.a";
- remoteRef = 2D16E6851FA4F8DC00B85C8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 2DF0FFDF2056DD460020B375 /* libjsinspector.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libjsinspector.a;
- remoteRef = 2DF0FFDE2056DD460020B375 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 2DF0FFE12056DD460020B375 /* libjsinspector-tvOS.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libjsinspector-tvOS.a";
- remoteRef = 2DF0FFE02056DD460020B375 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 2DF0FFE32056DD460020B375 /* libthird-party.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libthird-party.a";
- remoteRef = 2DF0FFE22056DD460020B375 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 2DF0FFE52056DD460020B375 /* libthird-party.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libthird-party.a";
- remoteRef = 2DF0FFE42056DD460020B375 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 2DF0FFE72056DD460020B375 /* libdouble-conversion.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libdouble-conversion.a";
- remoteRef = 2DF0FFE62056DD460020B375 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 2DF0FFE92056DD460020B375 /* libdouble-conversion.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libdouble-conversion.a";
- remoteRef = 2DF0FFE82056DD460020B375 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 2DF0FFEB2056DD460020B375 /* libprivatedata.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libprivatedata.a;
- remoteRef = 2DF0FFEA2056DD460020B375 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 2DF0FFED2056DD460020B375 /* libprivatedata-tvOS.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libprivatedata-tvOS.a";
- remoteRef = 2DF0FFEC2056DD460020B375 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libRCTImage-tvOS.a";
- remoteRef = 3DAD3E831DF850E9000B6D8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libRCTLinking-tvOS.a";
- remoteRef = 3DAD3E871DF850E9000B6D8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libRCTNetwork-tvOS.a";
- remoteRef = 3DAD3E8B1DF850E9000B6D8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libRCTSettings-tvOS.a";
- remoteRef = 3DAD3E8F1DF850E9000B6D8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libRCTText-tvOS.a";
- remoteRef = 3DAD3E931DF850E9000B6D8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = "libRCTWebSocket-tvOS.a";
- remoteRef = 3DAD3E981DF850E9000B6D8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 3DAD3EA31DF850E9000B6D8A /* libReact.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libReact.a;
- remoteRef = 3DAD3EA21DF850E9000B6D8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 3DAD3EA51DF850E9000B6D8A /* libyoga.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libyoga.a;
- remoteRef = 3DAD3EA41DF850E9000B6D8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 3DAD3EA71DF850E9000B6D8A /* libyoga.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libyoga.a;
- remoteRef = 3DAD3EA61DF850E9000B6D8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 3DAD3EA91DF850E9000B6D8A /* libcxxreact.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libcxxreact.a;
- remoteRef = 3DAD3EA81DF850E9000B6D8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 3DAD3EAB1DF850E9000B6D8A /* libcxxreact.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libcxxreact.a;
- remoteRef = 3DAD3EAA1DF850E9000B6D8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 3DAD3EAD1DF850E9000B6D8A /* libjschelpers.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libjschelpers.a;
- remoteRef = 3DAD3EAC1DF850E9000B6D8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 3DAD3EAF1DF850E9000B6D8A /* libjschelpers.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libjschelpers.a;
- remoteRef = 3DAD3EAE1DF850E9000B6D8A /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libRCTAnimation.a;
- remoteRef = 5E9157321DD0AC6500FF2AA8 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libRCTAnimation.a;
- remoteRef = 5E9157341DD0AC6500FF2AA8 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 78C398B91ACF4ADC00677621 /* libRCTLinking.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libRCTLinking.a;
- remoteRef = 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- 832341B51AAA6A8300B99B32 /* libRCTText.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libRCTText.a;
- remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libRCTBlob.a;
- remoteRef = ADBDB9261DFEBF0700ED6528 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
-/* End PBXReferenceProxy section */
-
-/* Begin PBXResourcesBuildPhase section */
- 00E356EC1AD99517003FC87E /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 13B07F8E1A680F5B00A75B9A /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
- 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 2D02E4791E0B4A5D006451C7 /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 2D02E48E1E0B4A5D006451C7 /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXShellScriptBuildPhase section */
- 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- inputPaths = (
- );
- name = "Bundle React Native code and images";
- outputPaths = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh";
- };
- 2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- inputPaths = (
- );
- name = "Bundle React Native Code And Images";
- outputPaths = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh";
- };
-/* End PBXShellScriptBuildPhase section */
-
-/* Begin PBXSourcesBuildPhase section */
- 00E356EA1AD99517003FC87E /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 00E356F31AD99517003FC87E /* HelloWorldTests.m in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 13B07F871A680F5B00A75B9A /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
- 13B07FC11A68108700A75B9A /* main.m in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 2D02E4771E0B4A5D006451C7 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */,
- 2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 2D02E48C1E0B4A5D006451C7 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 2DCD954D1E0B4F2C00145EB5 /* HelloWorldTests.m in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXSourcesBuildPhase section */
-
-/* Begin PBXTargetDependency section */
- 00E356F51AD99517003FC87E /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 13B07F861A680F5B00A75B9A /* HelloWorld */;
- targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */;
- };
- 2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 2D02E47A1E0B4A5D006451C7 /* HelloWorld-tvOS */;
- targetProxy = 2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */;
- };
-/* End PBXTargetDependency section */
-
-/* Begin PBXVariantGroup section */
- 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = {
- isa = PBXVariantGroup;
- children = (
- 13B07FB21A68108700A75B9A /* Base */,
- );
- name = LaunchScreen.xib;
- path = HelloWorld;
- sourceTree = "<group>";
- };
-/* End PBXVariantGroup section */
-
-/* Begin XCBuildConfiguration section */
- 00E356F61AD99517003FC87E /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- BUNDLE_LOADER = "$(TEST_HOST)";
- GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
- "$(inherited)",
- );
- INFOPLIST_FILE = HelloWorldTests/Info.plist;
- IPHONEOS_DEPLOYMENT_TARGET = 9.0;
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
- OTHER_LDFLAGS = (
- "-ObjC",
- "-lc++",
- );
- PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
- PRODUCT_NAME = "$(TARGET_NAME)";
- TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HelloWorld.app/HelloWorld";
- };
- name = Debug;
- };
- 00E356F71AD99517003FC87E /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- BUNDLE_LOADER = "$(TEST_HOST)";
- COPY_PHASE_STRIP = NO;
- INFOPLIST_FILE = HelloWorldTests/Info.plist;
- IPHONEOS_DEPLOYMENT_TARGET = 9.0;
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
- OTHER_LDFLAGS = (
- "-ObjC",
- "-lc++",
- );
- PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
- PRODUCT_NAME = "$(TARGET_NAME)";
- TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HelloWorld.app/HelloWorld";
- };
- name = Release;
- };
- 13B07F941A680F5B00A75B9A /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- CURRENT_PROJECT_VERSION = 1;
- DEAD_CODE_STRIPPING = NO;
- INFOPLIST_FILE = HelloWorld/Info.plist;
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
- OTHER_LDFLAGS = (
- "$(inherited)",
- "-ObjC",
- "-lc++",
- );
- PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
- PRODUCT_NAME = HelloWorld;
- VERSIONING_SYSTEM = "apple-generic";
- };
- name = Debug;
- };
- 13B07F951A680F5B00A75B9A /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- CURRENT_PROJECT_VERSION = 1;
- INFOPLIST_FILE = HelloWorld/Info.plist;
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
- OTHER_LDFLAGS = (
- "$(inherited)",
- "-ObjC",
- "-lc++",
- );
- PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
- PRODUCT_NAME = HelloWorld;
- VERSIONING_SYSTEM = "apple-generic";
- };
- name = Release;
- };
- 2D02E4971E0B4A5E006451C7 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
- ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- DEBUG_INFORMATION_FORMAT = dwarf;
- ENABLE_TESTABILITY = YES;
- GCC_NO_COMMON_BLOCKS = YES;
- INFOPLIST_FILE = "HelloWorld-tvOS/Info.plist";
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
- OTHER_LDFLAGS = (
- "-ObjC",
- "-lc++",
- );
- PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.HelloWorld-tvOS";
- PRODUCT_NAME = "$(TARGET_NAME)";
- SDKROOT = appletvos;
- TARGETED_DEVICE_FAMILY = 3;
- TVOS_DEPLOYMENT_TARGET = 9.2;
- };
- name = Debug;
- };
- 2D02E4981E0B4A5E006451C7 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
- ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- COPY_PHASE_STRIP = NO;
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- GCC_NO_COMMON_BLOCKS = YES;
- INFOPLIST_FILE = "HelloWorld-tvOS/Info.plist";
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
- OTHER_LDFLAGS = (
- "-ObjC",
- "-lc++",
- );
- PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.HelloWorld-tvOS";
- PRODUCT_NAME = "$(TARGET_NAME)";
- SDKROOT = appletvos;
- TARGETED_DEVICE_FAMILY = 3;
- TVOS_DEPLOYMENT_TARGET = 9.2;
- };
- name = Release;
- };
- 2D02E4991E0B4A5E006451C7 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- BUNDLE_LOADER = "$(TEST_HOST)";
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- DEBUG_INFORMATION_FORMAT = dwarf;
- ENABLE_TESTABILITY = YES;
- GCC_NO_COMMON_BLOCKS = YES;
- INFOPLIST_FILE = "HelloWorld-tvOSTests/Info.plist";
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
- OTHER_LDFLAGS = (
- "-ObjC",
- "-lc++",
- );
- PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.HelloWorld-tvOSTests";
- PRODUCT_NAME = "$(TARGET_NAME)";
- SDKROOT = appletvos;
- TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HelloWorld-tvOS.app/HelloWorld-tvOS";
- TVOS_DEPLOYMENT_TARGET = 10.1;
- };
- name = Debug;
- };
- 2D02E49A1E0B4A5E006451C7 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- BUNDLE_LOADER = "$(TEST_HOST)";
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- COPY_PHASE_STRIP = NO;
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- GCC_NO_COMMON_BLOCKS = YES;
- INFOPLIST_FILE = "HelloWorld-tvOSTests/Info.plist";
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
- OTHER_LDFLAGS = (
- "-ObjC",
- "-lc++",
- );
- PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.HelloWorld-tvOSTests";
- PRODUCT_NAME = "$(TARGET_NAME)";
- SDKROOT = appletvos;
- TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HelloWorld-tvOS.app/HelloWorld-tvOS";
- TVOS_DEPLOYMENT_TARGET = 10.1;
- };
- name = Release;
- };
- 83CBBA201A601CBA00E9B192 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
- CLANG_CXX_LIBRARY = "libc++";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_COMMA = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
- CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
- CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
- CLANG_WARN_STRICT_PROTOTYPES = YES;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
- COPY_PHASE_STRIP = NO;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- ENABLE_TESTABILITY = YES;
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_NO_COMMON_BLOCKS = YES;
- GCC_OPTIMIZATION_LEVEL = 0;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
- "$(inherited)",
- );
- GCC_SYMBOLS_PRIVATE_EXTERN = NO;
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 9.0;
- MTL_ENABLE_DEBUG_INFO = YES;
- ONLY_ACTIVE_ARCH = YES;
- SDKROOT = iphoneos;
- };
- name = Debug;
- };
- 83CBBA211A601CBA00E9B192 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
- CLANG_CXX_LIBRARY = "libc++";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_COMMA = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
- CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
- CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
- CLANG_WARN_STRICT_PROTOTYPES = YES;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
- COPY_PHASE_STRIP = YES;
- ENABLE_NS_ASSERTIONS = NO;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_NO_COMMON_BLOCKS = YES;
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 9.0;
- MTL_ENABLE_DEBUG_INFO = NO;
- SDKROOT = iphoneos;
- VALIDATE_PRODUCT = YES;
- };
- name = Release;
- };
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
- 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "HelloWorldTests" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 00E356F61AD99517003FC87E /* Debug */,
- 00E356F71AD99517003FC87E /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "HelloWorld" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 13B07F941A680F5B00A75B9A /* Debug */,
- 13B07F951A680F5B00A75B9A /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "HelloWorld-tvOS" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 2D02E4971E0B4A5E006451C7 /* Debug */,
- 2D02E4981E0B4A5E006451C7 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "HelloWorld-tvOSTests" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 2D02E4991E0B4A5E006451C7 /* Debug */,
- 2D02E49A1E0B4A5E006451C7 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "HelloWorld" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 83CBBA201A601CBA00E9B192 /* Debug */,
- 83CBBA211A601CBA00E9B192 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
-/* End XCConfigurationList section */
- };
- rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
-}

local-cli/templates/HelloWorld/ios/HelloWorld.xcodeproj/xcshareddata/xcschemes/HelloWorld-tvOS.xcscheme

@@ -1,129 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
- LastUpgradeVersion = "0940"
- version = "1.3">
- <BuildAction
- parallelizeBuildables = "NO"
- buildImplicitDependencies = "YES">
- <BuildActionEntries>
- <BuildActionEntry
- buildForTesting = "YES"
- buildForRunning = "YES"
- buildForProfiling = "YES"
- buildForArchiving = "YES"
- buildForAnalyzing = "YES">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "2D2A28121D9B038B00D4039D"
- BuildableName = "libReact.a"
- BlueprintName = "React-tvOS"
- ReferencedContainer = "container:../node_modules/react-native/React/React.xcodeproj">
- </BuildableReference>
- </BuildActionEntry>
- <BuildActionEntry
- buildForTesting = "YES"
- buildForRunning = "YES"
- buildForProfiling = "YES"
- buildForArchiving = "YES"
- buildForAnalyzing = "YES">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
- BuildableName = "HelloWorld-tvOS.app"
- BlueprintName = "HelloWorld-tvOS"
- ReferencedContainer = "container:HelloWorld.xcodeproj">
- </BuildableReference>
- </BuildActionEntry>
- <BuildActionEntry
- buildForTesting = "YES"
- buildForRunning = "YES"
- buildForProfiling = "NO"
- buildForArchiving = "NO"
- buildForAnalyzing = "YES">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "2D02E48F1E0B4A5D006451C7"
- BuildableName = "HelloWorld-tvOSTests.xctest"
- BlueprintName = "HelloWorld-tvOSTests"
- ReferencedContainer = "container:HelloWorld.xcodeproj">
- </BuildableReference>
- </BuildActionEntry>
- </BuildActionEntries>
- </BuildAction>
- <TestAction
- buildConfiguration = "Debug"
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- shouldUseLaunchSchemeArgsEnv = "YES">
- <Testables>
- <TestableReference
- skipped = "NO">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "2D02E48F1E0B4A5D006451C7"
- BuildableName = "HelloWorld-tvOSTests.xctest"
- BlueprintName = "HelloWorld-tvOSTests"
- ReferencedContainer = "container:HelloWorld.xcodeproj">
- </BuildableReference>
- </TestableReference>
- </Testables>
- <MacroExpansion>
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
- BuildableName = "HelloWorld-tvOS.app"
- BlueprintName = "HelloWorld-tvOS"
- ReferencedContainer = "container:HelloWorld.xcodeproj">
- </BuildableReference>
- </MacroExpansion>
- <AdditionalOptions>
- </AdditionalOptions>
- </TestAction>
- <LaunchAction
- buildConfiguration = "Debug"
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- launchStyle = "0"
- useCustomWorkingDirectory = "NO"
- ignoresPersistentStateOnLaunch = "NO"
- debugDocumentVersioning = "YES"
- debugServiceExtension = "internal"
- allowLocationSimulation = "YES">
- <BuildableProductRunnable
- runnableDebuggingMode = "0">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
- BuildableName = "HelloWorld-tvOS.app"
- BlueprintName = "HelloWorld-tvOS"
- ReferencedContainer = "container:HelloWorld.xcodeproj">
- </BuildableReference>
- </BuildableProductRunnable>
- <AdditionalOptions>
- </AdditionalOptions>
- </LaunchAction>
- <ProfileAction
- buildConfiguration = "Release"
- shouldUseLaunchSchemeArgsEnv = "YES"
- savedToolIdentifier = ""
- useCustomWorkingDirectory = "NO"
- debugDocumentVersioning = "YES">
- <BuildableProductRunnable
- runnableDebuggingMode = "0">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
- BuildableName = "HelloWorld-tvOS.app"
- BlueprintName = "HelloWorld-tvOS"
- ReferencedContainer = "container:HelloWorld.xcodeproj">
- </BuildableReference>
- </BuildableProductRunnable>
- </ProfileAction>
- <AnalyzeAction
- buildConfiguration = "Debug">
- </AnalyzeAction>
- <ArchiveAction
- buildConfiguration = "Release"
- revealArchiveInOrganizer = "YES">
- </ArchiveAction>
-</Scheme>

local-cli/templates/HelloWorld/ios/HelloWorld.xcodeproj/xcshareddata/xcschemes/HelloWorld.xcscheme

@@ -1,129 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
- LastUpgradeVersion = "0940"
- version = "1.3">
- <BuildAction
- parallelizeBuildables = "NO"
- buildImplicitDependencies = "YES">
- <BuildActionEntries>
- <BuildActionEntry
- buildForTesting = "YES"
- buildForRunning = "YES"
- buildForProfiling = "YES"
- buildForArchiving = "YES"
- buildForAnalyzing = "YES">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "83CBBA2D1A601D0E00E9B192"
- BuildableName = "libReact.a"
- BlueprintName = "React"
- ReferencedContainer = "container:../node_modules/react-native/React/React.xcodeproj">
- </BuildableReference>
- </BuildActionEntry>
- <BuildActionEntry
- buildForTesting = "YES"
- buildForRunning = "YES"
- buildForProfiling = "YES"
- buildForArchiving = "YES"
- buildForAnalyzing = "YES">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
- BuildableName = "HelloWorld.app"
- BlueprintName = "HelloWorld"
- ReferencedContainer = "container:HelloWorld.xcodeproj">
- </BuildableReference>
- </BuildActionEntry>
- <BuildActionEntry
- buildForTesting = "YES"
- buildForRunning = "YES"
- buildForProfiling = "NO"
- buildForArchiving = "NO"
- buildForAnalyzing = "YES">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "00E356ED1AD99517003FC87E"
- BuildableName = "HelloWorldTests.xctest"
- BlueprintName = "HelloWorldTests"
- ReferencedContainer = "container:HelloWorld.xcodeproj">
- </BuildableReference>
- </BuildActionEntry>
- </BuildActionEntries>
- </BuildAction>
- <TestAction
- buildConfiguration = "Debug"
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- shouldUseLaunchSchemeArgsEnv = "YES">
- <Testables>
- <TestableReference
- skipped = "NO">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "00E356ED1AD99517003FC87E"
- BuildableName = "HelloWorldTests.xctest"
- BlueprintName = "HelloWorldTests"
- ReferencedContainer = "container:HelloWorld.xcodeproj">
- </BuildableReference>
- </TestableReference>
- </Testables>
- <MacroExpansion>
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
- BuildableName = "HelloWorld.app"
- BlueprintName = "HelloWorld"
- ReferencedContainer = "container:HelloWorld.xcodeproj">
- </BuildableReference>
- </MacroExpansion>
- <AdditionalOptions>
- </AdditionalOptions>
- </TestAction>
- <LaunchAction
- buildConfiguration = "Debug"
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- launchStyle = "0"
- useCustomWorkingDirectory = "NO"
- ignoresPersistentStateOnLaunch = "NO"
- debugDocumentVersioning = "YES"
- debugServiceExtension = "internal"
- allowLocationSimulation = "YES">
- <BuildableProductRunnable
- runnableDebuggingMode = "0">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
- BuildableName = "HelloWorld.app"
- BlueprintName = "HelloWorld"
- ReferencedContainer = "container:HelloWorld.xcodeproj">
- </BuildableReference>
- </BuildableProductRunnable>
- <AdditionalOptions>
- </AdditionalOptions>
- </LaunchAction>
- <ProfileAction
- buildConfiguration = "Release"
- shouldUseLaunchSchemeArgsEnv = "YES"
- savedToolIdentifier = ""
- useCustomWorkingDirectory = "NO"
- debugDocumentVersioning = "YES">
- <BuildableProductRunnable
- runnableDebuggingMode = "0">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
- BuildableName = "HelloWorld.app"
- BlueprintName = "HelloWorld"
- ReferencedContainer = "container:HelloWorld.xcodeproj">
- </BuildableReference>
- </BuildableProductRunnable>
- </ProfileAction>
- <AnalyzeAction
- buildConfiguration = "Debug">
- </AnalyzeAction>
- <ArchiveAction
- buildConfiguration = "Release"
- revealArchiveInOrganizer = "YES">
- </ArchiveAction>
-</Scheme>

local-cli/templates/HelloWorld/_watchmanconfig

@@ -1 +0,0 @@
-{}
\ No newline at end of file

local-cli/templates/README.md

@@ -1,48 +0,0 @@
-# App templates
-
-This folder contains basic app templates. These get expanded by 'react-native init' when creating a new app to make it easier for anyone to get started.
-
-# Chat Example
-
-This is an example React Native app demonstrates ListViews, text input and
-navigation between a few screens.
-
-<img width="487" alt="screenshot 2017-01-13 17 24 37" src="https://cloud.githubusercontent.com/assets/346214/21950983/54d75cb4-d9b5-11e6-9d63-bd7edf51f4d4.png">
-<img width="487" alt="screenshot 2017-01-13 17 24 40" src="https://cloud.githubusercontent.com/assets/346214/21950982/54d6797a-d9b5-11e6-829f-3e0f15dab0c1.png">
-
-## Purpose
-
-One problem with React Native is that it is not trivial to get started: `react-native init` creates a very simple app that renders some text. Everyone then has to figure out how to do very basic things such as adding a list of items fetched from a server, navigating to a screen when a list item is tapped, or handling text input.
-
-This app is a template used by `react-native init` so it is easier for anyone to get up and running quickly by having an app with a few screens, a `ListView` and a `TextInput` that works well with the software keyboard.
-
-## Best practices
-
-Another purpose of this app is to define best practices such as:
-- The folder structure of a standalone React Native app
-- A style guide for JavaScript and React - for this we use the [AirBnb style guide](https://github.com/airbnb/javascript)
-- Naming conventions
-
-We need your feedback to settle on a good set of best practices. Have you built React Native apps? If so, please use the issues in the repo [mkonicek/ChatExample](https://github.com/mkonicek/ChatExample) to discuss what you think are the best practices that this example should be using.
-
-## Running the app locally
-
-```
-cd ChatExample
-yarn
-react-native run-ios
-react-native run-android
-```
-
-(In case you want to use react-navigation master):
-
-```
-# Install dependencies:
-cd react-navigation
-yarn
-yarn pack --filename react-navigation-1.0.0-alpha.tgz
-cd ChatExample
-yarn
-yarn add ~/code/react-navigation/react-navigation-1.0.0-alpha.tgz
-```

local-cli/upgrade/upgrade.js

@@ -1,174 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const chalk = require('chalk');
-const copyProjectTemplateAndReplace = require('../generator/copyProjectTemplateAndReplace');
-const fs = require('fs');
-const path = require('path');
-const printRunInstructions = require('../generator/printRunInstructions');
-const semver = require('semver');
-const yarn = require('../util/yarn');
-
-/**
- * Migrate application to a new version of React Native.
- * See http://facebook.github.io/react-native/docs/upgrading.html
- *
- * IMPORTANT: Assumes the cwd() is the project directory.
- * The code here must only be invoked via the CLI:
- * $ cd MyAwesomeApp
- * $ react-native upgrade
- */
-function validateAndUpgrade() {
- const projectDir = process.cwd();
-
- const packageJSON = JSON.parse(
- fs.readFileSync(path.resolve(projectDir, 'package.json'), 'utf8'),
- );
-
- warn(
- 'You should consider using the new upgrade tool based on Git. It ' +
- 'makes upgrades easier by resolving most conflicts automatically.\n' +
- 'To use it:\n' +
- '- Go back to the old version of React Native\n' +
- '- Run "npm install -g react-native-git-upgrade"\n' +
- '- Run "react-native-git-upgrade"\n' +
- 'See https://facebook.github.io/react-native/docs/upgrading.html',
- );
-
- const projectName = packageJSON.name;
- if (!projectName) {
- warn(
- 'Your project needs to have a name, declared in package.json, ' +
- 'such as "name": "AwesomeApp". Please add a project name. Aborting.',
- );
- return;
- }
-
- const version = packageJSON.dependencies['react-native'];
- if (!version) {
- warn(
- 'Your "package.json" file doesn\'t seem to declare "react-native" as ' +
- 'a dependency. Nothing to upgrade. Aborting.',
- );
- return;
- }
-
- if (version === 'latest' || version === '*') {
- warn(
- 'Some major releases introduce breaking changes.\n' +
- 'Please use a caret version number in your "package.json" file \n' +
- 'to avoid breakage. Use e.g. react-native: ^0.38.0. Aborting.',
- );
- return;
- }
-
- const installed = JSON.parse(
- fs.readFileSync(
- path.resolve(projectDir, 'node_modules/react-native/package.json'),
- 'utf8',
- ),
- );
-
- if (!semver.satisfies(installed.version, version)) {
- warn(
- 'react-native version in "package.json" doesn\'t match ' +
- 'the installed version in "node_modules".\n' +
- 'Try running "npm install" to fix this. Aborting.',
- );
- return;
- }
-
- const v = version.replace(/^(~|\^|=)/, '').replace(/x/i, '0');
-
- if (!semver.valid(v)) {
- warn(
- "A valid version number for 'react-native' is not specified in your " +
- "'package.json' file. Aborting.",
- );
- return;
- }
-
- console.log(
- 'Upgrading project to react-native v' +
- installed.version +
- '\n' +
- 'Check out the release notes and breaking changes: ' +
- 'https://github.com/facebook/react-native/releases/tag/v' +
- semver.major(v) +
- '.' +
- semver.minor(v) +
- '.0',
- );
-
- // >= v0.21.0, we require react to be a peer dependency
- if (semver.gte(v, '0.21.0') && !packageJSON.dependencies.react) {
- warn(
- 'Your "package.json" file doesn\'t seem to have "react" as a dependency.\n' +
- '"react" was changed from a dependency to a peer dependency in react-native v0.21.0.\n' +
- 'Therefore, it\'s necessary to include "react" in your project\'s dependencies.\n' +
- 'Please run "npm install --save react", then re-run "react-native upgrade".\n',
- );
- return;
- }
-
- if (semver.satisfies(v, '~0.26.0')) {
- warn(
- 'React Native 0.26 introduced some breaking changes to the native files on iOS. You can\n' +
- 'perform them manually by checking the release notes or use "rnpm" ' +
- 'to do it automatically.\n' +
- 'Just run:\n' +
- '"npm install -g rnpm && npm install rnpm-plugin-upgrade@0.26 --save-dev", ' +
- 'then run "rnpm upgrade".',
- );
- }
-
- return new Promise(resolve => {
- upgradeProjectFiles(projectDir, projectName);
- console.log(
- 'Successfully upgraded this project to react-native v' +
- installed.version,
- );
- resolve();
- });
-}
-
-/**
- * Once all checks passed, upgrade the project files.
- */
-function upgradeProjectFiles(projectDir, projectName) {
- // Just owerwrite
- copyProjectTemplateAndReplace(
- path.resolve(
- 'node_modules',
- 'react-native',
- 'local-cli',
- 'templates',
- 'HelloWorld',
- ),
- projectDir,
- projectName,
- {upgrade: true},
- );
-}
-
-function warn(message) {
- console.warn(chalk.yellow(message));
-}
-
-const upgradeCommand = {
- name: 'upgrade',
- description:
- "upgrade your app's template files to the latest version; run this after " +
- 'updating the react-native version in your package.json and running npm install',
- func: validateAndUpgrade,
-};
-
-module.exports = upgradeCommand;

local-cli/util/assertRequiredOptions.js

@@ -1,33 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const {Option} = require('commander');
-const {camelCase} = require('lodash');
-
-// Commander.js has a 2 years old open issue to support <...> syntax
-// for options. Until that gets merged, we run the checks manually
-// https://github.com/tj/commander.js/issues/230
-module.exports = function assertRequiredOptions(options, passedOptions) {
- options.forEach(opt => {
- const option = new Option(opt.command);
-
- if (!option.required) {
- return;
- }
-
- const name = camelCase(option.long);
-
- if (!passedOptions[name]) {
- // Provide commander.js like error message
- throw new Error(`error: option '${option.long}' missing`);
- }
- });
-};

local-cli/util/Config.js

@@ -1,100 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow
- */
-'use strict';
-
-const findSymlinkedModules = require('./findSymlinkedModules');
-const getPolyfills = require('../../rn-get-polyfills');
-const path = require('path');
-
-const {createBlacklist} = require('metro');
-/* $FlowFixMe(site=react_native_oss) */
-const {loadConfig} = require('metro-config');
-
-/**
- * Configuration file of the CLI.
- */
-/* $FlowFixMe(site=react_native_oss) */
-import type {ConfigT} from 'metro-config/src/configTypes.flow';
-
-function getProjectRoot() {
- if (
- __dirname.match(/node_modules[\/\\]react-native[\/\\]local-cli[\/\\]util$/)
- ) {
- // Packager is running from node_modules.
- // This is the default case for all projects created using 'react-native init'.
- return path.resolve(__dirname, '../../../..');
- } else if (__dirname.match(/Pods[\/\\]React[\/\\]packager$/)) {
- // React Native was installed using CocoaPods.
- return path.resolve(__dirname, '../../../..');
- }
- return path.resolve(__dirname, '../..');
-}
-
-const resolveSymlinksForRoots = roots =>
- roots.reduce(
- /* $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. */
- (arr, rootPath) => arr.concat(findSymlinkedModules(rootPath, roots)),
- [...roots],
- );
-
-const getWatchFolders = () => {
- const root = process.env.REACT_NATIVE_APP_ROOT;
- if (root) {
- return resolveSymlinksForRoots([path.resolve(root)]);
- }
- return [];
-};
-
-const getBlacklistRE = () => {
- return createBlacklist([/.*\/__fixtures__\/.*/]);
-};
-
-/**
- * Module capable of getting the configuration out of a given file.
- *
- * The function will return all the default configuration, as specified by the
- * `DEFAULT` param overriden by those found on `rn-cli.config.js` files, if any. If no
- * default config is provided and no configuration can be found in the directory
- * hierarchy, an error will be thrown.
- */
-const Config = {
- DEFAULT: {
- resolver: {
- resolverMainFields: ['react-native', 'browser', 'main'],
- blacklistRE: getBlacklistRE(),
- },
- serializer: {
- getModulesRunBeforeMainModule: () => [
- require.resolve('../../Libraries/Core/InitializeCore'),
- ],
- getPolyfills,
- },
- server: {
- port: process.env.RCT_METRO_PORT || 8081,
- },
- transformer: {
- babelTransformerPath: require.resolve('metro/src/reactNativeTransformer'),
- },
- watchFolders: getWatchFolders(),
- },
-
- async load(configFile: ?string): Promise<ConfigT> {
- const argv = {cwd: getProjectRoot()};
-
- return await loadConfig(
- configFile ? {...argv, config: configFile} : argv,
- this.DEFAULT,
- );
- },
-};
-
-module.exports = Config;

local-cli/util/copyAndReplace.js

@@ -1,140 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const fs = require('fs');
-const path = require('path');
-
-// Binary files, don't process these (avoid decoding as utf8)
-const binaryExtensions = ['.png', '.jar'];
-
-/**
- * Copy a file to given destination, replacing parts of its contents.
- * @param srcPath Path to a file to be copied.
- * @param destPath Destination path.
- * @param replacements: e.g. {'TextToBeReplaced': 'Replacement'}
- * @param contentChangedCallback
- * Used when upgrading projects. Based on if file contents would change
- * when being replaced, allows the caller to specify whether the file
- * should be replaced or not.
- * If null, files will be overwritten.
- * Function(path, 'identical' | 'changed' | 'new') => 'keep' | 'overwrite'
- */
-function copyAndReplace(
- srcPath,
- destPath,
- replacements,
- contentChangedCallback,
-) {
- if (fs.lstatSync(srcPath).isDirectory()) {
- if (!fs.existsSync(destPath)) {
- fs.mkdirSync(destPath);
- }
- // Not recursive
- return;
- }
-
- const extension = path.extname(srcPath);
- if (binaryExtensions.indexOf(extension) !== -1) {
- // Binary file
- let shouldOverwrite = 'overwrite';
- if (contentChangedCallback) {
- const newContentBuffer = fs.readFileSync(srcPath);
- let contentChanged = 'identical';
- try {
- const origContentBuffer = fs.readFileSync(destPath);
- if (Buffer.compare(origContentBuffer, newContentBuffer) !== 0) {
- contentChanged = 'changed';
- }
- } catch (err) {
- if (err.code === 'ENOENT') {
- contentChanged = 'new';
- } else {
- throw err;
- }
- }
- shouldOverwrite = contentChangedCallback(destPath, contentChanged);
- }
- if (shouldOverwrite === 'overwrite') {
- copyBinaryFile(srcPath, destPath, err => {
- if (err) {
- throw err;
- }
- });
- }
- } else {
- // Text file
- const srcPermissions = fs.statSync(srcPath).mode;
- let content = fs.readFileSync(srcPath, 'utf8');
- Object.keys(replacements).forEach(
- regex =>
- (content = content.replace(
- new RegExp(regex, 'g'),
- replacements[regex],
- )),
- );
-
- let shouldOverwrite = 'overwrite';
- if (contentChangedCallback) {
- // Check if contents changed and ask to overwrite
- let contentChanged = 'identical';
- try {
- const origContent = fs.readFileSync(destPath, 'utf8');
- if (content !== origContent) {
- //console.log('Content changed: ' + destPath);
- contentChanged = 'changed';
- }
- } catch (err) {
- if (err.code === 'ENOENT') {
- contentChanged = 'new';
- } else {
- throw err;
- }
- }
- shouldOverwrite = contentChangedCallback(destPath, contentChanged);
- }
- if (shouldOverwrite === 'overwrite') {
- fs.writeFileSync(destPath, content, {
- encoding: 'utf8',
- mode: srcPermissions,
- });
- }
- }
-}
-
-/**
- * Same as 'cp' on Unix. Don't do any replacements.
- */
-function copyBinaryFile(srcPath, destPath, cb) {
- let cbCalled = false;
- const srcPermissions = fs.statSync(srcPath).mode;
- const readStream = fs.createReadStream(srcPath);
- readStream.on('error', function(err) {
- done(err);
- });
- const writeStream = fs.createWriteStream(destPath, {
- mode: srcPermissions,
- });
- writeStream.on('error', function(err) {
- done(err);
- });
- writeStream.on('close', function(ex) {
- done();
- });
- readStream.pipe(writeStream);
- function done(err) {
- if (!cbCalled) {
- cb(err);
- cbCalled = true;
- }
- }
-}
-
-module.exports = copyAndReplace;

local-cli/util/findReactNativeScripts.js

@@ -1,28 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow strict
- */
-
-'use strict';
-
-const path = require('path');
-const fs = require('fs');
-
-function findReactNativeScripts(): ?string {
- const executablePath = path.resolve(
- 'node_modules',
- '.bin',
- 'react-native-scripts',
- );
- if (fs.existsSync(executablePath)) {
- return executablePath;
- }
- return null;
-}
-
-module.exports = findReactNativeScripts;

local-cli/util/findSymlinkedModules.js

@@ -1,108 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow strict
- */
-
-const path = require('path');
-const fs = require('fs');
-
-/**
- * Find symlinked modules inside "node_modules."
- *
- * Naively, we could just perform a depth-first search of all folders in
- * node_modules, recursing when we find a symlink.
- *
- * We can be smarter than this due to our knowledge of how npm/Yarn lays out
- * "node_modules" / how tools that build on top of npm/Yarn (such as Lerna)
- * install dependencies.
- *
- * Starting from a given root node_modules folder, this algorithm will look at
- * both the top level descendants of the node_modules folder or second level
- * descendants of folders that start with "@" (which indicates a scoped
- * package). If any of those folders is a symlink, it will recurse into the
- * link, and perform the same search in the linked folder.
- *
- * The end result should be a list of all resolved module symlinks for a given
- * root.
- */
-module.exports = function findSymlinkedModules(
- projectRoot: string,
- ignoredRoots?: Array<string> = [],
-) {
- const timeStart = Date.now();
- const nodeModuleRoot = path.join(projectRoot, 'node_modules');
- const resolvedSymlinks = findModuleSymlinks(nodeModuleRoot, [
- ...ignoredRoots,
- projectRoot,
- ]);
- const timeEnd = Date.now();
-
- console.log(
- `Scanning folders for symlinks in ${nodeModuleRoot} (${timeEnd -
- timeStart}ms)`,
- );
-
- return resolvedSymlinks;
-};
-
-function findModuleSymlinks(
- modulesPath: string,
- ignoredPaths: Array<string> = [],
-): Array<string> {
- if (!fs.existsSync(modulesPath)) {
- return [];
- }
-
- // Find module symlinks
- const moduleFolders = fs.readdirSync(modulesPath);
- const symlinks = moduleFolders.reduce((links, folderName) => {
- const folderPath = path.join(modulesPath, folderName);
- const maybeSymlinkPaths = [];
- if (folderName.startsWith('@')) {
- const scopedModuleFolders = fs.readdirSync(folderPath);
- maybeSymlinkPaths.push(
- ...scopedModuleFolders.map(name => path.join(folderPath, name)),
- );
- } else {
- maybeSymlinkPaths.push(folderPath);
- }
- return links.concat(resolveSymlinkPaths(maybeSymlinkPaths, ignoredPaths));
- }, []);
-
- // For any symlinks found, look in _that_ modules node_modules directory
- // and find any symlinked modules
- const nestedSymlinks = symlinks.reduce(
- (links, symlinkPath) =>
- links.concat(
- // We ignore any found symlinks or anything from the ignored list,
- // to prevent infinite recursion
- findModuleSymlinks(path.join(symlinkPath, 'node_modules'), [
- ...ignoredPaths,
- ...symlinks,
- ]),
- ),
- [],
- );
-
- return [...new Set([...symlinks, ...nestedSymlinks])];
-}
-
-function resolveSymlinkPaths(maybeSymlinkPaths, ignoredPaths) {
- return maybeSymlinkPaths.reduce((links, maybeSymlinkPath) => {
- if (fs.lstatSync(maybeSymlinkPath).isSymbolicLink()) {
- const resolved = path.resolve(
- path.dirname(maybeSymlinkPath),
- fs.readlinkSync(maybeSymlinkPath),
- );
- if (ignoredPaths.indexOf(resolved) === -1 && fs.existsSync(resolved)) {
- links.push(resolved);
- }
- }
- return links;
- }, []);
-}

local-cli/util/findSymlinksPaths.js

@@ -1,60 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const path = require('path');
-const fs = require('fs');
-
-/**
- * Find and resolve symlinks in `lookupFolder`.
- * Ignore any descendants of the paths in `ignoredRoots`.
- */
-module.exports = function findSymlinksPaths(lookupFolder, ignoredRoots) {
- const timeStart = Date.now();
- const folders = fs.readdirSync(lookupFolder);
-
- const resolvedSymlinks = [];
- folders.forEach(folder => {
- const visited = [];
-
- let symlink = path.resolve(lookupFolder, folder);
- while (fs.lstatSync(symlink).isSymbolicLink()) {
- const index = visited.indexOf(symlink);
- if (index !== -1) {
- throw Error(
- 'Infinite symlink recursion detected:\n ' +
- visited.slice(index).join('\n '),
- );
- }
-
- visited.push(symlink);
- symlink = path.resolve(path.dirname(symlink), fs.readlinkSync(symlink));
- }
-
- if (visited.length && !rootExists(ignoredRoots, symlink)) {
- resolvedSymlinks.push(symlink);
- }
- });
-
- const timeEnd = Date.now();
- console.log(
- `Scanning ${
- folders.length
- } folders for symlinks in ${lookupFolder} (${timeEnd - timeStart}ms)`,
- );
-
- return resolvedSymlinks;
-};
-
-function rootExists(roots, child) {
- return roots.some(root => isDescendant(root, child));
-}
-
-function isDescendant(root, child) {
- return root === child || child.startsWith(root + path.sep);
-}

local-cli/util/isPackagerRunning.js

@@ -1,36 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const fetch = require('node-fetch');
-
-/**
- * Indicates whether or not the packager is running. It returns a promise that
- * when fulfilled can returns one out of these possible values:
- * - `running`: the packager is running
- * - `not_running`: the packager nor any process is running on the expected
- * port.
- * - `unrecognized`: one other process is running on the port we expect the
- * packager to be running.
- */
-function isPackagerRunning(packagerPort = process.env.RCT_METRO_PORT || 8081) {
- return fetch(`http://localhost:${packagerPort}/status`).then(
- res =>
- res
- .text()
- .then(
- body =>
- body === 'packager-status:running' ? 'running' : 'unrecognized',
- ),
- () => 'not_running',
- );
-}
-
-module.exports = isPackagerRunning;

local-cli/util/isValidPackageName.js

@@ -1,16 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-function isValidPackageName(name) {
- return name.match(/^[$A-Z_][0-9A-Z_$]*$/i);
-}
-
-module.exports = isValidPackageName;

local-cli/util/log.js

@@ -1,30 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-var _enabled = true;
-
-function disable() {
- _enabled = false;
-}
-
-function log(stream, module) {
- return function() {
- if (!_enabled) {
- return;
- }
- const message = Array.prototype.slice.call(arguments).join(' ');
- stream.write(module + ': ' + message + '\n');
- };
-}
-
-module.exports.out = log.bind(null, process.stdout);
-module.exports.err = log.bind(null, process.stderr);
-module.exports.disable = disable;

local-cli/util/__mocks__/log.js

@@ -1,13 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-module.exports.out = () => jest.fn();
-module.exports.err = () => jest.fn();

local-cli/util/PackageManager.js

@@ -1,74 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const spawnSync = require('child_process').spawnSync;
-const yarn = require('../util/yarn');
-const spawnOpts = {
- stdio: 'inherit',
- stdin: 'inherit',
-};
-
-/**
- * Execute npm or yarn command
- *
- * @param {String} yarnCommand Yarn command to be executed eg. yarn add package
- * @param {String} npmCommand Npm command to be executed eg. npm install package
- * @return {object} spawnSync's result object
- */
-function callYarnOrNpm(yarnCommand, npmCommand) {
- let command;
-
- const projectDir = process.cwd();
- const isYarnAvailable =
- yarn.getYarnVersionIfAvailable() && yarn.isGlobalCliUsingYarn(projectDir);
-
- if (isYarnAvailable) {
- command = yarnCommand;
- } else {
- command = npmCommand;
- }
-
- const args = command.split(' ');
- const cmd = args.shift();
-
- const res = spawnSync(cmd, args, spawnOpts);
-
- return res;
-}
-
-/**
- * Install package into project using npm or yarn if available
- * @param {[type]} packageName Package to be installed
- * @return {[type]} spawnSync's result object
- */
-function add(packageName) {
- return callYarnOrNpm(
- `yarn add ${packageName}`,
- `npm install ${packageName} --save`,
- );
-}
-
-/**
- * Uninstall package from project using npm or yarn if available
- * @param {[type]} packageName Package to be uninstalled
- * @return {Object} spawnSync's result object
- */
-function remove(packageName) {
- return callYarnOrNpm(
- `yarn remove ${packageName}`,
- `npm uninstall --save ${packageName}`,
- );
-}
-
-module.exports = {
- add: add,
- remove: remove,
-};

local-cli/util/parseCommandLine.js

@@ -1,81 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * Wrapper on-top of `optimist` in order to properly support boolean flags
- * and have a slightly less awkward API.
- *
- * Usage example:
- * var argv = parseCommandLine([{
- * command: 'web',
- * description: 'Run in a web browser instead of iOS',
- * default: true
- * }])
- *
- * NOTE: This file is used internally at Facebook and not in `local-cli` itself.
- * No changes should be made to this file without prior discussion with FB team.
- *
- * @format
- */
-
-'use strict';
-
-var optimistModule = require('optimist');
-
-function parseCommandLine(config, args) {
- var optimist = new optimistModule();
- args = args || process.argv;
- // optimist default API requires you to write the command name three time
- // This is a small wrapper to accept an object instead
- for (var i = 0; i < config.length; ++i) {
- if (config[i].type === 'string') {
- optimist.string(config[i].command);
- } else {
- optimist.boolean(config[i].command);
- }
-
- optimist
- .default(config[i].command, config[i].default)
- .describe(config[i].command, config[i].description);
-
- if (config[i].required) {
- optimist.demand(config[i].command);
- }
- }
- var argv = optimist.parse(args);
-
- // optimist doesn't have support for --dev=false, instead it returns 'false'
- for (var i = 0; i < config.length; ++i) {
- var command = config[i].command;
- if (argv[command] === undefined) {
- argv[command] = config[i].default;
- }
- if (argv[command] === 'true') {
- argv[command] = true;
- }
- if (argv[command] === 'false') {
- argv[command] = false;
- }
- if (config[i].type === 'string') {
- // According to https://github.com/substack/node-optimist#numbers,
- // every argument that looks like a number should be converted to one.
- var strValue = argv[command];
- var numValue = strValue ? Number(strValue) : undefined;
- if (typeof numValue === 'number' && !isNaN(numValue)) {
- argv[command] = numValue;
- }
- }
- }
-
- // Show --help
- if (argv.help || argv.h) {
- optimist.showHelp();
- process.exit();
- }
-
- return argv;
-}
-
-module.exports = parseCommandLine;

local-cli/util/walk.js

@@ -1,27 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const fs = require('fs');
-const path = require('path');
-
-function walk(current) {
- if (!fs.lstatSync(current).isDirectory()) {
- return [current];
- }
-
- const files = fs.readdirSync(current).map(child => {
- child = path.join(current, child);
- return walk(child);
- });
- return [].concat.apply([current], files);
-}
-
-module.exports = walk;

local-cli/util/yarn.js

@@ -1,60 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const execSync = require('child_process').execSync;
-const fs = require('fs');
-const path = require('path');
-const semver = require('semver');
-
-/**
- * Use Yarn if available, it's much faster than the npm client.
- * Return the version of yarn installed on the system, null if yarn is not available.
- */
-function getYarnVersionIfAvailable() {
- let yarnVersion;
- try {
- // execSync returns a Buffer -> convert to string
- yarnVersion = (
- execSync('yarn --version', {
- stdio: [0, 'pipe', 'ignore'],
- }).toString() || ''
- ).trim();
- } catch (error) {
- return null;
- }
- // yarn < 0.16 has a 'missing manifest' bug
- try {
- if (semver.gte(yarnVersion, '0.16.0')) {
- return yarnVersion;
- } else {
- return null;
- }
- } catch (error) {
- console.error('Cannot parse yarn version: ' + yarnVersion);
- return null;
- }
-}
-
-/**
- * Check that 'react-native init' itself used yarn to install React Native.
- * When using an old global react-native-cli@1.0.0 (or older), we don't want
- * to install React Native with npm, and React + Jest with yarn.
- * Let's be safe and not mix yarn and npm in a single project.
- * @param projectDir e.g. /Users/martin/AwesomeApp
- */
-function isGlobalCliUsingYarn(projectDir) {
- return fs.existsSync(path.join(projectDir, 'yarn.lock'));
-}
-
-module.exports = {
- getYarnVersionIfAvailable: getYarnVersionIfAvailable,
- isGlobalCliUsingYarn: isGlobalCliUsingYarn,
-};

local-cli/wrong-react-native.js

@@ -1,44 +0,0 @@
-#!/usr/bin/env node
-
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const isWindows = process.platform === 'win32';
-
-var installedGlobally;
-if (isWindows) {
- const fs = require('fs');
- const path = require('path');
- // On Windows, assume we are installed globally if we can't find a package.json above node_modules.
- installedGlobally = !fs.existsSync(
- path.join(__dirname, '../../../package.json'),
- );
-} else {
- // On non-windows, assume we are installed globally if we are called from outside of the node_mobules/.bin/react-native executable.
- var script = process.argv[1];
- installedGlobally = script.indexOf('node_modules/.bin/react-native') === -1;
-}
-
-if (installedGlobally) {
- const chalk = require('chalk');
-
- console.error(
- [
- chalk.red(
- 'Looks like you installed react-native globally, maybe you meant react-native-cli?',
- ),
- chalk.red('To fix the issue, run:'),
- 'npm uninstall -g react-native',
- 'npm install -g react-native-cli',
- ].join('\n'),
- );
- process.exit(1);
-} else {
- require('./cli').run();
-}

package.json

@@ -1,6 +1,6 @@
{
"name": "react-native",
- "version": "0.57.8",
+ "version": "0.59.4",
"description": "A framework for building native apps using React",
"license": "MIT",
"repository": {
@@ -30,10 +30,11 @@
"moduleNameMapper": {
"^React$": "<rootDir>/Libraries/react-native/React.js"
},
+ "testRegex": "/__tests__/.*-test\\.js$",
"testPathIgnorePatterns": [
- "Libraries/Renderer",
"/node_modules/",
- "local-cli/templates/",
+ "<rootDir>/template",
+ "Libraries/Renderer",
"RNTester/e2e"
],
"haste": {
@@ -68,7 +69,6 @@
"node_modules/fbjs/lib/flattenArray.js",
"node_modules/fbjs/lib/forEachObject.js",
"node_modules/fbjs/lib/isEmpty.js",
- "node_modules/fbjs/lib/nullthrows.js",
"node_modules/fbjs/lib/removeFromArray.js",
"node_modules/fbjs/lib/resolveImmediate.js",
"node_modules/fbjs/lib/someObject.js",
@@ -88,7 +88,19 @@
"denodeify",
"fbjs"
],
- "testEnvironment": "node"
+ "testEnvironment": "node",
+ "collectCoverageFrom": [
+ "Libraries/**/*.js"
+ ],
+ "coveragePathIgnorePatterns": [
+ "/__tests__/",
+ "/vendor/",
+ "<rootDir>/Libraries/react-native/"
+ ]
+ },
+ "jest-junit": {
+ "outputDirectory": "reports/junit",
+ "outputName": "js-test-results.xml"
},
"main": "Libraries/react-native/react-native-implementation.js",
"files": [
@@ -96,22 +108,20 @@
"android",
"cli.js",
"flow",
- "flow-github",
"init.sh",
+ "local-cli",
"scripts/ios-configure-glog.sh",
"scripts/ios-install-third-party.sh",
"scripts/launchPackager.bat",
"scripts/launchPackager.command",
"scripts/packager.sh",
"scripts/react-native-xcode.sh",
- "jest-preset.json",
+ "jest-preset.js",
"jest",
"lib",
"rn-get-polyfills.js",
- "setupBabel.js",
"Libraries",
"LICENSE",
- "local-cli",
"packager",
"react.gradle",
"React.podspec",
@@ -119,17 +129,20 @@
"ReactAndroid",
"ReactCommon",
"README.md",
- "third-party-podspecs"
+ "third-party-podspecs",
+ "template"
],
"scripts": {
- "start": "node ./local-cli/cli.js start",
+ "start": "node cli.js start --reactNativePath .",
"test": "jest",
- "test-ci": "JEST_JUNIT_OUTPUT=\"reports/junit/js-test-results.xml\" jest --maxWorkers=2 --ci --testResultsProcessor=\"jest-junit\"",
+ "test-ci": "jest --maxWorkers=2 --ci --reporters=\"default\" --reporters=\"jest-junit\"",
"flow": "flow",
+ "flow-check-ios": "flow check",
+ "flow-check-android": "flow check --flowconfig-name .flowconfig.android",
"lint": "eslint .",
- "prettier": "prettier \"./**/*.js\" --write",
- "docker-setup-android": "docker pull reactnativeci/android-base:latest",
- "docker-build-android-base": "docker build -t reactnativeci/android-base -f ContainerShip/Dockerfile.android-base .",
+ "prettier": "prettier --write \"./**/*.js\" \"./**/*.md\"",
+ "format-check": "prettier --list-different \"./**/*.js\" \"./**/*.md\"",
+ "docker-setup-android": "docker pull reactnativecommunity/react-native-android",
"docker-build-android": "docker build -t reactnativeci/android -f ContainerShip/Dockerfile.android .",
"test-android-run-instrumentation": "docker run --cap-add=SYS_ADMIN -it reactnativeci/android bash ContainerShip/scripts/run-android-docker-instrumentation-tests.sh",
"test-android-run-unit": "docker run --cap-add=SYS_ADMIN -it reactnativeci/android bash ContainerShip/scripts/run-android-docker-unit-tests.sh",
@@ -139,27 +152,24 @@
"test-android-unit": "yarn run docker-build-android && yarn run test-android-run-unit",
"test-android-e2e": "yarn run docker-build-android && yarn run test-android-run-e2e",
"build-ios-e2e": "detox build -c ios.sim.release",
- "test-ios-e2e": "detox test -c ios.sim.release --cleanup"
- },
- "bin": {
- "react-native": "local-cli/wrong-react-native.js"
+ "test-ios-e2e": "detox test -c ios.sim.release"
},
"peerDependencies": {
- "react": "16.6.3"
+ "react": "16.8.3"
},
"dependencies": {
"@babel/runtime": "^7.0.0",
+ "@react-native-community/cli": "^1.2.1",
"absolute-path": "^0.0.0",
"art": "^0.10.0",
"base64-js": "^1.1.2",
- "chalk": "^1.1.1",
+ "chalk": "^2.4.1",
"commander": "^2.9.0",
"compression": "^1.7.1",
"connect": "^3.6.5",
"create-react-class": "^15.6.3",
"debug": "^2.2.0",
"denodeify": "^1.2.1",
- "envinfo": "^5.7.0",
"errorhandler": "^1.5.0",
"escape-string-regexp": "^1.0.5",
"event-target-shim": "^1.0.5",
@@ -169,11 +179,10 @@
"glob": "^7.1.1",
"graceful-fs": "^4.1.3",
"inquirer": "^3.0.6",
+ "invariant": "^2.2.4",
"lodash": "^4.17.5",
- "metro": "^0.48.1",
- "metro-babel-register": "^0.48.1",
- "metro-core": "^0.48.1",
- "metro-memory-fs": "^0.48.1",
+ "metro-babel-register": "0.51.0",
+ "metro-react-native-babel-transformer": "0.51.0",
"mime": "^1.3.4",
"minimist": "^1.2.0",
"mkdirp": "^0.5.1",
@@ -181,15 +190,15 @@
"node-fetch": "^2.2.0",
"node-notifier": "^5.2.1",
"npmlog": "^2.0.4",
+ "nullthrows": "^1.1.0",
"opn": "^3.0.2",
"optimist": "^0.6.1",
"plist": "^3.0.0",
- "pretty-format": "^4.2.1",
+ "pretty-format": "24.0.0-alpha.6",
"promise": "^7.1.1",
"prop-types": "^15.5.8",
"react-clone-referenced-element": "^1.0.1",
- "react-devtools-core": "^3.4.2",
- "react-timer-mixin": "^0.13.2",
+ "react-devtools-core": "^3.6.0",
"regenerator-runtime": "^0.11.0",
"rimraf": "^2.5.4",
"semver": "^5.0.3",
@@ -197,15 +206,16 @@
"shell-quote": "1.6.1",
"stacktrace-parser": "^0.1.3",
"ws": "^1.1.5",
- "xcode": "^1.0.0",
"xmldoc": "^0.4.0",
"yargs": "^9.0.0"
},
"devDependencies": {
"@babel/core": "^7.0.0",
+ "@babel/generator": "^7.0.0",
+ "@reactions/component": "^2.0.2",
"async": "^2.4.0",
"babel-eslint": "9.0.0",
- "babel-generator": "^6.26.0",
+ "coveralls": "^3.0.2",
"detox": "9.0.4",
"eslint": "5.1.0",
"eslint-config-fb-strict": "22.1.0",
@@ -215,14 +225,16 @@
"eslint-plugin-jest": "21.8.0",
"eslint-plugin-prettier": "2.6.0",
"eslint-plugin-react": "7.8.2",
- "eslint-plugin-react-native": "^3.2.1",
- "flow-bin": "^0.78.0",
- "jest": "23.4.1",
- "jest-junit": "5.1.0",
+ "eslint-plugin-react-hooks": "^1.0.1",
+ "eslint-plugin-react-native": "3.5.0",
+ "flow-bin": "^0.92.0",
+ "jest": "24.1.0",
+ "jest-junit": "5.2.0",
+ "jscodeshift": "^0.6.2",
"prettier": "1.13.6",
- "react": "16.6.3",
- "react-native-dummy": "0.1.0",
- "react-test-renderer": "16.6.3",
+ "react": "16.8.3",
+ "react-native-dummy": "0.2.0",
+ "react-test-renderer": "16.8.3",
"shelljs": "^0.7.8"
},
"detox": {
@@ -232,7 +244,13 @@
"configurations": {
"ios.sim.release": {
"binaryPath": "RNTester/build/Build/Products/Release-iphonesimulator/RNTester.app/",
- "build": "xcodebuild -project RNTester/RNTester.xcodeproj -scheme RNTester -configuration Release -sdk iphonesimulator -derivedDataPath RNTester/build -quiet",
+ "build": "xcodebuild -project RNTester/RNTester.xcodeproj -scheme RNTester -configuration Release -sdk iphonesimulator -derivedDataPath RNTester/build -UseModernBuildSystem=NO -quiet",
+ "type": "ios.simulator",
+ "name": "iPhone 8"
+ },
+ "ios.sim.debug": {
+ "binaryPath": "RNTester/build/Build/Products/Debug-iphonesimulator/RNTester.app/",
+ "build": "xcodebuild -project RNTester/RNTester.xcodeproj -scheme RNTester -configuration Debug -sdk iphonesimulator -derivedDataPath RNTester/build -UseModernBuildSystem=NO -quiet",
"type": "ios.simulator",
"name": "iPhone 8"
}

React/Base/RCTAssert.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTAssert.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -169,13 +169,14 @@
if (stackTrace) {
[prettyStack appendString:@", stack:\n"];
- NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^(\\d+\\.js)$"
+ NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"\\b((?:seg-\\d+(?:_\\d+)?|\\d+)\\.js)"
options:NSRegularExpressionCaseInsensitive
error:NULL];
for (NSDictionary<NSString *, id> *frame in stackTrace) {
NSString *fileName = [frame[@"file"] lastPathComponent];
- if (fileName && [regex numberOfMatchesInString:fileName options:0 range:NSMakeRange(0, [fileName length])]) {
- fileName = [fileName stringByAppendingString:@":"];
+ NSTextCheckingResult *match = fileName != nil ? [regex firstMatchInString:fileName options:0 range:NSMakeRange(0, fileName.length)] : nil;
+ if (match) {
+ fileName = [NSString stringWithFormat:@"%@:", [fileName substringWithRange:match.range]];
} else {
fileName = @"";
}

React/Base/RCTBridgeDelegate.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -72,4 +72,9 @@
- (void)loadSourceForBridge:(RCTBridge *)bridge
withBlock:(RCTSourceLoadBlock)loadCallback;
+/**
+ * Retrieve the list of lazy-native-modules names for the given bridge.
+ */
+- (NSDictionary<NSString *, Class> *)extraLazyModuleClassesForBridge:(RCTBridge *)bridge;
+
@end

React/Base/RCTBridge.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -94,6 +94,13 @@
RCT_EXTERN NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass);
/**
+ * Experimental.
+ * Check/set if JSI-bound NativeModule is enabled. By default it's off.
+ */
+RCT_EXTERN BOOL RCTTurboModuleEnabled(void);
+RCT_EXTERN void RCTEnableTurboModule(BOOL enabled);
+
+/**
* Async batched bridge used to communicate with the JavaScript application.
*/
@interface RCTBridge : NSObject <RCTInvalidating>
@@ -144,11 +151,21 @@
* lazily instantiated, so calling these methods for the first time with a given
* module name/class may cause the class to be sychronously instantiated,
* potentially blocking both the calling thread and main thread for a short time.
+ *
+ * Note: This method does NOT lazily load the particular module if it's not yet loaded.
*/
- (id)moduleForName:(NSString *)moduleName;
+- (id)moduleForName:(NSString *)moduleName lazilyLoadIfNecessary:(BOOL)lazilyLoad;
+// Note: This method lazily load the module as necessary.
- (id)moduleForClass:(Class)moduleClass;
/**
+ * When a NativeModule performs a lookup for a TurboModule, we need to query
+ * the lookupDelegate.
+ */
+- (void)setRCTTurboModuleLookupDelegate:(id<RCTTurboModuleLookupDelegate>)turboModuleLookupDelegate;
+
+/**
* Convenience method for retrieving all modules conforming to a given protocol.
* Modules will be sychronously instantiated if they haven't already been,
* potentially blocking both the calling thread and main thread for a short time.
@@ -163,11 +180,6 @@
- (BOOL)moduleIsInitialized:(Class)moduleClass;
/**
- * Retrieve an extra module that gets bound to the JS context, if any.
- */
-- (id)jsBoundExtraModuleForClass:(Class)moduleClass;
-
-/**
* All registered bridge module classes.
*/
@property (nonatomic, copy, readonly) NSArray<Class> *moduleClasses;

React/Base/RCTBridge.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -44,8 +44,6 @@
return result;
}
-void RCTFBQuickPerformanceLoggerConfigureHooks(__unused JSGlobalContextRef ctx) { }
-
/**
* Register the given class as a bridge module. All modules must be registered
* prior to the first bridge initialization.
@@ -84,13 +82,17 @@
name = NSStringFromClass(cls);
}
- if ([name hasPrefix:@"RK"]) {
- name = [name substringFromIndex:2];
- } else if ([name hasPrefix:@"RCT"]) {
- name = [name substringFromIndex:3];
- }
+ return RCTDropReactPrefixes(name);
+}
+
+static BOOL turboModuleEnabled = NO;
+BOOL RCTTurboModuleEnabled(void)
+{
+ return turboModuleEnabled;
+}
- return name;
+void RCTEnableTurboModule(BOOL enabled) {
+ turboModuleEnabled = enabled;
}
#if RCT_DEBUG
@@ -128,7 +130,8 @@
break;
}
- RCTLogWarn(@"Class %@ was not exported. Did you forget to use RCT_EXPORT_MODULE()?", cls);
+ // Note: Some modules may be lazily loaded and not exported up front, so this message is no longer a warning.
+ RCTLogInfo(@"Class %@ was not exported. Did you forget to use RCT_EXPORT_MODULE()?", cls);
break;
}
superclass = class_getSuperclass(superclass);
@@ -223,6 +226,11 @@
[self invalidate];
}
+- (void)setRCTTurboModuleLookupDelegate:(id<RCTTurboModuleLookupDelegate>)turboModuleLookupDelegate
+{
+ [self.batchedBridge setRCTTurboModuleLookupDelegate:turboModuleLookupDelegate];
+}
+
- (void)didReceiveReloadCommand
{
[self reload];
@@ -238,9 +246,18 @@
return [self.batchedBridge moduleForName:moduleName];
}
+- (id)moduleForName:(NSString *)moduleName lazilyLoadIfNecessary:(BOOL)lazilyLoad
+{
+ return [self.batchedBridge moduleForName:moduleName lazilyLoadIfNecessary:lazilyLoad];
+}
+
- (id)moduleForClass:(Class)moduleClass
{
- return [self moduleForName:RCTBridgeModuleNameForClass(moduleClass)];
+ id module = [self.batchedBridge moduleForClass:moduleClass];
+ if (!module) {
+ module = [self moduleForName:RCTBridgeModuleNameForClass(moduleClass)];
+ }
+ return module;
}
- (NSArray *)modulesConformingToProtocol:(Protocol *)protocol
@@ -262,11 +279,6 @@
return [self.batchedBridge moduleIsInitialized:moduleClass];
}
-- (id)jsBoundExtraModuleForClass:(Class)moduleClass
-{
- return [self.batchedBridge jsBoundExtraModuleForClass:moduleClass];
-}
-
- (void)reload
{
#if RCT_ENABLE_INSPECTOR
@@ -280,7 +292,11 @@
* 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;
[self setUp];
});
}
@@ -354,6 +370,11 @@
}
}
+- (void)updateModuleWithInstance:(id<RCTBridgeModule>)instance
+{
+ [self.batchedBridge updateModuleWithInstance:instance];
+}
+
- (void)registerAdditionalModuleClasses:(NSArray<Class> *)modules
{
[self.batchedBridge registerAdditionalModuleClasses:modules];
@@ -382,9 +403,4 @@
[self.batchedBridge registerSegmentWithId:segmentId path:path];
}
-- (JSGlobalContextRef)jsContextRef
-{
- return [self.batchedBridge jsContextRef];
-}
-
@end

React/Base/RCTBridgeMethod.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTBridgeModule.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -74,6 +74,17 @@
+ (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
* macro takes the place of the above for those cases by omitting the +load
@@ -250,7 +261,7 @@
@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
@@ -301,7 +312,7 @@
* for the lifetime of the bridge, so it is not suitable for returning dynamic values, but may be used for long-lived
* values such as session keys, that are regenerated only as part of a reload of the entire React application.
*
- * If you implement this method and do not implement `requiresMainThreadSetup`, you will trigger deprecated logic
+ * If you implement this method and do not implement `requiresMainQueueSetup`, you will trigger deprecated logic
* that eagerly initializes your module on bridge startup. In the future, this behaviour will be changed to default
* to initializing lazily, and even modules with constants will be initialized lazily.
*/
@@ -321,3 +332,31 @@
- (void)partialBatchDidFlush;
@end
+
+/**
+ * A protocol that allows TurboModules to do lookup on other TurboModules.
+ * Calling these methods may cause a module to be synchronously instantiated.
+ */
+ @protocol RCTTurboModuleLookupDelegate <NSObject>
+ - (id)moduleForName:(const char *)moduleName;
+
+ /**
+ * Rationale:
+ * When TurboModules lookup other modules by name, we first check the TurboModule
+ * registry to see if a TurboModule exists with the respective name. In this case,
+ * we don't want a RedBox to be raised if the TurboModule isn't found.
+ *
+ * This method is deprecated and will be deleted after the migration from
+ * TurboModules to TurboModules is complete.
+ */
+ - (id)moduleForName:(const char *)moduleName warnOnLookupFailure:(BOOL)warnOnLookupFailure;
+ - (BOOL)moduleIsInitialized:(const char *)moduleName;
+ @end
+
+/**
+ * Experimental.
+ * A protocol to declare that a class supports TurboModule.
+ * This may be removed in the future.
+ * See RCTTurboModule.h for actual signature.
+ */
+@protocol RCTTurboModule;

React/Base/RCTBridge+Private.h

@@ -1,13 +1,10 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
*/
-#import <JavaScriptCore/JavaScriptCore.h>
-#import <JavaScriptCore/JSBase.h>
-
#import <React/RCTBridge.h>
@class RCTModuleData;
@@ -15,8 +12,6 @@
RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
-RCT_EXTERN __attribute__((weak)) void RCTFBQuickPerformanceLoggerConfigureHooks(JSGlobalContextRef ctx);
-
#if RCT_DEBUG
RCT_EXTERN void RCTVerifyAllModulesExported(NSArray *extraModules);
#endif
@@ -112,11 +107,16 @@
- (RCTModuleData *)moduleDataForName:(NSString *)moduleName;
/**
-* Registers additional classes with the ModuleRegistry.
-*/
+ * Registers additional classes with the ModuleRegistry.
+ */
- (void)registerAdditionalModuleClasses:(NSArray<Class> *)newModules;
/**
+ * Updates the ModuleRegistry with a pre-initialized instance.
+ */
+- (void)updateModuleWithInstance:(id<RCTBridgeModule>)instance;
+
+/**
* Systrace profiler toggling methods exposed for the RCTDevMenu
*/
- (void)startProfiling;
@@ -141,15 +141,6 @@
@end
-@interface RCTBridge (JavaScriptCore)
-
-/**
- * The raw JSGlobalContextRef used by the bridge.
- */
-@property (nonatomic, readonly, assign) JSGlobalContextRef jsContextRef;
-
-@end
-
@interface RCTBridge (Inspector)
@property (nonatomic, readonly, getter=isInspectable) BOOL inspectable;
@@ -158,6 +149,8 @@
@interface RCTCxxBridge : RCTBridge
+@property (nonatomic) void *runtime;
+
- (instancetype)initWithParentBridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
@end

React/Base/RCTBundleURLProvider.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTBundleURLProvider.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTConvert.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -15,7 +15,9 @@
#import <React/RCTPointerEvents.h>
#import <React/RCTTextDecorationLineType.h>
#import <yoga/Yoga.h>
+#if TARGET_OS_IPHONE && WEBKIT_IOS_10_APIS_AVAILABLE
#import <WebKit/WebKit.h>
+#endif
/**
* This class provides a collection of conversion functions for mapping

React/Base/RCTConvert.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -89,7 +89,14 @@
// Check if it has a scheme
if ([path rangeOfString:@":"].location != NSNotFound) {
- path = [path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+ NSMutableCharacterSet *urlAllowedCharacterSet = [NSMutableCharacterSet new];
+ [urlAllowedCharacterSet formUnionWithCharacterSet:[NSCharacterSet URLUserAllowedCharacterSet]];
+ [urlAllowedCharacterSet formUnionWithCharacterSet:[NSCharacterSet URLPasswordAllowedCharacterSet]];
+ [urlAllowedCharacterSet formUnionWithCharacterSet:[NSCharacterSet URLHostAllowedCharacterSet]];
+ [urlAllowedCharacterSet formUnionWithCharacterSet:[NSCharacterSet URLPathAllowedCharacterSet]];
+ [urlAllowedCharacterSet formUnionWithCharacterSet:[NSCharacterSet URLQueryAllowedCharacterSet]];
+ [urlAllowedCharacterSet formUnionWithCharacterSet:[NSCharacterSet URLFragmentAllowedCharacterSet]];
+ path = [path stringByAddingPercentEncodingWithAllowedCharacters:urlAllowedCharacterSet];
URL = [NSURL URLWithString:path];
if (URL) {
return URL;
@@ -422,6 +429,8 @@
RCT_ENUM_CONVERTER(UIBarStyle, (@{
@"default": @(UIBarStyleDefault),
@"black": @(UIBarStyleBlack),
+ @"blackOpaque": @(UIBarStyleBlackOpaque),
+ @"blackTranslucent": @(UIBarStyleBlackTranslucent),
}), UIBarStyleDefault, integerValue)
#endif

React/Base/RCTCxxConvert.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTCxxConvert.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTDefines.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTDisplayLink.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTDisplayLink.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTErrorCustomizer.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTErrorInfo.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTErrorInfo.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTEventDispatcher.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTEventDispatcher.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTFrameUpdate.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTFrameUpdate.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTImageSource.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTImageSource.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTInvalidating.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTJavaScriptExecutor.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,8 +7,6 @@
#import <objc/runtime.h>
-#import <JavaScriptCore/JavaScriptCore.h>
-
#import <React/RCTBridgeModule.h>
#import <React/RCTInvalidating.h>

React/Base/RCTJavaScriptLoader.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTJavaScriptLoader.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,7 +10,6 @@
#import <sys/stat.h>
#import <cxxreact/JSBundleType.h>
-#import <jschelpers/JavaScriptCore.h>
#import "RCTBridge.h"
#import "RCTConvert.h"
@@ -20,6 +19,8 @@
NSString *const RCTJavaScriptLoaderErrorDomain = @"RCTJavaScriptLoaderErrorDomain";
+static const int32_t JSNoBytecodeFileFormatVersion = -1;
+
@interface RCTSource()
{
@public

React/Base/RCTJSCErrorHandling.h

@@ -1,31 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#import <JavaScriptCore/JavaScriptCore.h>
-
-#import <React/RCTDefines.h>
-
-/**
- Translates a given exception into an NSError.
-
- @param exception The JavaScript exception object to translate into an NSError. This must be
- a JavaScript Error object, otherwise no stack trace information will be available.
-
- @return The translated NSError object
-
- - The JS exception's name property is incorporated in the NSError's localized description
- - The JS exception's message property is the NSError's failure reason
- - The JS exception's unsymbolicated stack trace is available via the NSError userInfo's RCTJSExceptionUnsymbolicatedStackTraceKey
- */
-RCT_EXTERN NSError *RCTNSErrorFromJSError(JSValue *exception);
-
-/**
- Translates a given exception into an NSError.
-
- @see RCTNSErrorFromJSError for details
- */
-RCT_EXTERN NSError *RCTNSErrorFromJSErrorRef(JSValueRef exceptionRef, JSGlobalContextRef ctx);

React/Base/RCTJSCErrorHandling.mm

@@ -1,41 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#include "RCTJSCErrorHandling.h"
-
-#import <jschelpers/JavaScriptCore.h>
-
-#import "RCTAssert.h"
-#import "RCTJSStackFrame.h"
-#import "RCTLog.h"
-
-NSString *const RCTJSExceptionUnsymbolicatedStackTraceKey = @"RCTJSExceptionUnsymbolicatedStackTraceKey";
-
-NSError *RCTNSErrorFromJSError(JSValue *exception)
-{
- NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
- userInfo[NSLocalizedDescriptionKey] = [NSString stringWithFormat:@"Unhandled JS Exception: %@", [exception[@"name"] toString] ?: @"Unknown"];
- NSString *const exceptionMessage = [exception[@"message"] toString];
- if ([exceptionMessage length]) {
- userInfo[NSLocalizedFailureReasonErrorKey] = exceptionMessage;
- }
- NSString *const stack = [exception[@"stack"] toString];
- if ([@"undefined" isEqualToString:stack]) {
- RCTLogWarn(@"Couldn't get stack trace for %@:%@", exception[@"sourceURL"], exception[@"line"]);
- } else if ([stack length]) {
- NSArray<RCTJSStackFrame *> *const unsymbolicatedFrames = [RCTJSStackFrame stackFramesWithLines:stack];
- userInfo[RCTJSStackTraceKey] = unsymbolicatedFrames;
- }
- return [NSError errorWithDomain:RCTErrorDomain code:1 userInfo:userInfo];
-}
-
-NSError *RCTNSErrorFromJSErrorRef(JSValueRef exceptionRef, JSGlobalContextRef ctx)
-{
- JSContext *context = [JSC_JSContext(ctx) contextWithJSGlobalContextRef:ctx];
- JSValue *exception = [JSC_JSValue(ctx) valueWithJSValueRef:exceptionRef inContext:context];
- return RCTNSErrorFromJSError(exception);
-}

React/Base/RCTJSStackFrame.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTJSStackFrame.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTKeyCommands.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTKeyCommands.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTLog.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTLog.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTManagedPointer.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTManagedPointer.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTModuleData.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -69,7 +69,7 @@
* if it has not already been created. To check if the module instance exists
* without causing it to be created, use `hasInstance` instead.
*/
-@property (nonatomic, strong, readonly) id<RCTBridgeModule> instance;
+@property (nonatomic, strong, readwrite) id<RCTBridgeModule> instance;
/**
* Returns the module method dispatch queue. Note that this will init both the

React/Base/RCTModuleData.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTModuleMethod.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTModuleMethod.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTMultipartDataTask.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTMultipartDataTask.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTMultipartStreamReader.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTMultipartStreamReader.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTNullability.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTParserUtils.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTParserUtils.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTPerformanceLogger.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -19,10 +19,8 @@
RCTPLNativeModuleInit,
RCTPLNativeModuleMainThread,
RCTPLNativeModulePrepareConfig,
- RCTPLNativeModuleInjectConfig,
RCTPLNativeModuleMainThreadUsesCount,
RCTPLJSCWrapperOpenLibrary,
- RCTPLJSCExecutorSetup,
RCTPLBridgeStartup,
RCTPLTTI,
RCTPLBundleSize,

React/Base/RCTPerformanceLogger.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTPlatform.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTPlatform.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -38,6 +38,11 @@
- (NSDictionary<NSString *, id> *)constantsToExport
{
+ return [self getConstants];
+}
+
+- (NSDictionary<NSString *, id> *)getConstants
+{
UIDevice *device = [UIDevice currentDevice];
return @{
@"forceTouchAvailable": @(RCTForceTouchAvailable()),

React/Base/RCTReloadCommand.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTReloadCommand.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTRootContentView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTRootContentView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTRootViewDelegate.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTRootView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTRootViewInternal.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTRootView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTTouchEvent.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTTouchEvent.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTTouchHandler.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTTouchHandler.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTTVRemoteHandler.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTTVRemoteHandler.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -69,22 +69,22 @@
name:RCTTVRemoteEventSelect];
// Up
- [self addTapGestureRecognizerWithSelector:@selector(swipedUp:)
+ [self addTapGestureRecognizerWithSelector:@selector(tappedUp:)
pressType:UIPressTypeUpArrow
name:RCTTVRemoteEventUp];
// Down
- [self addTapGestureRecognizerWithSelector:@selector(swipedDown:)
+ [self addTapGestureRecognizerWithSelector:@selector(tappedDown:)
pressType:UIPressTypeDownArrow
name:RCTTVRemoteEventDown];
// Left
- [self addTapGestureRecognizerWithSelector:@selector(swipedLeft:)
+ [self addTapGestureRecognizerWithSelector:@selector(tappedLeft:)
pressType:UIPressTypeLeftArrow
name:RCTTVRemoteEventLeft];
// Right
- [self addTapGestureRecognizerWithSelector:@selector(swipedRight:)
+ [self addTapGestureRecognizerWithSelector:@selector(tappedRight:)
pressType:UIPressTypeRightArrow
name:RCTTVRemoteEventRight];
@@ -158,21 +158,41 @@
- (void)swipedUp:(UIGestureRecognizer *)r
{
- [self sendAppleTVEvent:RCTTVRemoteEventUp toView:r.view];
+ [self sendAppleTVEvent:RCTTVRemoteEventSwipeUp toView:r.view];
}
- (void)swipedDown:(UIGestureRecognizer *)r
{
- [self sendAppleTVEvent:RCTTVRemoteEventDown toView:r.view];
+ [self sendAppleTVEvent:RCTTVRemoteEventSwipeDown toView:r.view];
}
- (void)swipedLeft:(UIGestureRecognizer *)r
{
- [self sendAppleTVEvent:RCTTVRemoteEventLeft toView:r.view];
+ [self sendAppleTVEvent:RCTTVRemoteEventSwipeLeft toView:r.view];
}
- (void)swipedRight:(UIGestureRecognizer *)r
{
+ [self sendAppleTVEvent:RCTTVRemoteEventSwipeRight toView:r.view];
+}
+
+- (void)tappedUp:(UIGestureRecognizer *)r
+{
+ [self sendAppleTVEvent:RCTTVRemoteEventUp toView:r.view];
+}
+
+- (void)tappedDown:(UIGestureRecognizer *)r
+{
+ [self sendAppleTVEvent:RCTTVRemoteEventDown toView:r.view];
+}
+
+- (void)tappedLeft:(UIGestureRecognizer *)r
+{
+ [self sendAppleTVEvent:RCTTVRemoteEventLeft toView:r.view];
+}
+
+- (void)tappedRight:(UIGestureRecognizer *)r
+{
[self sendAppleTVEvent:RCTTVRemoteEventRight toView:r.view];
}

React/Base/RCTURLRequestDelegate.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTURLRequestHandler.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTUtils.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -146,4 +146,7 @@
RCT_EXTERN NSString *__nullable RCTGetURLQueryParam(NSURL *__nullable URL, NSString *param);
RCT_EXTERN NSURL *__nullable RCTURLByReplacingQueryParam(NSURL *__nullable URL, NSString *param, NSString *__nullable value);
+// Given a string, drop common RN prefixes (RCT, RK, etc.)
+RCT_EXTERN NSString *RCTDropReactPrefixes(NSString *s);
+
NS_ASSUME_NONNULL_END

React/Base/RCTUtils.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -458,7 +458,9 @@
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSDictionary *environment = [[NSProcessInfo processInfo] environment];
- isTestEnvironment = objc_lookUpClass("SenTestCase") || objc_lookUpClass("XCTest") ||
+ isTestEnvironment = objc_lookUpClass("SenTestCase") ||
+ objc_lookUpClass("XCTest") ||
+ objc_lookUpClass("SnapshotTestAppDelegate") ||
[environment[@"IS_TESTING"] boolValue];
});
return isTestEnvironment;
@@ -706,13 +708,11 @@
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) {
@@ -900,3 +900,14 @@
components.queryItems = queryItems;
return components.URL;
}
+
+RCT_EXTERN NSString *RCTDropReactPrefixes(NSString *s)
+{
+ if ([s hasPrefix:@"RK"]) {
+ return [s substringFromIndex:2];
+ } else if ([s hasPrefix:@"RCT"]) {
+ return [s substringFromIndex:3];
+ }
+
+ return s;
+}

React/Base/RCTVersion.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/RCTVersion.m

@@ -1,7 +1,7 @@
/**
* @generated by scripts/bump-oss-version.js
*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -21,8 +21,8 @@
{
__rnVersion = @{
RCTVersionMajor: @(0),
- RCTVersionMinor: @(57),
- RCTVersionPatch: @(8),
+ RCTVersionMinor: @(59),
+ RCTVersionPatch: @(4),
RCTVersionPrerelease: [NSNull null],
};
}

React/Base/Surface/RCTSurfaceDelegate.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/Surface/RCTSurface.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -114,6 +114,15 @@
*/
- (BOOL)synchronouslyWaitForStage:(RCTSurfaceStage)stage timeout:(NSTimeInterval)timeout;
+#pragma mark - Start & Stop
+
+/**
+ * Starts or stops the Surface.
+ * Those methods are a no-op for regular RCTSurface (for now), but all call sites must call them appropriately.
+ */
+- (BOOL)start;
+- (BOOL)stop;
+
#pragma mark - Mounting/Unmounting of React components
/**

React/Base/Surface/RCTSurface.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -450,7 +450,7 @@
return NO;
}
- if (RCTIsMainQueue() && (stage == RCTSurfaceStageSurfaceDidInitialMounting)) {
+ if (RCTIsMainQueue() && (stage & RCTSurfaceStageSurfaceDidInitialMounting)) {
// All main-threaded execution (especially mounting process) has to be
// intercepted, captured and performed synchnously at the end of this method
// right after the semaphore signals.
@@ -485,7 +485,7 @@
dispatch_semaphore_signal(semaphore);
}
- if (RCTIsMainQueue() && (stage == RCTSurfaceStageSurfaceDidInitialMounting)) {
+ if (RCTIsMainQueue() && (stage & RCTSurfaceStageSurfaceDidInitialMounting)) {
// Time to apply captured mounting block.
RCTUIManagerMountingBlock mountingBlock;
{
@@ -560,6 +560,20 @@
}
}
+- (BOOL)start
+{
+ // Does nothing.
+ // The Start&Stop feature is not implemented for regular Surface yet.
+ return YES;
+}
+
+- (BOOL)stop
+{
+ // Does nothing.
+ // The Start&Stop feature is not implemented for regular Surface yet.
+ return YES;
+}
+
#pragma mark - Mounting/Unmounting of React components
- (void)mountReactComponentWithBridge:(RCTBridge *)bridge moduleName:(NSString *)moduleName params:(NSDictionary *)params

React/Base/Surface/RCTSurfaceRootShadowViewDelegate.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/Surface/RCTSurfaceRootShadowView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/Surface/RCTSurfaceRootShadowView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/Surface/RCTSurfaceRootView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/Surface/RCTSurfaceRootView.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/Surface/RCTSurfaceStage.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -21,6 +21,18 @@
RCTSurfaceStageSurfaceDidInitialLayout = 1 << 5, // UIManager completed the first layout pass
RCTSurfaceStageSurfaceDidInitialMounting = 1 << 6, // UIManager completed the first mounting pass
RCTSurfaceStageSurfaceDidStop = 1 << 7, // Surface stopped
+
+ // Most of the previously existed stages make no sense in the new architecture;
+ // now Surface exposes only three simple stages:
+ //
+ // Surface object was constructed and still valid.
+ RCTSurfaceStageInitialized = RCTSurfaceStageSurfaceDidInitialize,
+ // Surface was started.
+ RCTSurfaceStageStarted = 1 << 8,
+ // All off-main-thread work is done; we are ready to mount the UI.
+ RCTSurfaceStagePrepared = RCTSurfaceStageBridgeDidLoad | RCTSurfaceStageModuleDidLoad | RCTSurfaceStageSurfaceDidRun | RCTSurfaceStageSurfaceDidInitialRendering | RCTSurfaceStageSurfaceDidInitialLayout,
+ // All main-thread work is done, the UI was mounted.
+ RCTSurfaceStageMounted = RCTSurfaceStageSurfaceDidInitialMounting,
};
/**

React/Base/Surface/RCTSurfaceStage.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/Surface/RCTSurfaceView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/Surface/RCTSurfaceView+Internal.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/Surface/RCTSurfaceView.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -69,6 +69,7 @@
if (self = [super initWithBridge:bridge moduleName:moduleName initialProperties:initialProperties sizeMeasureMode:sizeMeasureMode]) {
self.backgroundColor = [UIColor whiteColor];
+ [super.surface start];
}
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");

React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -14,7 +14,7 @@
@class RCTBridge;
@class RCTSurface;
-typedef UIView *(^RCTSurfaceHostingViewActivityIndicatorViewFactory)();
+typedef UIView *_Nullable(^RCTSurfaceHostingViewActivityIndicatorViewFactory)(void);
NS_ASSUME_NONNULL_BEGIN
@@ -27,6 +27,13 @@
@interface RCTSurfaceHostingView : UIView <RCTSurfaceDelegate>
/**
+ * Create an instance of RCTSurface to be hosted.
+ */
++ (RCTSurface *)createSurfaceWithBridge:(RCTBridge *)bridge
+ moduleName:(NSString *)moduleName
+ initialProperties:(NSDictionary *)initialProperties;
+
+/**
* Designated initializer.
* Instanciates a view with given Surface object.
* Note: The view retains the surface object.
@@ -45,13 +52,6 @@
sizeMeasureMode:(RCTSurfaceSizeMeasureMode)sizeMeasureMode;
/**
- * Create an instance of RCTSurface to be hosted.
- */
-- (RCTSurface *)createSurfaceWithBridge:(RCTBridge *)bridge
- moduleName:(NSString *)moduleName
- initialProperties:(NSDictionary *)initialProperties;
-
-/**
* Surface object which is currently using to power the view.
* Read-only.
*/

React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -26,6 +26,13 @@
RCTSurfaceStage _stage;
}
++ (RCTSurface *)createSurfaceWithBridge:(RCTBridge *)bridge
+ moduleName:(NSString *)moduleName
+ initialProperties:(NSDictionary *)initialProperties
+{
+ return [[RCTSurface alloc] initWithBridge:bridge moduleName:moduleName initialProperties:initialProperties];
+}
+
RCT_NOT_IMPLEMENTED(- (instancetype)init)
RCT_NOT_IMPLEMENTED(- (instancetype)initWithFrame:(CGRect)frame)
RCT_NOT_IMPLEMENTED(- (nullable instancetype)initWithCoder:(NSCoder *)coder)
@@ -35,7 +42,8 @@
initialProperties:(NSDictionary *)initialProperties
sizeMeasureMode:(RCTSurfaceSizeMeasureMode)sizeMeasureMode
{
- RCTSurface *surface = [self createSurfaceWithBridge:bridge moduleName:moduleName initialProperties:initialProperties];
+ RCTSurface *surface = [[self class] createSurfaceWithBridge:bridge moduleName:moduleName initialProperties:initialProperties];
+ [surface start];
return [self initWithSurface:surface sizeMeasureMode:sizeMeasureMode];
}
@@ -53,11 +61,9 @@
return self;
}
-- (RCTSurface *)createSurfaceWithBridge:(RCTBridge *)bridge
- moduleName:(NSString *)moduleName
- initialProperties:(NSDictionary *)initialProperties
+- (void)dealloc
{
- return [[RCTSurface alloc] initWithBridge:bridge moduleName:moduleName initialProperties:initialProperties];
+ [_surface stop];
}
- (void)setFrame:(CGRect)frame

React/Base/Surface/SurfaceHostingView/RCTSurfaceSizeMeasureMode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Base/Surface/SurfaceHostingView/RCTSurfaceSizeMeasureMode.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/CxxBridge/JSCExecutorFactory.h

@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#pragma once
+
+#include <jsireact/JSIExecutor.h>
+
+namespace facebook {
+namespace react {
+
+class JSCExecutorFactory : public JSExecutorFactory {
+public:
+ explicit JSCExecutorFactory(
+ JSIExecutor::RuntimeInstaller runtimeInstaller)
+ : runtimeInstaller_(std::move(runtimeInstaller)) {}
+
+ std::unique_ptr<JSExecutor> createJSExecutor(
+ std::shared_ptr<ExecutorDelegate> delegate,
+ std::shared_ptr<MessageQueueThread> jsQueue) override;
+
+private:
+ JSIExecutor::RuntimeInstaller runtimeInstaller_;
+};
+
+} // namespace react
+} // namespace facebook

React/CxxBridge/JSCExecutorFactory.mm

@@ -0,0 +1,32 @@
+/**
+ * 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.
+ */
+
+#include "JSCExecutorFactory.h"
+
+#import <React/RCTLog.h>
+#import <jsi/JSCRuntime.h>
+
+namespace facebook {
+namespace react {
+
+std::unique_ptr<JSExecutor> JSCExecutorFactory::createJSExecutor(
+ std::shared_ptr<ExecutorDelegate> delegate,
+ std::shared_ptr<MessageQueueThread> jsQueue) {
+ return folly::make_unique<JSIExecutor>(
+ facebook::jsc::makeJSCRuntime(),
+ delegate,
+ [](const std::string &message, unsigned int logLevel) {
+ _RCTLogJavaScriptInternal(
+ static_cast<RCTLogLevel>(logLevel),
+ [NSString stringWithUTF8String:message.c_str()]);
+ },
+ JSIExecutor::defaultTimeoutInvoker,
+ std::move(runtimeInstaller_));
+}
+
+} // namespace react
+} // namespace facebook

React/CxxBridge/NSDataBigString.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/CxxBridge/NSDataBigString.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/CxxBridge/RCTCxxBridgeDelegate.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -8,7 +8,6 @@
#include <memory>
#import <React/RCTBridgeDelegate.h>
-#import <jschelpers/JavaScriptCore.h>
namespace facebook {
namespace react {
@@ -26,21 +25,9 @@
/**
* In the RCTCxxBridge, if this method is implemented, return a
* ExecutorFactory instance which can be used to create the executor.
- * If not implemented, or returns an empty pointer, JSCExecutorFactory
- * will be used.
+ * If not implemented, or returns an empty pointer, JSIExecutorFactory
+ * will be used with a JSCRuntime.
*/
- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge;
-@optional
-
-/**
- * Experimental: Perform installation of extra JS binding on the given JS context, as appropriate.
- */
-- (void)installExtraJSBinding:(JSGlobalContextRef)jsContextRef;
-
-/**
- * Experimental: Get the instance of the extra module/class which gets bound via `installExtraJSBinding:`
- */
-- (id)jsBoundExtraModuleForClass:(Class)moduleClass;
-
@end

React/CxxBridge/RCTCxxBridge.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -29,15 +29,14 @@
#import <cxxreact/CxxNativeModule.h>
#import <cxxreact/Instance.h>
#import <cxxreact/JSBundleType.h>
-#import <cxxreact/JSCExecutor.h>
#import <cxxreact/JSIndexedRAMBundle.h>
#import <cxxreact/ModuleRegistry.h>
-#import <cxxreact/Platform.h>
#import <cxxreact/RAMBundleRegistry.h>
-#import <jschelpers/Value.h>
+#import <cxxreact/ReactMarker.h>
+#import <jsireact/JSIExecutor.h>
+#import "JSCExecutorFactory.h"
#import "NSDataBigString.h"
-#import "RCTJSCHelpers.h"
#import "RCTMessageThread.h"
#import "RCTObjcExecutor.h"
@@ -57,6 +56,7 @@
typedef void (^RCTPendingCall)();
+using namespace facebook::jsi;
using namespace facebook::react;
/**
@@ -152,8 +152,8 @@
@implementation RCTCxxBridge
{
- BOOL _wasBatchActive;
BOOL _didInvalidate;
+ BOOL _moduleRegistryCreated;
NSMutableArray<RCTPendingCall> *_pendingCalls;
std::atomic<NSInteger> _pendingCount;
@@ -168,9 +168,13 @@
// JS thread management
NSThread *_jsThread;
std::shared_ptr<RCTMessageThread> _jsMessageThread;
+ std::mutex _moduleRegistryLock;
// This is uniquely owned, but weak_ptr is used.
std::shared_ptr<Instance> _reactInstance;
+
+ // Necessary for searching in TurboModuleRegistry
+ id<RCTTurboModuleLookupDelegate> _turboModuleLookupDelegate;
}
@synthesize bridgeDescription = _bridgeDescription;
@@ -178,16 +182,9 @@
@synthesize performanceLogger = _performanceLogger;
@synthesize valid = _valid;
-+ (void)initialize
+- (void) setRCTTurboModuleLookupDelegate:(id<RCTTurboModuleLookupDelegate>)turboModuleLookupDelegate
{
- if (self == [RCTCxxBridge class]) {
- RCTPrepareJSCExecutor();
- }
-}
-
-- (JSGlobalContextRef)jsContextRef
-{
- return (JSGlobalContextRef)(_reactInstance ? _reactInstance->getJavaScriptContext() : nullptr);
+ _turboModuleLookupDelegate = turboModuleLookupDelegate;
}
- (std::shared_ptr<MessageQueueThread>)jsMessageThread
@@ -220,9 +217,9 @@
*/
_valid = YES;
_loading = YES;
+ _moduleRegistryCreated = NO;
_pendingCalls = [NSMutableArray new];
_displayLink = [RCTDisplayLink new];
-
_moduleDataByName = [NSMutableDictionary new];
_moduleClassesByID = [NSMutableArray new];
_moduleDataByID = [NSMutableArray new];
@@ -312,6 +309,7 @@
[self registerExtraModules];
// Initialize all native modules that cannot be loaded lazily
(void)[self _initializeModules:RCTGetModuleClasses() withDispatchGroup:prepareBridge lazilyDiscovered:NO];
+ [self registerExtraLazyModules];
[_performanceLogger markStopForTag:RCTPLNativeModuleInit];
@@ -328,22 +326,7 @@
executorFactory = [cxxDelegate jsExecutorFactoryForBridge:self];
}
if (!executorFactory) {
- BOOL useCustomJSC =
- [self.delegate respondsToSelector:@selector(shouldBridgeUseCustomJSC:)] &&
- [self.delegate shouldBridgeUseCustomJSC:self];
- // We use the name of the device and the app for debugging & metrics
- NSString *deviceName = [[UIDevice currentDevice] name];
- NSString *appName = [[NSBundle mainBundle] bundleIdentifier];
- // The arg is a cache dir. It's not used with standard JSC.
- executorFactory.reset(new JSCExecutorFactory(folly::dynamic::object
- ("OwnerIdentity", "ReactNative")
- ("AppIdentity", [(appName ?: @"unknown") UTF8String])
- ("DeviceIdentity", [(deviceName ?: @"unknown") UTF8String])
- ("UseCustomJSC", (bool)useCustomJSC)
- #if RCT_PROFILE
- ("StartSamplingProfilerOnInit", (bool)self.devSettings.startSamplingProfilerOnLaunch)
- #endif
- ));
+ executorFactory = std::make_shared<JSCExecutorFactory>(nullptr);
}
} else {
id<RCTJavaScriptExecutor> objcExecutor = [self moduleForClass:self.executorClass];
@@ -374,7 +357,9 @@
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
}];
@@ -453,27 +438,69 @@
- (id)moduleForName:(NSString *)moduleName
{
- return _moduleDataByName[moduleName].instance;
+ return [self moduleForName:moduleName lazilyLoadIfNecessary:NO];
}
-- (BOOL)moduleIsInitialized:(Class)moduleClass
+- (id)moduleForName:(NSString *)moduleName lazilyLoadIfNecessary:(BOOL)lazilyLoad
{
- return _moduleDataByName[RCTBridgeModuleNameForClass(moduleClass)].hasInstance;
+ if (RCTTurboModuleEnabled() && _turboModuleLookupDelegate) {
+ const char* moduleNameCStr = [moduleName UTF8String];
+ if (lazilyLoad || [_turboModuleLookupDelegate moduleIsInitialized:moduleNameCStr]) {
+ id<RCTTurboModule> module = [_turboModuleLookupDelegate moduleForName:moduleNameCStr warnOnLookupFailure:NO];
+ if (module != nil) {
+ return module;
+ }
+ }
+ }
+
+ if (!lazilyLoad) {
+ return _moduleDataByName[moduleName].instance;
+ }
+
+ RCTModuleData *moduleData = _moduleDataByName[moduleName];
+ if (moduleData) {
+ if (![moduleData isKindOfClass:[RCTModuleData class]]) {
+ // There is rare race condition where the data stored in the dictionary
+ // may have been deallocated, which means the module instance is no longer
+ // usable.
+ return nil;
+ }
+ return moduleData.instance;
+ }
+
+ // Module may not be loaded yet, so attempt to force load it here.
+ const BOOL result = [self.delegate respondsToSelector:@selector(bridge:didNotFindModule:)] &&
+ [self.delegate bridge:self didNotFindModule:moduleName];
+ if (result) {
+ // Try again.
+ moduleData = _moduleDataByName[moduleName];
+ } else {
+ RCTLogError(@"Unable to find module for %@", moduleName);
+ }
+
+ return moduleData.instance;
}
-- (id)jsBoundExtraModuleForClass:(Class)moduleClass
+- (BOOL)moduleIsInitialized:(Class)moduleClass
{
- if ([self.delegate conformsToProtocol:@protocol(RCTCxxBridgeDelegate)]) {
- id<RCTCxxBridgeDelegate> cxxDelegate = (id<RCTCxxBridgeDelegate>) self.delegate;
- if ([cxxDelegate respondsToSelector:@selector(jsBoundExtraModuleForClass:)]) {
- return [cxxDelegate jsBoundExtraModuleForClass:moduleClass];
+ NSString* moduleName = RCTBridgeModuleNameForClass(moduleClass);
+ if (_moduleDataByName[moduleName].hasInstance) {
+ return YES;
}
+
+ if (_turboModuleLookupDelegate) {
+ return [_turboModuleLookupDelegate moduleIsInitialized:[moduleName UTF8String]];
}
- return nil;
+ return NO;
+}
+
+- (id)moduleForClass:(Class)moduleClass
+{
+ return [self moduleForName:RCTBridgeModuleNameForClass(moduleClass) lazilyLoadIfNecessary:YES];
}
-- (std::shared_ptr<ModuleRegistry>)_buildModuleRegistry
+- (std::shared_ptr<ModuleRegistry>)_buildModuleRegistryUnlocked
{
if (!self.valid) {
return {};
@@ -520,12 +547,7 @@
executorFactory = std::make_shared<GetDescAdapter>(self, executorFactory);
#endif
- // This is async, but any calls into JS are blocked by the m_syncReady CV in Instance
- _reactInstance->initializeBridge(
- std::make_unique<RCTInstanceCallback>(self),
- executorFactory,
- _jsMessageThread,
- [self _buildModuleRegistry]);
+ [self _initializeBridgeLocked:executorFactory];
#if RCT_PROFILE
if (RCTProfileIsProfiling()) {
@@ -534,27 +556,58 @@
std::make_unique<JSBigStdString>("true"));
}
#endif
-
- [self installExtraJSBinding];
}
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
}
+- (void)_initializeBridgeLocked:(std::shared_ptr<JSExecutorFactory>)executorFactory
+{
+ std::lock_guard<std::mutex> guard(_moduleRegistryLock);
+
+ // This is async, but any calls into JS are blocked by the m_syncReady CV in Instance
+ _reactInstance->initializeBridge(
+ std::make_unique<RCTInstanceCallback>(self),
+ executorFactory,
+ _jsMessageThread,
+ [self _buildModuleRegistryUnlocked]);
+ _moduleRegistryCreated = YES;
+}
+
+- (void)updateModuleWithInstance:(id<RCTBridgeModule>)instance;
+{
+ NSString *const moduleName = RCTBridgeModuleNameForClass([instance class]);
+ if (moduleName) {
+ RCTModuleData *const moduleData = _moduleDataByName[moduleName];
+ if (moduleData) {
+ moduleData.instance = instance;
+ }
+ }
+}
+
- (NSArray<RCTModuleData *> *)registerModulesForClasses:(NSArray<Class> *)moduleClasses
{
+ return [self _registerModulesForClasses:moduleClasses lazilyDiscovered:NO];
+}
+
+- (NSArray<RCTModuleData *> *)_registerModulesForClasses:(NSArray<Class> *)moduleClasses
+ lazilyDiscovered:(BOOL)lazilyDiscovered
+{
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways,
@"-[RCTCxxBridge initModulesWithDispatchGroup:] autoexported moduleData", nil);
NSArray *moduleClassesCopy = [moduleClasses copy];
NSMutableArray<RCTModuleData *> *moduleDataByID = [NSMutableArray arrayWithCapacity:moduleClassesCopy.count];
for (Class moduleClass in moduleClassesCopy) {
+ if (RCTTurboModuleEnabled() && [moduleClass conformsToProtocol:@protocol(RCTTurboModule)]) {
+ continue;
+ }
NSString *moduleName = RCTBridgeModuleNameForClass(moduleClass);
// Check for module name collisions
RCTModuleData *moduleData = _moduleDataByName[moduleName];
if (moduleData) {
- if (moduleData.hasInstance) {
+ if (moduleData.hasInstance || lazilyDiscovered) {
// Existing module was preregistered, so it takes precedence
continue;
} else if ([moduleClass new] == nil) {
@@ -622,6 +675,16 @@
}
}
+ if (RCTTurboModuleEnabled() && [module conformsToProtocol:@protocol(RCTTurboModule)]) {
+#if RCT_DEBUG
+ // TODO: don't ask for extra module for when TurboModule is enabled.
+ RCTLogError(@"NativeModule '%@' was marked as TurboModule, but provided as an extra NativeModule "
+ "by the class '%@', ignoring.",
+ moduleName, moduleClass);
+#endif
+ continue;
+ }
+
// Instantiate moduleData container
RCTModuleData *moduleData = [[RCTModuleData alloc] initWithModuleInstance:module bridge:self];
_moduleDataByName[moduleName] = moduleData;
@@ -631,14 +694,53 @@
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
}
-- (void)installExtraJSBinding
+- (void)registerExtraLazyModules
{
- if ([self.delegate conformsToProtocol:@protocol(RCTCxxBridgeDelegate)]) {
- id<RCTCxxBridgeDelegate> cxxDelegate = (id<RCTCxxBridgeDelegate>) self.delegate;
- if ([cxxDelegate respondsToSelector:@selector(installExtraJSBinding:)]) {
- [cxxDelegate installExtraJSBinding:self.jsContextRef];
+#if RCT_DEBUG
+ // This is debug-only and only when Chrome is attached, since it expects all modules to be already
+ // available on start up. Otherwise, we can let the lazy module discovery to load them on demand.
+ Class executorClass = [_parentBridge executorClass];
+ if (executorClass && [NSStringFromClass(executorClass) isEqualToString:@"RCTWebSocketExecutor"]) {
+ NSDictionary<NSString *, Class> *moduleClasses = nil;
+ if ([self.delegate respondsToSelector:@selector(extraLazyModuleClassesForBridge:)]) {
+ moduleClasses = [self.delegate extraLazyModuleClassesForBridge:_parentBridge];
+ }
+
+ if (!moduleClasses) {
+ return;
+ }
+
+ // This logic is mostly copied from `registerModulesForClasses:`, but with one difference:
+ // we must use the names provided by the delegate method here.
+ for (NSString *moduleName in moduleClasses) {
+ Class moduleClass = moduleClasses[moduleName];
+ if (RCTTurboModuleEnabled() && [moduleClass conformsToProtocol:@protocol(RCTTurboModule)]) {
+ continue;
+ }
+
+ // Check for module name collisions
+ RCTModuleData *moduleData = _moduleDataByName[moduleName];
+ if (moduleData) {
+ if (moduleData.hasInstance) {
+ // Existing module was preregistered, so it takes precedence
+ continue;
+ } else if ([moduleClass new] == nil) {
+ // The new module returned nil from init, so use the old module
+ continue;
+ } else if ([moduleData.moduleClass new] != nil) {
+ // Use existing module since it was already loaded but not yet instantiated.
+ continue;
+ }
+ }
+
+ moduleData = [[RCTModuleData alloc] initWithModuleClass:moduleClass bridge:self];
+
+ _moduleDataByName[moduleName] = moduleData;
+ [_moduleClassesByID addObject:moduleClass];
+ [_moduleDataByID addObject:moduleData];
}
}
+#endif
}
- (NSArray<RCTModuleData *> *)_initializeModules:(NSArray<id<RCTBridgeModule>> *)modules
@@ -646,7 +748,7 @@
lazilyDiscovered:(BOOL)lazilyDiscovered
{
// Set up moduleData for automatically-exported modules
- NSArray<RCTModuleData *> *moduleDataById = [self registerModulesForClasses:modules];
+ NSArray<RCTModuleData *> *moduleDataById = [self _registerModulesForClasses:modules lazilyDiscovered:lazilyDiscovered];
if (lazilyDiscovered) {
#if RCT_DEBUG
@@ -695,9 +797,13 @@
- (void)registerAdditionalModuleClasses:(NSArray<Class> *)modules
{
+ std::lock_guard<std::mutex> guard(_moduleRegistryLock);
+ if (_moduleRegistryCreated) {
NSArray<RCTModuleData *> *newModules = [self _initializeModules:modules withDispatchGroup:NULL lazilyDiscovered:YES];
- if (_reactInstance) {
+ assert(_reactInstance); // at this point you must have reactInstance as you already called reactInstance->initialzeBridge
_reactInstance->getModuleRegistry().registerModules(createNativeModules(newModules, self, _reactInstance));
+ } else {
+ [self registerModulesForClasses:modules];
}
}
@@ -836,6 +942,7 @@
_loading = NO;
_valid = NO;
+ _moduleRegistryCreated = NO;
dispatch_async(dispatch_get_main_queue(), ^{
if (self->_jsMessageThread) {
@@ -932,6 +1039,7 @@
_loading = NO;
_valid = NO;
_didInvalidate = YES;
+ _moduleRegistryCreated = NO;
if ([RCTBridge currentBridge] == self) {
[RCTBridge setCurrentBridge:nil];
@@ -1268,7 +1376,16 @@
- (BOOL)isBatchActive
{
- return _wasBatchActive;
+ return _reactInstance ? _reactInstance->isBatchActive() : NO;
+}
+
+- (void *)runtime
+{
+ if (!_reactInstance) {
+ return nullptr;
+ }
+
+ return _reactInstance->getJavaScriptContext();
}
@end

React/CxxBridge/RCTJSCHelpers.h

@@ -1,15 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#pragma once
-
-/**
- * This must be invoked on iOS to set up platform dependencies before
- * creating an instance of JSCExecutor.
- */
-
-void RCTPrepareJSCExecutor();

React/CxxBridge/RCTJSCHelpers.mm

@@ -1,50 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#include "RCTJSCHelpers.h"
-
-#import <Foundation/Foundation.h>
-
-#import <React/RCTBridge+Private.h>
-#import <React/RCTCxxUtils.h>
-#import <React/RCTLog.h>
-#import <cxxreact/Platform.h>
-#import <jschelpers/Value.h>
-
-using namespace facebook::react;
-
-namespace {
-
-JSValueRef nativeLoggingHook(
- JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount,
- const JSValueRef arguments[], JSValueRef *exception) {
- RCTLogLevel level = RCTLogLevelInfo;
- if (argumentCount > 1) {
- level = MAX(level, (RCTLogLevel)Value(ctx, arguments[1]).asNumber());
- }
- if (argumentCount > 0) {
- JSContext *contextObj = contextForGlobalContextRef(JSC_JSContextGetGlobalContext(ctx));
- JSValue *msg = [JSC_JSValue(ctx) valueWithJSValueRef:arguments[0] inContext:contextObj];
- _RCTLogJavaScriptInternal(level, [msg toString]);
- }
- return Value::makeUndefined(ctx);
-}
-
-JSValueRef nativePerformanceNow(
- JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount,
- const JSValueRef arguments[], JSValueRef *exception) {
- return Value::makeNumber(ctx, CACurrentMediaTime() * 1000);
-}
-
-}
-
-void RCTPrepareJSCExecutor() {
- ReactMarker::logTaggedMarker = [](const ReactMarker::ReactMarkerId, const char *tag) {};
- JSCNativeHooks::loggingHook = nativeLoggingHook;
- JSCNativeHooks::nowHook = nativePerformanceNow;
- JSCNativeHooks::installPerfHooks = RCTFBQuickPerformanceLoggerConfigureHooks;
-}

React/CxxBridge/RCTMessageThread.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/CxxBridge/RCTMessageThread.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -12,7 +12,6 @@
#import <React/RCTCxxUtils.h>
#import <React/RCTUtils.h>
-#include <jschelpers/JSCHelpers.h>
// A note about the implementation: This class is not used
// generically. It's a thin wrapper around a run loop which

React/CxxBridge/RCTObjcExecutor.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/CxxBridge/RCTObjcExecutor.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/CxxModule/DispatchMessageQueueThread.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/CxxModule/RCTCxxMethod.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/CxxModule/RCTCxxMethod.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/CxxModule/RCTCxxModule.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/CxxModule/RCTCxxModule.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -64,7 +64,12 @@
return moduleMethods;
}
-- (NSDictionary<NSString *, id> *)constantsToExport;
+- (NSDictionary<NSString *, id> *)constantsToExport
+{
+ return [self getConstants];
+}
+
+- (NSDictionary<NSString *, id> *)getConstants;
{
[self lazyInit];
if (!_module) {

React/CxxModule/RCTCxxUtils.h

@@ -1,16 +1,14 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
*/
+#include <functional>
#include <memory>
-#import <JavaScriptCore/JavaScriptCore.h>
-
-#import <cxxreact/JSCExecutor.h>
-#import <jschelpers/JavaScriptCore.h>
+#import <Foundation/Foundation.h>
@class RCTBridge;
@class RCTModuleData;
@@ -19,19 +17,10 @@
namespace react {
class Instance;
+class NativeModule;
std::vector<std::unique_ptr<NativeModule>> createNativeModules(NSArray<RCTModuleData *> *modules, RCTBridge *bridge, const std::shared_ptr<Instance> &instance);
-JSContext *contextForGlobalContextRef(JSGlobalContextRef contextRef);
-
-template<>
-struct JSCValueEncoder<id> {
- static Value toJSCValue(JSGlobalContextRef ctx, id obj) {
- JSValue *value = [JSC_JSValue(ctx) valueWithObject:obj inContext:contextForGlobalContextRef(ctx)];
- return {ctx, [value JSValueRef]};
- }
-};
-
NSError *tryAndReturnError(const std::function<void()>& func);
NSString *deriveSourceURL(NSURL *url);

React/CxxModule/RCTCxxUtils.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,7 +11,7 @@
#import <React/RCTModuleData.h>
#import <React/RCTUtils.h>
#import <cxxreact/CxxNativeModule.h>
-#import <jschelpers/Value.h>
+#import <jsi/jsi.h>
#import "DispatchMessageQueueThread.h"
#import "RCTCxxModule.h"
@@ -20,6 +20,8 @@
namespace facebook {
namespace react {
+using facebook::jsi::JSError;
+
std::vector<std::unique_ptr<NativeModule>> createNativeModules(NSArray<RCTModuleData *> *modules, RCTBridge *bridge, const std::shared_ptr<Instance> &instance)
{
std::vector<std::unique_ptr<NativeModule>> nativeModules;
@@ -37,39 +39,14 @@
return nativeModules;
}
-JSContext *contextForGlobalContextRef(JSGlobalContextRef contextRef)
-{
- static std::mutex s_mutex;
- static NSMapTable *s_contextCache;
-
- if (!contextRef) {
- return nil;
- }
-
- // Adding our own lock here, since JSC internal ones are insufficient
- std::lock_guard<std::mutex> lock(s_mutex);
- if (!s_contextCache) {
- NSPointerFunctionsOptions keyOptions = NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality;
- NSPointerFunctionsOptions valueOptions = NSPointerFunctionsWeakMemory | NSPointerFunctionsObjectPersonality;
- s_contextCache = [[NSMapTable alloc] initWithKeyOptions:keyOptions valueOptions:valueOptions capacity:0];
- }
-
- JSContext *ctx = [s_contextCache objectForKey:(__bridge id)contextRef];
- if (!ctx) {
- ctx = [JSC_JSContext(contextRef) contextWithJSGlobalContextRef:contextRef];
- [s_contextCache setObject:ctx forKey:(__bridge id)contextRef];
- }
- return ctx;
-}
-
static NSError *errorWithException(const std::exception &e)
{
NSString *msg = @(e.what());
NSMutableDictionary *errorInfo = [NSMutableDictionary dictionary];
- const JSException *jsException = dynamic_cast<const JSException*>(&e);
- if (jsException) {
- errorInfo[RCTJSRawStackTraceKey] = @(jsException->getStack().c_str());
+ const auto *jsError = dynamic_cast<const JSError*>(&e);
+ if (jsError) {
+ errorInfo[RCTJSRawStackTraceKey] = @(jsError->getStack().c_str());
msg = [@"Unhandled JS Exception: " stringByAppendingString:msg];
}

React/CxxModule/RCTNativeModule.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/CxxModule/RCTNativeModule.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/CxxUtils/RCTFollyConvert.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/CxxUtils/RCTFollyConvert.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/DevSupport/RCTDevLoadingView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/DevSupport/RCTDevLoadingView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/DevSupport/RCTDevMenu.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/DevSupport/RCTDevMenu.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -269,12 +269,6 @@
}]];
}
- if (devSettings.isJSCSamplingProfilerAvailable) {
- [items addObject:[RCTDevMenuItem buttonItemWithTitle:@"Start / Stop JS Sampling Profiler" handler:^{
- [devSettings toggleJSCSamplingProfiler];
- }]];
- }
-
[items addObject:[RCTDevMenuItem buttonItemWithTitleBlock:^NSString *{
return @"Toggle Inspector";
} handler:^{
@@ -398,6 +392,7 @@
- (void)addItem:(NSString *)title handler:(dispatch_block_t)handler {}
- (void)addItem:(RCTDevMenu *)item {}
- (BOOL)isActionSheetShown { return NO; }
++ (NSString *)moduleName { return @""; }
@end

React/DevSupport/RCTInspectorDevServerHelper.h

@@ -1,10 +1,9 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
#import <Foundation/Foundation.h>
-#import <JavaScriptCore/JSBase.h>
#import <UIKit/UIKit.h>
#import <React/RCTDefines.h>

React/DevSupport/RCTInspectorDevServerHelper.mm

@@ -1,16 +1,18 @@
+// 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.
+
#import "RCTInspectorDevServerHelper.h"
#if RCT_DEV
-#import <jschelpers/JSCWrapper.h>
#import <UIKit/UIKit.h>
#import <React/RCTLog.h>
#import "RCTDefines.h"
#import "RCTInspectorPackagerConnection.h"
-using namespace facebook::react;
-
static NSString *const kDebuggerMsgDisable = @"{ \"id\":1,\"method\":\"Debugger.disable\" }";
static NSString *getServerHost(NSURL *bundleURL, NSNumber *port)
@@ -31,8 +33,8 @@
static NSURL *getInspectorDeviceUrl(NSURL *bundleURL)
{
NSNumber *inspectorProxyPort = @8082;
- NSString *escapedDeviceName = [[[UIDevice currentDevice] name] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
- NSString *escapedAppName = [[[NSBundle mainBundle] bundleIdentifier] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+ NSString *escapedDeviceName = [[[UIDevice currentDevice] name] stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet];
+ NSString *escapedAppName = [[[NSBundle mainBundle] bundleIdentifier] stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet];
return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/inspector/device?name=%@&app=%@",
getServerHost(bundleURL, inspectorProxyPort),
escapedDeviceName,
@@ -42,8 +44,8 @@
static NSURL *getAttachDeviceUrl(NSURL *bundleURL, NSString *title)
{
NSNumber *metroBundlerPort = @8081;
- NSString *escapedDeviceName = [[[UIDevice currentDevice] name] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
- NSString *escapedAppName = [[[NSBundle mainBundle] bundleIdentifier] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+ NSString *escapedDeviceName = [[[UIDevice currentDevice] name] stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLHostAllowedCharacterSet];
+ NSString *escapedAppName = [[[NSBundle mainBundle] bundleIdentifier] stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLHostAllowedCharacterSet];
return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/attach-debugger-nuclide?title=%@&device=%@&app=%@",
getServerHost(bundleURL, metroBundlerPort),
title,

React/DevSupport/RCTPackagerClient.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/DevSupport/RCTPackagerClient.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/DevSupport/RCTPackagerConnection.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/DevSupport/RCTPackagerConnection.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Fabric/Mounting/ComponentViews/ActivityIndicator/RCTActivityIndicatorViewComponentView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Fabric/Mounting/ComponentViews/ActivityIndicator/RCTActivityIndicatorViewComponentView.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,7 +7,8 @@
#import "RCTActivityIndicatorViewComponentView.h"
-#import <fabric/components/activityindicator/ActivityIndicatorViewProps.h>
+#import <react/components/activityindicator/ActivityIndicatorViewShadowNode.h>
+#import <react/components/activityindicator/ActivityIndicatorViewProps.h>
using namespace facebook::react;
@@ -24,22 +25,30 @@
UIActivityIndicatorView *_activityIndicatorView;
}
+#pragma mark - RCTComponentViewProtocol
+
++ (ComponentHandle)componentHandle
+{
+ return ActivityIndicatorViewShadowNode::Handle();
+}
+
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
+ static const auto defaultProps = std::make_shared<const ActivityIndicatorViewProps>();
+ _props = defaultProps;
+
_activityIndicatorView = [[UIActivityIndicatorView alloc] initWithFrame:self.bounds];
_activityIndicatorView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- const auto &defaultProps = ActivityIndicatorViewProps();
-
- if (defaultProps.animating) {
+ if (defaultProps->animating) {
[_activityIndicatorView startAnimating];
} else {
[_activityIndicatorView stopAnimating];
}
- _activityIndicatorView.color = [UIColor colorWithCGColor:defaultProps.color.get()];
- _activityIndicatorView.hidesWhenStopped = defaultProps.hidesWhenStopped;
- _activityIndicatorView.activityIndicatorViewStyle = convertActivityIndicatorViewStyle(defaultProps.size);
+ _activityIndicatorView.color = [UIColor colorWithCGColor:defaultProps->color.get()];
+ _activityIndicatorView.hidesWhenStopped = defaultProps->hidesWhenStopped;
+ _activityIndicatorView.activityIndicatorViewStyle = convertActivityIndicatorViewStyle(defaultProps->size);
[self addSubview:_activityIndicatorView];
}
@@ -49,16 +58,11 @@
- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps
{
- if (!oldProps) {
- oldProps = _props ?: std::make_shared<ActivityIndicatorViewProps>();
- }
- _props = props;
+ const auto &oldViewProps = *std::static_pointer_cast<const ActivityIndicatorViewProps>(oldProps ?: _props);
+ const auto &newViewProps = *std::static_pointer_cast<const ActivityIndicatorViewProps>(props);
[super updateProps:props oldProps:oldProps];
- auto oldViewProps = *std::dynamic_pointer_cast<const ActivityIndicatorViewProps>(oldProps);
- auto newViewProps = *std::dynamic_pointer_cast<const ActivityIndicatorViewProps>(props);
-
if (oldViewProps.animating != newViewProps.animating) {
if (newViewProps.animating) {
[_activityIndicatorView startAnimating];

React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.h

@@ -1,20 +1,19 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
*/
-#import <UIKit/UIKit.h>
-
-#import <React/RCTViewComponentView.h>
+#import "RCTViewComponentView.h"
+#import <React/RCTImageResponseDelegate.h>
NS_ASSUME_NONNULL_BEGIN
/**
* UIView class for root <Image> component.
*/
-@interface RCTImageComponentView : RCTViewComponentView
+@interface RCTImageComponentView : RCTViewComponentView <RCTImageResponseDelegate>
@end

React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,31 +7,36 @@
#import "RCTImageComponentView.h"
-#import <fabric/components/image/ImageEventEmitter.h>
-#import <fabric/components/image/ImageLocalData.h>
-#import <fabric/components/image/ImageProps.h>
-#import <fabric/imagemanager/ImageRequest.h>
-#import <fabric/imagemanager/ImageResponse.h>
-#import <fabric/imagemanager/RCTImagePrimitivesConversions.h>
+#import <react/components/image/ImageEventEmitter.h>
+#import <react/components/image/ImageLocalData.h>
+#import <react/components/image/ImageProps.h>
+#import <react/components/image/ImageShadowNode.h>
+#import <react/imagemanager/ImageRequest.h>
+#import <react/imagemanager/RCTImagePrimitivesConversions.h>
+#import <React/RCTImageResponseObserverProxy.h>
#import "RCTConversions.h"
#import "MainQueueExecutor.h"
-using namespace facebook::react;
-
@implementation RCTImageComponentView {
UIImageView *_imageView;
SharedImageLocalData _imageLocalData;
+ const ImageResponseObserverCoordinator *_coordinator;
+ std::unique_ptr<RCTImageResponseObserverProxy> _imageResponseObserverProxy;
}
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
+ static const auto defaultProps = std::make_shared<const ImageProps>();
+ _props = defaultProps;
+
_imageView = [[UIImageView alloc] initWithFrame:self.bounds];
_imageView.clipsToBounds = YES;
- auto defaultProps = ImageProps();
- _imageView.contentMode = (UIViewContentMode)RCTResizeModeFromImageResizeMode(defaultProps.resizeMode);
+ _imageView.contentMode = (UIViewContentMode)RCTResizeModeFromImageResizeMode(defaultProps->resizeMode);
+
+ _imageResponseObserverProxy = std::make_unique<RCTImageResponseObserverProxy>((__bridge void *)self);
self.contentView = _imageView;
}
@@ -41,18 +46,18 @@
#pragma mark - RCTComponentViewProtocol
++ (ComponentHandle)componentHandle
+{
+ return ImageShadowNode::Handle();
+}
+
- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps
{
- if (!oldProps) {
- oldProps = _props ?: std::make_shared<const ImageProps>();
- }
- _props = props;
+ const auto &oldImageProps = *std::static_pointer_cast<const ImageProps>(oldProps ?: _props);
+ const auto &newImageProps = *std::static_pointer_cast<const ImageProps>(props);
[super updateProps:props oldProps:oldProps];
- const auto &oldImageProps = *std::dynamic_pointer_cast<const ImageProps>(oldProps);
- const auto &newImageProps = *std::dynamic_pointer_cast<const ImageProps>(props);
-
// `resizeMode`
if (oldImageProps.resizeMode != newImageProps.resizeMode) {
if (newImageProps.resizeMode == ImageResizeMode::Repeat) {
@@ -73,24 +78,50 @@
- (void)updateLocalData:(SharedLocalData)localData
oldLocalData:(SharedLocalData)oldLocalData
{
+ SharedImageLocalData previousData = _imageLocalData;
_imageLocalData = std::static_pointer_cast<const ImageLocalData>(localData);
assert(_imageLocalData);
- auto future = _imageLocalData->getImageRequest().getResponseFuture();
- future.via(&MainQueueExecutor::instance()).then([self](ImageResponse &&imageResponse) {
- self.image = (__bridge_transfer UIImage *)imageResponse.getImage().get();
- });
+ bool havePreviousData = previousData != nullptr;
+
+ if (!havePreviousData || _imageLocalData->getImageSource() != previousData->getImageSource()) {
+ self.coordinator = _imageLocalData->getImageRequest().getObserverCoordinator();
+
+ // Loading actually starts a little before this, but this is the first time we know
+ // the image is loading and can fire an event from this component
+ std::static_pointer_cast<const ImageEventEmitter>(_eventEmitter)->onLoadStart();
+ }
+}
+
+- (void)setCoordinator:(const ImageResponseObserverCoordinator *)coordinator {
+ if (_coordinator) {
+ _coordinator->removeObserver(_imageResponseObserverProxy.get());
+ }
+ _coordinator = coordinator;
+ if (_coordinator != nullptr) {
+ _coordinator->addObserver(_imageResponseObserverProxy.get());
+ }
}
- (void)prepareForRecycle
{
[super prepareForRecycle];
+ self.coordinator = nullptr;
_imageView.image = nil;
+ _imageLocalData.reset();
+}
+
+-(void)dealloc
+{
+ self.coordinator = nullptr;
+ _imageResponseObserverProxy.reset();
}
-#pragma mark - Other
+#pragma mark - RCTImageResponseDelegate
-- (void)setImage:(UIImage *)image
+- (void)didReceiveImage:(UIImage *)image fromObserver:(void*)observer
{
+ std::static_pointer_cast<const ImageEventEmitter>(_eventEmitter)->onLoad();
+
const auto &imageProps = *std::static_pointer_cast<const ImageProps>(_props);
if (imageProps.tintColor) {
@@ -106,11 +137,22 @@
resizingMode:UIImageResizingModeStretch];
}
- _imageView.image = image;
+ self->_imageView.image = image;
// Apply trilinear filtering to smooth out mis-sized images.
- _imageView.layer.minificationFilter = kCAFilterTrilinear;
- _imageView.layer.magnificationFilter = kCAFilterTrilinear;
+ self->_imageView.layer.minificationFilter = kCAFilterTrilinear;
+ self->_imageView.layer.magnificationFilter = kCAFilterTrilinear;
+
+ std::static_pointer_cast<const ImageEventEmitter>(self->_eventEmitter)->onLoadEnd();
+}
+
+- (void)didReceiveProgress:(float)progress fromObserver:(void*)observer {
+ std::static_pointer_cast<const ImageEventEmitter>(_eventEmitter)->onProgress(progress);
}
+- (void)didReceiveFailureFromObserver:(void*)observer {
+ std::static_pointer_cast<const ImageEventEmitter>(_eventEmitter)->onError();
+}
+
+
@end

React/Fabric/Mounting/ComponentViews/Root/RCTRootComponentView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Fabric/Mounting/ComponentViews/Root/RCTRootComponentView.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,6 +7,26 @@
#import "RCTRootComponentView.h"
+#import <react/components/root/RootShadowNode.h>
+#import <react/components/root/RootProps.h>
+
+using namespace facebook::react;
+
@implementation RCTRootComponentView
+- (instancetype)initWithFrame:(CGRect)frame
+{
+ if (self = [super initWithFrame:frame]) {
+ static const auto defaultProps = std::make_shared<const RootProps>();
+ _props = defaultProps;
+ }
+
+ return self;
+}
+
++ (ComponentHandle)componentHandle
+{
+ return RootShadowNode::Handle();
+}
+
@end

React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -8,10 +8,11 @@
#import "RCTScrollViewComponentView.h"
#import <React/RCTAssert.h>
-#import <fabric/components/scrollview/ScrollViewLocalData.h>
-#import <fabric/components/scrollview/ScrollViewProps.h>
-#import <fabric/components/scrollview/ScrollViewEventEmitter.h>
-#import <fabric/graphics/Geometry.h>
+#import <react/components/scrollview/ScrollViewShadowNode.h>
+#import <react/components/scrollview/ScrollViewLocalData.h>
+#import <react/components/scrollview/ScrollViewProps.h>
+#import <react/components/scrollview/ScrollViewEventEmitter.h>
+#import <react/graphics/Geometry.h>
#import "RCTConversions.h"
#import "RCTEnhancedScrollView.h"
@@ -33,6 +34,9 @@
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
+ static const auto defaultProps = std::make_shared<const ScrollViewProps>();
+ _props = defaultProps;
+
_scrollView = [[RCTEnhancedScrollView alloc] initWithFrame:self.bounds];
_scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_scrollView.delegate = self;
@@ -45,19 +49,19 @@
return self;
}
-#pragma mark - ComponentViewProtocol
+#pragma mark - RCTComponentViewProtocol
-- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps
++ (ComponentHandle)componentHandle
{
- [super updateProps:props oldProps:oldProps];
+ return ScrollViewShadowNode::Handle();
+}
- if (!oldProps) {
- oldProps = _props ?: std::make_shared<ScrollViewProps>();
- }
- _props = props;
+- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps
+{
+ const auto &oldScrollViewProps = *std::static_pointer_cast<const ScrollViewProps>(oldProps ?: _props);
+ const auto &newScrollViewProps = *std::static_pointer_cast<const ScrollViewProps>(props);
- auto oldScrollViewProps = *std::dynamic_pointer_cast<const ScrollViewProps>(oldProps);
- auto newScrollViewProps = *std::dynamic_pointer_cast<const ScrollViewProps>(props);
+ [super updateProps:props oldProps:oldProps];
#define REMAP_PROP(reactName, localName, target) \
if (oldScrollViewProps.reactName != newScrollViewProps.reactName) { \

React/Fabric/Mounting/ComponentViews/Slider/RCTSliderComponentView.h

@@ -0,0 +1,21 @@
+/**
+ * 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.
+ */
+
+#import <UIKit/UIKit.h>
+
+#import <React/RCTViewComponentView.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * UIView class for root <Slider> component.
+ */
+@interface RCTSliderComponentView : RCTViewComponentView
+
+@end
+
+NS_ASSUME_NONNULL_END

React/Fabric/Mounting/ComponentViews/Slider/RCTSliderComponentView.mm

@@ -0,0 +1,335 @@
+/**
+ * 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.
+ */
+
+#import "RCTSliderComponentView.h"
+
+#import <react/components/slider/SliderEventEmitter.h>
+#import <react/components/slider/SliderProps.h>
+#import <react/components/slider/SliderShadowNode.h>
+#import <react/components/slider/SliderLocalData.h>
+#import <React/RCTImageResponseObserverProxy.h>
+
+#import "MainQueueExecutor.h"
+
+using namespace facebook::react;
+
+@implementation RCTSliderComponentView {
+ UISlider *_sliderView;
+ float _previousValue;
+ SharedSliderLocalData _sliderLocalData;
+
+ UIImage *_trackImage;
+ UIImage *_minimumTrackImage;
+ UIImage *_maximumTrackImage;
+ UIImage *_thumbImage;
+
+ const ImageResponseObserverCoordinator *_trackImageCoordinator;
+ const ImageResponseObserverCoordinator *_minimumTrackImageCoordinator;
+ const ImageResponseObserverCoordinator *_maximumTrackImageCoordinator;
+ const ImageResponseObserverCoordinator *_thumbImageCoordinator;
+
+ std::unique_ptr<RCTImageResponseObserverProxy> _trackImageResponseObserverProxy;
+ std::unique_ptr<RCTImageResponseObserverProxy> _minimumTrackImageResponseObserverProxy;
+ std::unique_ptr<RCTImageResponseObserverProxy> _maximumTrackImageResponseObserverProxy;
+ std::unique_ptr<RCTImageResponseObserverProxy> _thumbImageResponseObserverProxy;
+}
+
+
+- (instancetype)initWithFrame:(CGRect)frame
+{
+ if (self = [super initWithFrame:frame]) {
+ static const auto defaultProps = std::make_shared<const SliderProps>();
+ _props = defaultProps;
+
+ _sliderView = [[UISlider alloc] initWithFrame:self.bounds];
+
+ [_sliderView addTarget:self
+ action:@selector(onChange:)
+ forControlEvents:UIControlEventValueChanged];
+ [_sliderView addTarget:self
+ action:@selector(sliderTouchEnd:)
+ forControlEvents:(UIControlEventTouchUpInside |
+ UIControlEventTouchUpOutside |
+ UIControlEventTouchCancel)];
+
+ _sliderView.value = defaultProps->value;
+
+ _trackImageResponseObserverProxy = std::make_unique<RCTImageResponseObserverProxy>((__bridge void *)self);
+ _minimumTrackImageResponseObserverProxy = std::make_unique<RCTImageResponseObserverProxy>((__bridge void *)self);
+ _maximumTrackImageResponseObserverProxy = std::make_unique<RCTImageResponseObserverProxy>((__bridge void *)self);
+ _thumbImageResponseObserverProxy = std::make_unique<RCTImageResponseObserverProxy>((__bridge void *)self);
+
+ self.contentView = _sliderView;
+ }
+
+ return self;
+}
+
+// Recycling still doesn't work 100% properly
+// TODO: T40099998 implement recycling properly for Fabric Slider component
+- (void)prepareForRecycle
+{
+ [super prepareForRecycle];
+
+ self.trackImageCoordinator = nullptr;
+ self.minimumTrackImageCoordinator = nullptr;
+ self.maximumTrackImageCoordinator = nullptr;
+ self.thumbImageCoordinator = nullptr;
+
+ _sliderLocalData.reset();
+
+ // Tint colors will be taken care of when props are set again - we just
+ // need to make sure that image properties are reset here
+ [_sliderView setMinimumTrackImage:nil forState:UIControlStateNormal];
+ [_sliderView setMaximumTrackImage:nil forState:UIControlStateNormal];
+ [_sliderView setThumbImage:nil forState:UIControlStateNormal];
+
+ _trackImage = nil;
+ _minimumTrackImage = nil;
+ _maximumTrackImage = nil;
+ _thumbImage = nil;
+}
+
+-(void)dealloc
+{
+ self.trackImageCoordinator = nullptr;
+ self.minimumTrackImageCoordinator = nullptr;
+ self.maximumTrackImageCoordinator = nullptr;
+ self.thumbImageCoordinator = nullptr;
+
+ _trackImageResponseObserverProxy.reset();
+ _minimumTrackImageResponseObserverProxy.reset();
+ _maximumTrackImageResponseObserverProxy.reset();
+ _thumbImageResponseObserverProxy.reset();
+}
+
+#pragma mark - RCTComponentViewProtocol
+
++ (ComponentHandle)componentHandle
+{
+ return SliderShadowNode::Handle();
+}
+
+- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps
+{
+ const auto &oldSliderProps = *std::static_pointer_cast<const SliderProps>(oldProps ?: _props);
+ const auto &newSliderProps = *std::static_pointer_cast<const SliderProps>(props);
+
+ [super updateProps:props oldProps:oldProps];
+
+ // `value`
+ if (oldSliderProps.value != newSliderProps.value) {
+ _sliderView.value = newSliderProps.value;
+ _previousValue = newSliderProps.value;
+ }
+
+ // `minimumValue`
+ if (oldSliderProps.minimumValue != newSliderProps.minimumValue) {
+ _sliderView.minimumValue = newSliderProps.minimumValue;
+ }
+
+ // `maximumValue`
+ if (oldSliderProps.maximumValue != newSliderProps.maximumValue) {
+ _sliderView.maximumValue = newSliderProps.maximumValue;
+ }
+
+ // `disabled`
+ if (oldSliderProps.disabled != newSliderProps.disabled) {
+ _sliderView.enabled = !newSliderProps.disabled;
+ }
+
+ // `thumbTintColor`
+ if (oldSliderProps.thumbTintColor != newSliderProps.thumbTintColor) {
+ _sliderView.thumbTintColor = [UIColor colorWithCGColor:newSliderProps.thumbTintColor.get()];
+ }
+
+ // `minimumTrackTintColor`
+ if (oldSliderProps.minimumTrackTintColor != newSliderProps.minimumTrackTintColor) {
+ _sliderView.minimumTrackTintColor = [UIColor colorWithCGColor:newSliderProps.minimumTrackTintColor.get()];
+ }
+
+ // `maximumTrackTintColor`
+ if (oldSliderProps.maximumTrackTintColor != newSliderProps.maximumTrackTintColor) {
+ _sliderView.maximumTrackTintColor = [UIColor colorWithCGColor:newSliderProps.maximumTrackTintColor.get()];
+ }
+}
+
+- (void)updateLocalData:(SharedLocalData)localData
+ oldLocalData:(SharedLocalData)oldLocalData
+{
+ SharedSliderLocalData previousData = _sliderLocalData;
+ _sliderLocalData = std::static_pointer_cast<const SliderLocalData>(localData);
+ assert(_sliderLocalData);
+ bool havePreviousData = previousData != nullptr;
+
+ if (!havePreviousData || _sliderLocalData->getTrackImageSource() != previousData->getTrackImageSource()) {
+ self.trackImageCoordinator = _sliderLocalData->getTrackImageRequest().getObserverCoordinator();
+ }
+ if (!havePreviousData || _sliderLocalData->getMinimumTrackImageSource() != previousData->getMinimumTrackImageSource()) {
+ self.minimumTrackImageCoordinator = _sliderLocalData->getMinimumTrackImageRequest().getObserverCoordinator();
+ }
+ if (!havePreviousData || _sliderLocalData->getMaximumTrackImageSource() != previousData->getMaximumTrackImageSource()) {
+ self.maximumTrackImageCoordinator = _sliderLocalData->getMaximumTrackImageRequest().getObserverCoordinator();
+ }
+ if (!havePreviousData || _sliderLocalData->getThumbImageSource() != previousData->getThumbImageSource()) {
+ self.thumbImageCoordinator = _sliderLocalData->getThumbImageRequest().getObserverCoordinator();
+ }
+}
+
+- (void)setTrackImageCoordinator:(const ImageResponseObserverCoordinator *)coordinator {
+ if (_trackImageCoordinator) {
+ _trackImageCoordinator->removeObserver(_trackImageResponseObserverProxy.get());
+ }
+ _trackImageCoordinator = coordinator;
+ if (_trackImageCoordinator) {
+ _trackImageCoordinator->addObserver(_trackImageResponseObserverProxy.get());
+ }
+}
+
+- (void)setMinimumTrackImageCoordinator:(const ImageResponseObserverCoordinator *)coordinator {
+ if (_minimumTrackImageCoordinator) {
+ _minimumTrackImageCoordinator->removeObserver(_minimumTrackImageResponseObserverProxy.get());
+ }
+ _minimumTrackImageCoordinator = coordinator;
+ if (_minimumTrackImageCoordinator) {
+ _minimumTrackImageCoordinator->addObserver(_minimumTrackImageResponseObserverProxy.get());
+ }
+}
+
+- (void)setMaximumTrackImageCoordinator:(const ImageResponseObserverCoordinator *)coordinator {
+ if (_maximumTrackImageCoordinator) {
+ _maximumTrackImageCoordinator->removeObserver(_maximumTrackImageResponseObserverProxy.get());
+ }
+ _maximumTrackImageCoordinator = coordinator;
+ if (_maximumTrackImageCoordinator) {
+ _maximumTrackImageCoordinator->addObserver(_maximumTrackImageResponseObserverProxy.get());
+ }
+}
+
+- (void)setThumbImageCoordinator:(const ImageResponseObserverCoordinator *)coordinator {
+ if (_thumbImageCoordinator) {
+ _thumbImageCoordinator->removeObserver(_thumbImageResponseObserverProxy.get());
+ }
+ _thumbImageCoordinator = coordinator;
+ if (_thumbImageCoordinator) {
+ _thumbImageCoordinator->addObserver(_thumbImageResponseObserverProxy.get());
+ }
+}
+
+- (void)setTrackImage:(UIImage *)trackImage {
+ if ([trackImage isEqual:_trackImage]) {
+ return;
+ }
+
+ _trackImage = trackImage;
+ _minimumTrackImage = nil;
+ _maximumTrackImage = nil;
+ CGFloat width = trackImage.size.width / 2;
+ UIImage *minimumTrackImage = [trackImage resizableImageWithCapInsets:(UIEdgeInsets){
+ 0, width, 0, width
+ } resizingMode:UIImageResizingModeStretch];
+ UIImage *maximumTrackImage = [trackImage resizableImageWithCapInsets:(UIEdgeInsets){
+ 0, width, 0, width
+ } resizingMode:UIImageResizingModeStretch];
+ [_sliderView setMinimumTrackImage:minimumTrackImage forState:UIControlStateNormal];
+ [_sliderView setMaximumTrackImage:maximumTrackImage forState:UIControlStateNormal];
+}
+
+-(void)setMinimumTrackImage:(UIImage *)minimumTrackImage {
+ if ([minimumTrackImage isEqual:_minimumTrackImage] && _trackImage == nil) {
+ return;
+ }
+
+ _trackImage = nil;
+ _minimumTrackImage = minimumTrackImage;
+ _minimumTrackImage = [_minimumTrackImage resizableImageWithCapInsets:(UIEdgeInsets) {
+ 0, _minimumTrackImage.size.width, 0, 0
+ } resizingMode:UIImageResizingModeStretch];
+ [_sliderView setMinimumTrackImage:_minimumTrackImage forState:UIControlStateNormal];
+}
+
+-(void)setMaximumTrackImage:(UIImage *)maximumTrackImage {
+ if ([maximumTrackImage isEqual:_maximumTrackImage] && _trackImage == nil) {
+ return;
+ }
+
+ _trackImage = nil;
+ _maximumTrackImage = maximumTrackImage;
+ _maximumTrackImage = [_maximumTrackImage resizableImageWithCapInsets:(UIEdgeInsets) {
+ 0, 0, 0, _maximumTrackImage.size.width
+ } resizingMode:UIImageResizingModeStretch];
+ [_sliderView setMaximumTrackImage:_maximumTrackImage forState:UIControlStateNormal];
+}
+
+-(void)setThumbImage:(UIImage *)thumbImage {
+ if ([thumbImage isEqual:_thumbImage]) {
+ return;
+ }
+
+ _thumbImage = thumbImage;
+ [_sliderView setThumbImage:thumbImage forState:UIControlStateNormal];
+}
+
+- (void)onChange:(UISlider *)sender
+{
+ [self onChange:sender withContinuous:YES];
+}
+
+- (void)sliderTouchEnd:(UISlider *)sender
+{
+ [self onChange:sender withContinuous:NO];
+}
+
+- (void)onChange:(UISlider *)sender withContinuous:(BOOL)continuous
+{
+ float value = sender.value;
+
+ const auto &props = *std::static_pointer_cast<const SliderProps>(_props);
+
+ if (props.step > 0 && value <= (props.maximumValue - props.minimumValue)) {
+ value = MAX(props.minimumValue,
+ MIN(props.maximumValue,
+ props.minimumValue + round((value - props.minimumValue) / props.step) * props.step
+ )
+ );
+
+ [_sliderView setValue:value animated:YES];
+ }
+
+ if (continuous && _previousValue != value) {
+ std::dynamic_pointer_cast<const SliderEventEmitter>(_eventEmitter)->onValueChange(value);
+ }
+ if (!continuous) {
+ std::dynamic_pointer_cast<const SliderEventEmitter>(_eventEmitter)->onSlidingComplete(value);
+ }
+
+ _previousValue = value;
+}
+
+#pragma mark - RCTImageResponseDelegate
+
+- (void)didReceiveImage:(UIImage *)image fromObserver:(void *)observer
+{
+ if (observer == _trackImageResponseObserverProxy.get()) {
+ self.trackImage = image;
+ } else if (observer == _minimumTrackImageResponseObserverProxy.get()) {
+ self.minimumTrackImage = image;
+ } else if (observer == _maximumTrackImageResponseObserverProxy.get()) {
+ self.maximumTrackImage = image;
+ } else if (observer == _thumbImageResponseObserverProxy.get()) {
+ self.thumbImage = image;
+ }
+}
+
+- (void)didReceiveProgress:(float)progress fromObserver:(void *)observer {
+}
+
+- (void)didReceiveFailureFromObserver:(void *)observer {
+}
+
+
+@end

React/Fabric/Mounting/ComponentViews/Switch/RCTSwitchComponentView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Fabric/Mounting/ComponentViews/Switch/RCTSwitchComponentView.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,8 +7,9 @@
#import "RCTSwitchComponentView.h"
-#import <fabric/components/switch/SwitchEventEmitter.h>
-#import <fabric/components/switch/SwitchProps.h>
+#import <react/components/rncore/EventEmitters.h>
+#import <react/components/rncore/Props.h>
+#import <react/components/rncore/ShadowNodes.h>
using namespace facebook::react;
@@ -20,15 +21,16 @@
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
+ static const auto defaultProps = std::make_shared<const SwitchProps>();
+ _props = defaultProps;
+
_switchView = [[UISwitch alloc] initWithFrame:self.bounds];
[_switchView addTarget:self
action:@selector(onChange:)
forControlEvents:UIControlEventValueChanged];
- const auto &defaultProps = SwitchProps();
-
- _switchView.on = defaultProps.value;
+ _switchView.on = defaultProps->value;
self.contentView = _switchView;
}
@@ -36,18 +38,20 @@
return self;
}
+#pragma mark - RCTComponentViewProtocol
+
++ (ComponentHandle)componentHandle
+{
+ return SwitchShadowNode::Handle();
+}
+
- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps
{
- if (!oldProps) {
- oldProps = _props ?: std::make_shared<SwitchProps>();
- }
- _props = props;
+ const auto &oldSwitchProps = *std::static_pointer_cast<const SwitchProps>(oldProps ?: _props);
+ const auto &newSwitchProps = *std::static_pointer_cast<const SwitchProps>(props);
[super updateProps:props oldProps:oldProps];
- auto oldSwitchProps = *std::dynamic_pointer_cast<const SwitchProps>(oldProps);
- auto newSwitchProps = *std::dynamic_pointer_cast<const SwitchProps>(props);
-
// `value`
if (oldSwitchProps.value != newSwitchProps.value) {
_switchView.on = newSwitchProps.value;
@@ -82,7 +86,7 @@
}
_wasOn = sender.on;
- std::dynamic_pointer_cast<const SwitchEventEmitter>(_eventEmitter)->onChange(sender.on);
+ std::dynamic_pointer_cast<const SwitchEventEmitter>(_eventEmitter)->onChange(SwitchOnChangeStruct{.value=static_cast<bool>(sender.on)});
}
@end

React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,12 +7,13 @@
#import "RCTParagraphComponentView.h"
-#import <fabric/components/text/ParagraphLocalData.h>
-#import <fabric/components/text/ParagraphProps.h>
-#import <fabric/core/LocalData.h>
-#import <fabric/graphics/Geometry.h>
-#import <fabric/textlayoutmanager/TextLayoutManager.h>
-#import <fabric/textlayoutmanager/RCTTextLayoutManager.h>
+#import <react/components/text/ParagraphLocalData.h>
+#import <react/components/text/ParagraphProps.h>
+#import <react/components/text/ParagraphShadowNode.h>
+#import <react/core/LocalData.h>
+#import <react/graphics/Geometry.h>
+#import <react/textlayoutmanager/TextLayoutManager.h>
+#import <react/textlayoutmanager/RCTTextLayoutManager.h>
#import "RCTConversions.h"
using namespace facebook::react;
@@ -25,6 +26,9 @@
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
+ static const auto defaultProps = std::make_shared<const ParagraphProps>();
+ _props = defaultProps;
+
self.isAccessibilityElement = YES;
self.accessibilityTraits |= UIAccessibilityTraitStaticText;
self.opaque = NO;
@@ -34,10 +38,19 @@
return self;
}
+#pragma mark - RCTComponentViewProtocol
+
++ (ComponentHandle)componentHandle
+{
+ return ParagraphShadowNode::Handle();
+}
+
- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps
{
+ const auto &paragraphProps = std::static_pointer_cast<const ParagraphProps>(props);
+
[super updateProps:props oldProps:oldProps];
- auto paragraphProps = std::static_pointer_cast<const ParagraphProps>(props);
+
assert(paragraphProps);
_paragraphAttributes = paragraphProps->paragraphAttributes;
}
@@ -50,6 +63,12 @@
[self setNeedsDisplay];
}
+- (void)prepareForRecycle
+{
+ [super prepareForRecycle];
+ _paragraphLocalData.reset();
+}
+
- (void)drawRect:(CGRect)rect
{
if (!_paragraphLocalData) {
@@ -72,7 +91,8 @@
- (NSString *)accessibilityLabel
{
- NSString *superAccessibilityLabel = [super accessibilityLabel];
+ NSString *superAccessibilityLabel =
+ RCTNSStringFromStringNilIfEmpty(_props->accessibilityLabel);
if (superAccessibilityLabel) {
return superAccessibilityLabel;
}
@@ -84,4 +104,28 @@
return RCTNSStringFromString(_paragraphLocalData->getAttributedString().getString());
}
+- (SharedTouchEventEmitter)touchEventEmitterAtPoint:(CGPoint)point
+{
+ if (!_paragraphLocalData) {
+ return _eventEmitter;
+ }
+
+ SharedTextLayoutManager textLayoutManager = _paragraphLocalData->getTextLayoutManager();
+ RCTTextLayoutManager *nativeTextLayoutManager = (__bridge RCTTextLayoutManager *)textLayoutManager->getNativeTextLayoutManager();
+ CGRect frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame());
+
+ SharedEventEmitter eventEmitter =
+ [nativeTextLayoutManager getEventEmitterWithAttributeString:_paragraphLocalData->getAttributedString()
+ paragraphAttributes:_paragraphAttributes
+ frame:frame
+ atPoint:point];
+
+ if (!eventEmitter) {
+ return _eventEmitter;
+ }
+
+ assert(std::dynamic_pointer_cast<const TouchEventEmitter>(eventEmitter));
+ return std::static_pointer_cast<const TouchEventEmitter>(eventEmitter);
+}
+
@end

React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,20 +9,22 @@
#import <React/RCTComponentViewProtocol.h>
#import <React/UIView+ComponentViewProtocol.h>
-#import <fabric/core/LayoutMetrics.h>
-#import <fabric/core/Props.h>
-#import <fabric/components/view/ViewEventEmitter.h>
-#import <fabric/events/EventEmitter.h>
+#import <react/core/LayoutMetrics.h>
+#import <react/core/Props.h>
+#import <react/components/view/ViewEventEmitter.h>
+#import <react/components/view/ViewProps.h>
+#import <react/events/EventEmitter.h>
+#import <React/RCTTouchableComponentViewProtocol.h>
NS_ASSUME_NONNULL_BEGIN
/**
* UIView class for <View> component.
*/
-@interface RCTViewComponentView : UIView <RCTComponentViewProtocol> {
+@interface RCTViewComponentView : UIView <RCTComponentViewProtocol, RCTTouchableComponentViewProtocol> {
@protected
facebook::react::LayoutMetrics _layoutMetrics;
- facebook::react::SharedProps _props;
+ facebook::react::SharedViewProps _props;
facebook::react::SharedViewEventEmitter _eventEmitter;
}

React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,8 +7,12 @@
#import "RCTViewComponentView.h"
-#import <fabric/components/view/ViewProps.h>
-#import <fabric/components/view/ViewEventEmitter.h>
+#import <react/components/view/ViewShadowNode.h>
+#import <react/components/view/ViewProps.h>
+#import <react/components/view/ViewEventEmitter.h>
+#import <objc/runtime.h>
+#import <React/RCTAssert.h>
+#import <React/RCTBorderDrawing.h>
#import "RCTConversions.h"
@@ -16,7 +20,18 @@
@implementation RCTViewComponentView
{
- BOOL _isCoreAnimationBorderRenderingEnabled;
+ UIColor *_backgroundColor;
+ CALayer *_borderLayer;
+}
+
+- (instancetype)initWithFrame:(CGRect)frame
+{
+ if (self = [super initWithFrame:frame]) {
+ static const auto defaultProps = std::make_shared<const ViewProps>();
+ _props = defaultProps;
+ }
+
+ return self;
}
- (void)setContentView:(UIView *)contentView
@@ -36,6 +51,10 @@
{
[super layoutSubviews];
+ if (_borderLayer) {
+ _borderLayer.frame = self.layer.bounds;
+ }
+
if (_contentView) {
_contentView.frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame());
}
@@ -50,25 +69,59 @@
return CGRectContainsPoint(hitFrame, point);
}
+- (UIColor *)backgroundColor
+{
+ return _backgroundColor;
+}
+
+- (void)setBackgroundColor:(UIColor *)backgroundColor
+{
+ _backgroundColor = backgroundColor;
+}
+
+#pragma mark - RCTComponentViewProtocol
+
++ (ComponentHandle)componentHandle
+{
+ RCTAssert(
+ self == [RCTViewComponentView class],
+ @"`+[RCTComponentViewProtocol componentHandle]` must be implemented for all subclasses (and `%@` particularly).", NSStringFromClass([self class]));
+ return ViewShadowNode::Handle();
+}
+
- (void)updateProps:(SharedProps)props
oldProps:(SharedProps)oldProps
{
- if (!oldProps) {
- oldProps = _props ?: std::make_shared<ViewProps>();
- }
- _props = props;
+#ifndef NS_BLOCK_ASSERTIONS
+ auto propsRawPtr = _props.get();
+ RCTAssert(
+ propsRawPtr &&
+ (
+ [self class] == [RCTViewComponentView class] ||
+ typeid(*propsRawPtr).hash_code() != typeid(const ViewProps).hash_code()
+ ),
+ @"`RCTViewComponentView` subclasses (and `%@` particularly) must setup `_props`"
+ " instance variable with a default value in the constructor.", NSStringFromClass([self class])
+ );
+#endif
+
+ const auto &oldViewProps = *std::static_pointer_cast<const ViewProps>(oldProps ?: _props);
+ const auto &newViewProps = *std::static_pointer_cast<const ViewProps>(props);
+
+ _props = std::static_pointer_cast<const ViewProps>(props);
- auto oldViewProps = *std::dynamic_pointer_cast<const ViewProps>(oldProps);
- auto newViewProps = *std::dynamic_pointer_cast<const ViewProps>(props);
+ BOOL needsInvalidateLayer = NO;
// `opacity`
if (oldViewProps.opacity != newViewProps.opacity) {
self.layer.opacity = (CGFloat)newViewProps.opacity;
+ needsInvalidateLayer = YES;
}
// `backgroundColor`
if (oldViewProps.backgroundColor != newViewProps.backgroundColor) {
- self.backgroundColor = RCTUIColorFromSharedColor(newViewProps.backgroundColor);
+ _backgroundColor = RCTUIColorFromSharedColor(newViewProps.backgroundColor);
+ needsInvalidateLayer = YES;
}
// `foregroundColor`
@@ -81,21 +134,25 @@
CGColorRef shadowColor = RCTCGColorRefFromSharedColor(newViewProps.shadowColor);
self.layer.shadowColor = shadowColor;
CGColorRelease(shadowColor);
+ needsInvalidateLayer = YES;
}
// `shadowOffset`
if (oldViewProps.shadowOffset != newViewProps.shadowOffset) {
self.layer.shadowOffset = RCTCGSizeFromSize(newViewProps.shadowOffset);
+ needsInvalidateLayer = YES;
}
// `shadowOpacity`
if (oldViewProps.shadowOpacity != newViewProps.shadowOpacity) {
self.layer.shadowOpacity = (CGFloat)newViewProps.shadowOpacity;
+ needsInvalidateLayer = YES;
}
// `shadowRadius`
if (oldViewProps.shadowRadius != newViewProps.shadowRadius) {
self.layer.shadowRadius = (CGFloat)newViewProps.shadowRadius;
+ needsInvalidateLayer = YES;
}
// `backfaceVisibility`
@@ -128,6 +185,7 @@
// `overflow`
if (oldViewProps.yogaStyle.overflow != newViewProps.yogaStyle.overflow) {
self.clipsToBounds = newViewProps.yogaStyle.overflow != YGOverflowVisible;
+ needsInvalidateLayer = YES;
}
// `zIndex`
@@ -137,23 +195,60 @@
// `border`
if (
- oldViewProps.borderWidth != newViewProps.borderWidth ||
- oldViewProps.borderStyle != newViewProps.borderStyle ||
- oldViewProps.borderRadius != newViewProps.borderRadius ||
- oldViewProps.borderColor != newViewProps.borderColor
+ oldViewProps.borderStyles != newViewProps.borderStyles ||
+ oldViewProps.borderRadii != newViewProps.borderRadii ||
+ oldViewProps.borderColors != newViewProps.borderColors
) {
- [self invalidateBorder];
+ needsInvalidateLayer = YES;
}
// `nativeId`
if (oldViewProps.nativeId != newViewProps.nativeId) {
- self.nativeId = RCTNSStringFromString(newViewProps.nativeId);
+ self.nativeId = RCTNSStringFromStringNilIfEmpty(newViewProps.nativeId);
}
// `accessible`
if (oldViewProps.accessible != newViewProps.accessible) {
self.accessibilityElement.isAccessibilityElement = newViewProps.accessible;
}
+
+ // `accessibilityLabel`
+ if (oldViewProps.accessibilityLabel != newViewProps.accessibilityLabel) {
+ self.accessibilityElement.accessibilityLabel = RCTNSStringFromStringNilIfEmpty(newViewProps.accessibilityLabel);
+ }
+
+ // `accessibilityHint`
+ if (oldViewProps.accessibilityHint != newViewProps.accessibilityHint) {
+ self.accessibilityElement.accessibilityHint = RCTNSStringFromStringNilIfEmpty(newViewProps.accessibilityHint);
+ }
+
+ // `accessibilityTraits`
+ if (oldViewProps.accessibilityTraits != newViewProps.accessibilityTraits) {
+ self.accessibilityElement.accessibilityTraits = RCTUIAccessibilityTraitsFromAccessibilityTraits(newViewProps.accessibilityTraits);
+ }
+
+ // `accessibilityViewIsModal`
+ if (oldViewProps.accessibilityViewIsModal != newViewProps.accessibilityViewIsModal) {
+ self.accessibilityElement.accessibilityViewIsModal = newViewProps.accessibilityViewIsModal;
+ }
+
+ // `accessibilityElementsHidden`
+ if (oldViewProps.accessibilityElementsHidden != newViewProps.accessibilityElementsHidden) {
+ self.accessibilityElement.accessibilityElementsHidden = newViewProps.accessibilityElementsHidden;
+ }
+
+ // `accessibilityIgnoresInvertColors`
+ if (oldViewProps.accessibilityIgnoresInvertColors != newViewProps.accessibilityIgnoresInvertColors) {
+#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
+ if (@available(iOS 11.0, *)) {
+ self.accessibilityIgnoresInvertColors = newViewProps.accessibilityIgnoresInvertColors;
+ }
+#endif
+ }
+
+ if (needsInvalidateLayer) {
+ [self invalidateLayer];
+ }
}
- (void)updateEventEmitter:(SharedEventEmitter)eventEmitter
@@ -168,35 +263,226 @@
_layoutMetrics = layoutMetrics;
[super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics];
+
+ [self invalidateLayer];
+}
+
+- (void)prepareForRecycle
+{
+ [super prepareForRecycle];
+ _eventEmitter.reset();
+}
+
+- (UIView *)betterHitTest:(CGPoint)point withEvent:(UIEvent *)event
+{
+ // This is a classic textbook implementation of `hitTest:` with a couple of improvements:
+ // * It takes layers' `zIndex` property into an account;
+ // * It does not stop algorithm if some touch is outside the view
+ // which does not have `clipToBounds` enabled.
+
+ if (!self.userInteractionEnabled || self.hidden || self.alpha < 0.01) {
+ return nil;
+ }
+
+ BOOL isPointInside = [self pointInside:point withEvent:event];
+
+ if (self.clipsToBounds && !isPointInside) {
+ return nil;
+ }
+
+ NSArray<__kindof UIView *> *sortedSubviews =
+ [self.subviews sortedArrayUsingComparator:^NSComparisonResult(UIView *a, UIView *b) {
+ // Ensure sorting is stable by treating equal `zIndex` as ascending so
+ // that original order is preserved.
+ return a.layer.zPosition > b.layer.zPosition ? NSOrderedDescending : NSOrderedAscending;
+ }];
+
+ for (UIView *subview in [sortedSubviews reverseObjectEnumerator]) {
+ UIView *hitView = [subview hitTest:[subview convertPoint:point fromView:self] withEvent:event];
+ if (hitView) {
+ return hitView;
+ }
+ }
+
+ return isPointInside ? self : nil;
}
-- (void)invalidateBorder
+- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
- const auto &props = *std::dynamic_pointer_cast<const ViewProps>(_props);
+ switch (_props->pointerEvents) {
+ case PointerEventsMode::Auto:
+ return [self betterHitTest:point withEvent:event];
+ case PointerEventsMode::None:
+ return nil;
+ case PointerEventsMode::BoxOnly:
+ return [self pointInside:point withEvent:event] ? self : nil;
+ case PointerEventsMode::BoxNone:
+ UIView *view = [self betterHitTest:point withEvent:event];
+ return view != self ? view : nil;
+ }
+}
+
+static RCTCornerRadii RCTCornerRadiiFromBorderRadii(BorderRadii borderRadii) {
+ return RCTCornerRadii {
+ .topLeft = (CGFloat)borderRadii.topLeft,
+ .topRight = (CGFloat)borderRadii.topRight,
+ .bottomLeft = (CGFloat)borderRadii.bottomLeft,
+ .bottomRight = (CGFloat)borderRadii.bottomRight
+ };
+}
+
+static RCTBorderColors RCTBorderColorsFromBorderColors(BorderColors borderColors) {
+ return RCTBorderColors {
+ .left = RCTCGColorRefFromSharedColor(borderColors.left),
+ .top = RCTCGColorRefFromSharedColor(borderColors.top),
+ .bottom = RCTCGColorRefFromSharedColor(borderColors.bottom),
+ .right = RCTCGColorRefFromSharedColor(borderColors.right)
+ };
+}
+
+static UIEdgeInsets UIEdgeInsetsFromBorderInsets(EdgeInsets edgeInsets) {
+ return UIEdgeInsets {
+ .left = (CGFloat)edgeInsets.left,
+ .top = (CGFloat)edgeInsets.top,
+ .bottom = (CGFloat)edgeInsets.bottom,
+ .right = (CGFloat)edgeInsets.right
+ };
+}
- bool useCoreAnimationBorderRendering =
- props.borderStyle == BorderStyle::Solid &&
- props.borderWidth.isUniform() &&
- props.borderRadius.isUniform();
+static RCTBorderStyle RCTBorderStyleFromBorderStyle(BorderStyle borderStyle) {
+ switch (borderStyle) {
+ case BorderStyle::Solid:
+ return RCTBorderStyleSolid;
+ case BorderStyle::Dotted:
+ return RCTBorderStyleDotted;
+ case BorderStyle::Dashed:
+ return RCTBorderStyleDashed;
+ }
+}
+
+- (void)invalidateLayer
+{
+ const auto borderMetrics =
+ _props->resolveBorderMetrics(_layoutMetrics.layoutDirection == LayoutDirection::RightToLeft);
CALayer *layer = self.layer;
- if (_isCoreAnimationBorderRenderingEnabled != useCoreAnimationBorderRendering) {
- _isCoreAnimationBorderRenderingEnabled = useCoreAnimationBorderRendering;
- if (!useCoreAnimationBorderRendering) {
+
+ // Stage 1. Shadow Path
+ BOOL layerHasShadow = layer.shadowOpacity > 0 && CGColorGetAlpha(layer.shadowColor) > 0;
+ if (layerHasShadow) {
+ if (CGColorGetAlpha(_backgroundColor.CGColor) > 0.999) {
+ // If view has a solid background color, calculate shadow path from border.
+ const RCTCornerInsets cornerInsets =
+ RCTGetCornerInsets(RCTCornerRadiiFromBorderRadii(borderMetrics.borderRadii), UIEdgeInsetsZero);
+ CGPathRef shadowPath = RCTPathCreateWithRoundedRect(self.bounds, cornerInsets, nil);
+ layer.shadowPath = shadowPath;
+ CGPathRelease(shadowPath);
+ } else {
+ // Can't accurately calculate box shadow, so fall back to pixel-based shadow.
+ layer.shadowPath = nil;
+ }
+ } else {
+ layer.shadowPath = nil;
+ }
+
+ // Stage 2. Border Rendering
+ const bool useCoreAnimationBorderRendering =
+ borderMetrics.borderColors.isUniform() &&
+ borderMetrics.borderWidths.isUniform() &&
+ borderMetrics.borderStyles.isUniform() &&
+ borderMetrics.borderRadii.isUniform() &&
+ borderMetrics.borderStyles.left == BorderStyle::Solid &&
+ (
+ // iOS draws borders in front of the content whereas CSS draws them behind
+ // the content. For this reason, only use iOS border drawing when clipping
+ // or when the border is hidden.
+ borderMetrics.borderWidths.left == 0 ||
+ colorComponentsFromColor(borderMetrics.borderColors.left).alpha == 0 ||
+ self.clipsToBounds
+ );
+
+ if (useCoreAnimationBorderRendering) {
+ if (_borderLayer) {
+ [_borderLayer removeFromSuperlayer];
+ _borderLayer = nil;
+ }
+
+ layer.borderWidth = (CGFloat)borderMetrics.borderWidths.left;
+ layer.borderColor = RCTCGColorRefFromSharedColor(borderMetrics.borderColors.left);
+ layer.cornerRadius = (CGFloat)borderMetrics.borderRadii.topLeft;
+ layer.backgroundColor = _backgroundColor.CGColor;
+ _contentView.layer.cornerRadius = (CGFloat)borderMetrics.borderRadii.topLeft;
+ _contentView.layer.masksToBounds = YES;
+ } else {
+ if (!_borderLayer) {
+ _borderLayer = [[CALayer alloc] init];
+ _borderLayer.zPosition = -1024.0f;
+ _borderLayer.frame = layer.bounds;
+ _borderLayer.magnificationFilter = kCAFilterNearest;
+ [layer addSublayer:_borderLayer];
+ }
+
+ layer.backgroundColor = nil;
layer.borderWidth = 0;
layer.borderColor = nil;
layer.cornerRadius = 0;
+ _contentView.layer.cornerRadius = 0;
+ _contentView.layer.masksToBounds = NO;
+
+ UIImage *image = RCTGetBorderImage(
+ RCTBorderStyleFromBorderStyle(borderMetrics.borderStyles.left),
+ layer.bounds.size,
+ RCTCornerRadiiFromBorderRadii(borderMetrics.borderRadii),
+ UIEdgeInsetsFromBorderInsets(borderMetrics.borderWidths),
+ RCTBorderColorsFromBorderColors(borderMetrics.borderColors),
+ _backgroundColor.CGColor,
+ self.clipsToBounds
+ );
+
+ if (image == nil) {
+ _borderLayer.contents = nil;
+ } else {
+ CGSize imageSize = image.size;
+ UIEdgeInsets imageCapInsets = image.capInsets;
+ CGRect contentsCenter = CGRect {
+ CGPoint {imageCapInsets.left / imageSize.width, imageCapInsets.top / imageSize.height},
+ CGSize {(CGFloat)1.0 / imageSize.width, (CGFloat)1.0 / imageSize.height}
+ };
+
+ _borderLayer.contents = (id)image.CGImage;
+ _borderLayer.contentsScale = image.scale;
+
+ const BOOL isResizable = !UIEdgeInsetsEqualToEdgeInsets(image.capInsets, UIEdgeInsetsZero);
+ if (isResizable) {
+ _borderLayer.contentsCenter = contentsCenter;
+ } else {
+ _borderLayer.contentsCenter = CGRect { CGPoint {0.0, 0.0}, CGSize {1.0, 1.0}};
}
}
- if (useCoreAnimationBorderRendering) {
- layer.borderWidth = (CGFloat)props.borderWidth.left;
- layer.borderColor = RCTCGColorRefFromSharedColor(props.borderColor);
- layer.cornerRadius = (CGFloat)props.borderRadius.topLeft;
- _contentView.layer.cornerRadius = (CGFloat)props.borderRadius.topLeft;
- _contentView.layer.masksToBounds = YES;
+ // Stage 2.5. Custom Clipping Mask
+ CAShapeLayer *maskLayer = nil;
+ CGFloat cornerRadius = 0;
+ if (self.clipsToBounds) {
+ if (borderMetrics.borderRadii.isUniform()) {
+ // In this case we can simply use `cornerRadius` exclusivly.
+ cornerRadius = borderMetrics.borderRadii.topLeft;
} else {
- // Not supported yet.
+ // In this case we have to generate masking layer manually.
+ CGPathRef path = RCTPathCreateWithRoundedRect(
+ self.bounds,
+ RCTGetCornerInsets(RCTCornerRadiiFromBorderRadii(borderMetrics.borderRadii), UIEdgeInsetsZero),
+ nil
+ );
+
+ maskLayer = [CAShapeLayer layer];
+ maskLayer.path = path;
+ CGPathRelease(path);
+ }
+ }
+
+ layer.cornerRadius = cornerRadius;
+ layer.mask = maskLayer;
}
}
@@ -207,18 +493,46 @@
return self;
}
+static NSString *RCTRecursiveAccessibilityLabel(UIView *view)
+{
+ NSMutableString *result = [NSMutableString stringWithString:@""];
+ for (UIView *subview in view.subviews) {
+ NSString *label = subview.accessibilityLabel;
+ if (!label) {
+ label = RCTRecursiveAccessibilityLabel(subview);
+ }
+ if (label && label.length > 0) {
+ if (result.length > 0) {
+ [result appendString:@" "];
+ }
+ [result appendString:label];
+ }
+ }
+ return result;
+}
+
+- (NSString *)accessibilityLabel
+{
+ NSString *label = super.accessibilityLabel;
+ if (label) {
+ return label;
+ }
+
+ return RCTRecursiveAccessibilityLabel(self);
+}
+
#pragma mark - Accessibility Events
- (NSArray<UIAccessibilityCustomAction *> *)accessibilityCustomActions
{
- const auto &accessibilityProps = *std::dynamic_pointer_cast<const AccessibilityProps>(_props);
+ const auto &accessibilityActions = _props->accessibilityActions;
- if (accessibilityProps.accessibilityActions.size() == 0) {
+ if (accessibilityActions.size() == 0) {
return nil;
}
NSMutableArray<UIAccessibilityCustomAction *> *customActions = [NSMutableArray array];
- for (const auto &accessibilityAction : accessibilityProps.accessibilityActions) {
+ for (const auto &accessibilityAction : accessibilityActions) {
[customActions addObject:[[UIAccessibilityCustomAction alloc] initWithName:RCTNSStringFromString(accessibilityAction)
target:self
selector:@selector(didActivateAccessibilityCustomAction:)]];
@@ -239,13 +553,19 @@
return YES;
}
+- (BOOL)accessibilityPerformEscape
+{
+ _eventEmitter->onAccessibilityEscape();
+ return YES;
+}
+
- (BOOL)didActivateAccessibilityCustomAction:(UIAccessibilityCustomAction *)action
{
_eventEmitter->onAccessibilityAction(RCTStringFromNSString(action.name));
return YES;
}
-- (SharedEventEmitter)touchEventEmitter
+- (SharedTouchEventEmitter)touchEventEmitterAtPoint:(CGPoint)point
{
return _eventEmitter;
}

React/Fabric/Mounting/MountItems/RCTCreateMountItem.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,6 +7,7 @@
#import <UIKit/UIKit.h>
+#import <react/core/ReactPrimitives.h>
#import <React/RCTMountItemProtocol.h>
#import <React/RCTPrimitives.h>
@@ -19,7 +20,7 @@
*/
@interface RCTCreateMountItem : NSObject <RCTMountItemProtocol>
-- (instancetype)initWithComponentName:(NSString *)componentName
+- (instancetype)initWithComponentHandle:(facebook::react::ComponentHandle)componentHandle
tag:(ReactTag)tag;
@end

React/Fabric/Mounting/MountItems/RCTCreateMountItem.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,16 +9,18 @@
#import "RCTComponentViewRegistry.h"
+using namespace facebook::react;
+
@implementation RCTCreateMountItem {
- NSString *_componentName;
+ ComponentHandle _componentHandle;
ReactTag _tag;
}
-- (instancetype)initWithComponentName:(NSString *)componentName
+- (instancetype)initWithComponentHandle:(facebook::react::ComponentHandle)componentHandle
tag:(ReactTag)tag
{
if (self = [super init]) {
- _componentName = componentName;
+ _componentHandle = componentHandle;
_tag = tag;
}
@@ -27,7 +29,7 @@
- (void)executeWithRegistry:(RCTComponentViewRegistry *)registry
{
- [registry dequeueComponentViewWithName:_componentName tag:_tag];
+ [registry dequeueComponentViewWithComponentHandle:_componentHandle tag:_tag];
}
@end

React/Fabric/Mounting/MountItems/RCTDeleteMountItem.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,6 +7,7 @@
#import <UIKit/UIKit.h>
+#import <react/core/ReactPrimitives.h>
#import <React/RCTMountItemProtocol.h>
#import <React/RCTPrimitives.h>
@@ -17,7 +18,7 @@
*/
@interface RCTDeleteMountItem : NSObject <RCTMountItemProtocol>
-- (instancetype)initWithComponentName:(NSString *)componentName
+- (instancetype)initWithComponentHandle:(facebook::react::ComponentHandle)componentHandle
tag:(ReactTag)tag;
@end

React/Fabric/Mounting/MountItems/RCTDeleteMountItem.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,16 +9,18 @@
#import "RCTComponentViewRegistry.h"
+using namespace facebook::react;
+
@implementation RCTDeleteMountItem {
- NSString *_componentName;
+ ComponentHandle _componentHandle;
ReactTag _tag;
}
-- (instancetype)initWithComponentName:(NSString *)componentName
+- (instancetype)initWithComponentHandle:(facebook::react::ComponentHandle)componentHandle
tag:(ReactTag)tag
{
if (self = [super init]) {
- _componentName = componentName;
+ _componentHandle = componentHandle;
_tag = tag;
}
@@ -33,7 +35,7 @@
return;
}
- [registry enqueueComponentViewWithName:_componentName tag:_tag componentView:componentView];
+ [registry enqueueComponentViewWithComponentHandle:_componentHandle tag:_tag componentView:componentView];
}
@end

React/Fabric/Mounting/MountItems/RCTInsertMountItem.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Fabric/Mounting/MountItems/RCTInsertMountItem.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Fabric/Mounting/MountItems/RCTMountItemProtocol.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Fabric/Mounting/MountItems/RCTRemoveMountItem.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Fabric/Mounting/MountItems/RCTRemoveMountItem.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Fabric/Mounting/MountItems/RCTUpdateEventEmitterMountItem.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,7 +9,7 @@
#import <React/RCTMountItemProtocol.h>
#import <React/RCTPrimitives.h>
-#import <fabric/events/EventEmitter.h>
+#import <react/events/EventEmitter.h>
NS_ASSUME_NONNULL_BEGIN

React/Fabric/Mounting/MountItems/RCTUpdateEventEmitterMountItem.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Fabric/Mounting/MountItems/RCTUpdateLayoutMetricsMountItem.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,7 +9,7 @@
#import <React/RCTMountItemProtocol.h>
#import <React/RCTPrimitives.h>
-#import <fabric/core/LayoutMetrics.h>
+#import <react/core/LayoutMetrics.h>
NS_ASSUME_NONNULL_BEGIN

React/Fabric/Mounting/MountItems/RCTUpdateLayoutMetricsMountItem.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Fabric/Mounting/MountItems/RCTUpdateLocalDataMountItem.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,7 +9,7 @@
#import <React/RCTMountItemProtocol.h>
#import <React/RCTPrimitives.h>
-#import <fabric/core/LocalData.h>
+#import <react/core/LocalData.h>
NS_ASSUME_NONNULL_BEGIN

React/Fabric/Mounting/MountItems/RCTUpdateLocalDataMountItem.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Fabric/Mounting/MountItems/RCTUpdatePropsMountItem.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,7 +9,7 @@
#import <React/RCTMountItemProtocol.h>
#import <React/RCTPrimitives.h>
-#import <fabric/core/Props.h>
+#import <react/core/Props.h>
NS_ASSUME_NONNULL_BEGIN

React/Fabric/Mounting/MountItems/RCTUpdatePropsMountItem.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Fabric/Mounting/RCTComponentViewFactory.h

@@ -0,0 +1,38 @@
+/**
+ * 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.
+ */
+
+#import <UIKit/UIKit.h>
+
+#import <React/RCTComponentViewProtocol.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * Registry of supported component view classes that can instantiate
+ * view component instances by given component handle.
+ */
+@interface RCTComponentViewFactory : NSObject
+
+/**
+ * Constructs and returns an instance of the class with a bunch of already registered standard components.
+ */
++ (RCTComponentViewFactory *)standardComponentViewFactory;
+
+/**
+ * Registers a component view class in the factory.
+ */
+- (void)registerComponentViewClass:(Class<RCTComponentViewProtocol>)componentViewClass;
+
+/**
+ * Creates a component view with given component handle.
+ */
+- (UIView<RCTComponentViewProtocol> *)createComponentViewWithComponentHandle:
+ (facebook::react::ComponentHandle)componentHandle;
+
+@end
+
+NS_ASSUME_NONNULL_END

React/Fabric/Mounting/RCTComponentViewFactory.mm

@@ -0,0 +1,69 @@
+/**
+ * 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.
+ */
+
+#import "RCTComponentViewFactory.h"
+
+#import <React/RCTAssert.h>
+#import <react/core/ReactPrimitives.h>
+
+#import "RCTActivityIndicatorViewComponentView.h"
+#import "RCTImageComponentView.h"
+#import "RCTParagraphComponentView.h"
+#import "RCTRootComponentView.h"
+#import "RCTScrollViewComponentView.h"
+#import "RCTSliderComponentView.h"
+#import "RCTSwitchComponentView.h"
+#import "RCTViewComponentView.h"
+
+using namespace facebook::react;
+
+@implementation RCTComponentViewFactory {
+ std::unordered_map<ComponentHandle, Class<RCTComponentViewProtocol>> _registry;
+}
+
++ (RCTComponentViewFactory *)standardComponentViewFactory
+{
+ RCTAssertMainQueue();
+
+ RCTComponentViewFactory *componentViewFactory = [[RCTComponentViewFactory alloc] init];
+
+ [componentViewFactory registerComponentViewClass:[RCTViewComponentView class]];
+ [componentViewFactory registerComponentViewClass:[RCTRootComponentView class]];
+ [componentViewFactory registerComponentViewClass:[RCTScrollViewComponentView class]];
+ [componentViewFactory registerComponentViewClass:[RCTImageComponentView class]];
+ [componentViewFactory registerComponentViewClass:[RCTParagraphComponentView class]];
+ [componentViewFactory registerComponentViewClass:[RCTActivityIndicatorViewComponentView class]];
+ [componentViewFactory registerComponentViewClass:[RCTSliderComponentView class]];
+ [componentViewFactory registerComponentViewClass:[RCTSwitchComponentView class]];
+
+ return componentViewFactory;
+}
+
+- (void)registerComponentViewClass:(Class<RCTComponentViewProtocol>)componentViewClass
+{
+ RCTAssertMainQueue();
+
+ ComponentHandle componentHandle = [componentViewClass componentHandle];
+ _registry[componentHandle] = componentViewClass;
+}
+
+- (UIView<RCTComponentViewProtocol> *)createComponentViewWithComponentHandle:
+ (facebook::react::ComponentHandle)componentHandle
+{
+ RCTAssertMainQueue();
+
+ auto iterator = _registry.find(componentHandle);
+ RCTAssert(
+ iterator != _registry.end(),
+ @"ComponentView with componentHandle `%lli` (`%s`) not found.",
+ componentHandle,
+ (char *)componentHandle);
+ Class componentViewClass = iterator->second;
+ return [[componentViewClass alloc] init];
+}
+
+@end

React/Fabric/Mounting/RCTComponentViewProtocol.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,11 +7,11 @@
#import <UIKit/UIKit.h>
-#import <fabric/core/LocalData.h>
-#import <fabric/core/Props.h>
-#import <fabric/core/LayoutMetrics.h>
-#import <fabric/events/EventEmitter.h>
#import <React/RCTPrimitives.h>
+#import <react/core/LayoutMetrics.h>
+#import <react/core/LocalData.h>
+#import <react/core/Props.h>
+#import <react/events/EventEmitter.h>
NS_ASSUME_NONNULL_BEGIN
@@ -24,27 +24,30 @@
@protocol RCTComponentViewProtocol <NSObject>
/*
+ * Returns ComponentHandle of ComponentDescriptor which this ComponentView
+ * represents.
+ */
++ (facebook::react::ComponentHandle)componentHandle;
+
+/*
* Called for mounting (attaching) a child component view inside `self`
* component view.
* Receiver must add `childComponentView` as a subview.
*/
-- (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView
- index:(NSInteger)index;
+- (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index;
/*
* Called for unmounting (detaching) a child component view from `self`
* component view.
* Receiver must remove `childComponentView` as a subview.
*/
-- (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView
- index:(NSInteger)index;
+- (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index;
/*
* Called for updating component's props.
* Receiver must update native view props accordingly changed props.
*/
-- (void)updateProps:(facebook::react::SharedProps)props
- oldProps:(facebook::react::SharedProps)oldProps;
+- (void)updateProps:(facebook::react::SharedProps)props oldProps:(facebook::react::SharedProps)oldProps;
/*
* Called for updating component's local data.

React/Fabric/Mounting/RCTComponentViewRegistry.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,7 +7,9 @@
#import <UIKit/UIKit.h>
+#import <React/RCTComponentViewFactory.h>
#import <React/RCTComponentViewProtocol.h>
+#import <react/core/ReactPrimitives.h>
NS_ASSUME_NONNULL_BEGIN
@@ -17,19 +19,22 @@
*/
@interface RCTComponentViewRegistry : NSObject
+@property (nonatomic, strong, readonly) RCTComponentViewFactory *componentViewFactory;
+
/**
* Returns a native view instance from the recycle pool (or create)
- * for given `componentName` and with given `tag`.
+ * for given `componentHandle` and with given `tag`.
* #RefuseSingleUse
*/
-- (UIView<RCTComponentViewProtocol> *)dequeueComponentViewWithName:(NSString *)componentName
+- (UIView<RCTComponentViewProtocol> *)dequeueComponentViewWithComponentHandle:
+ (facebook::react::ComponentHandle)componentHandle
tag:(ReactTag)tag;
/**
* Puts a given native component view to the recycle pool.
* #RefuseSingleUse
*/
-- (void)enqueueComponentViewWithName:(NSString *)componentName
+- (void)enqueueComponentViewWithComponentHandle:(facebook::react::ComponentHandle)componentHandle
tag:(ReactTag)tag
componentView:(UIView<RCTComponentViewProtocol> *)componentView;
@@ -46,7 +51,7 @@
/**
* Creates a component view with a given type and puts it to the recycle pool.
*/
-- (void)preliminaryCreateComponentViewWithName:(NSString *)componentName;
+- (void)optimisticallyCreateComponentViewWithComponentHandle:(facebook::react::ComponentHandle)componentHandle;
@end

React/Fabric/Mounting/RCTComponentViewRegistry.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,12 +10,14 @@
#import <Foundation/NSMapTable.h>
#import <React/RCTAssert.h>
+using namespace facebook::react;
+
#define LEGACY_UIMANAGER_INTEGRATION_ENABLED 1
#ifdef LEGACY_UIMANAGER_INTEGRATION_ENABLED
-#import <React/RCTUIManager.h>
#import <React/RCTBridge+Private.h>
+#import <React/RCTUIManager.h>
/**
* Warning: This is a total hack and temporary solution.
@@ -67,8 +69,8 @@
const NSInteger RCTComponentViewRegistryRecyclePoolMaxSize = 1024;
@implementation RCTComponentViewRegistry {
- NSMapTable<id, UIView<RCTComponentViewProtocol> *> *_registry;
- NSMapTable<NSString *, NSHashTable<UIView<RCTComponentViewProtocol> *> *> *_recyclePool;
+ NSMapTable<id /* ReactTag */, UIView<RCTComponentViewProtocol> *> *_registry;
+ NSMapTable<id /* ComponentHandle */, NSHashTable<UIView<RCTComponentViewProtocol> *> *> *_recyclePool;
}
- (instancetype)init
@@ -76,23 +78,35 @@
if (self = [super init]) {
_registry = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsIntegerPersonality | NSPointerFunctionsOpaqueMemory
valueOptions:NSPointerFunctionsObjectPersonality];
- _recyclePool = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsObjectPersonality
+ _recyclePool =
+ [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsOpaquePersonality | NSPointerFunctionsOpaqueMemory
valueOptions:NSPointerFunctionsObjectPersonality];
+ _componentViewFactory = [RCTComponentViewFactory standardComponentViewFactory];
+
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(handleApplicationDidReceiveMemoryWarningNotification)
+ name:UIApplicationDidReceiveMemoryWarningNotification
+ object:nil];
}
return self;
}
-- (UIView<RCTComponentViewProtocol> *)dequeueComponentViewWithName:(NSString *)componentName
+- (void)dealloc
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (UIView<RCTComponentViewProtocol> *)dequeueComponentViewWithComponentHandle:(ComponentHandle)componentHandle
tag:(ReactTag)tag
{
RCTAssertMainQueue();
- RCTAssert(![_registry objectForKey:(__bridge id)(void *)tag],
+ RCTAssert(
+ ![_registry objectForKey:(__bridge id)(void *)tag],
@"RCTComponentViewRegistry: Attempt to dequeue already registered component.");
- UIView<RCTComponentViewProtocol> *componentView =
- [self _dequeueComponentViewWithName:componentName];
+ UIView<RCTComponentViewProtocol> *componentView = [self _dequeueComponentViewWithComponentHandle:componentHandle];
componentView.tag = tag;
[_registry setObject:componentView forKey:(__bridge id)(void *)tag];
@@ -103,13 +117,14 @@
return componentView;
}
-- (void)enqueueComponentViewWithName:(NSString *)componentName
+- (void)enqueueComponentViewWithComponentHandle:(ComponentHandle)componentHandle
tag:(ReactTag)tag
componentView:(UIView<RCTComponentViewProtocol> *)componentView
{
RCTAssertMainQueue();
- RCTAssert([_registry objectForKey:(__bridge id)(void *)tag],
+ RCTAssert(
+ [_registry objectForKey:(__bridge id)(void *)tag],
@"RCTComponentViewRegistry: Attempt to enqueue unregistered component.");
#ifdef LEGACY_UIMANAGER_INTEGRATION_ENABLED
@@ -118,14 +133,15 @@
[_registry removeObjectForKey:(__bridge id)(void *)tag];
componentView.tag = 0;
- [self _enqueueComponentViewWithName:componentName componentView:componentView];
+ [self _enqueueComponentViewWithComponentHandle:componentHandle componentView:componentView];
}
-- (void)preliminaryCreateComponentViewWithName:(NSString *)componentName
+- (void)optimisticallyCreateComponentViewWithComponentHandle:(ComponentHandle)componentHandle
{
RCTAssertMainQueue();
- [self _enqueueComponentViewWithName:componentName
- componentView:[self _createComponentViewWithName:componentName]];
+ [self _enqueueComponentViewWithComponentHandle:componentHandle
+ componentView:[self.componentViewFactory
+ createComponentViewWithComponentHandle:componentHandle]];
}
- (UIView<RCTComponentViewProtocol> *)componentViewByTag:(ReactTag)tag
@@ -140,21 +156,13 @@
return componentView.tag;
}
-- (UIView<RCTComponentViewProtocol> *)_createComponentViewWithName:(NSString *)componentName
+- (nullable UIView<RCTComponentViewProtocol> *)_dequeueComponentViewWithComponentHandle:(ComponentHandle)componentHandle
{
RCTAssertMainQueue();
- // This is temporary approach.
- NSString *className = [NSString stringWithFormat:@"RCT%@ComponentView", componentName];
- UIView<RCTComponentViewProtocol> *componentView = [[NSClassFromString(className) alloc] init];
- return componentView;
-}
-
-- (nullable UIView<RCTComponentViewProtocol> *)_dequeueComponentViewWithName:(NSString *)componentName
-{
- RCTAssertMainQueue();
- NSHashTable<UIView<RCTComponentViewProtocol> *> *componentViews = [_recyclePool objectForKey:componentName];
+ NSHashTable<UIView<RCTComponentViewProtocol> *> *componentViews =
+ [_recyclePool objectForKey:(__bridge id)(void *)componentHandle];
if (!componentViews || componentViews.count == 0) {
- return [self _createComponentViewWithName:componentName];
+ return [self.componentViewFactory createComponentViewWithComponentHandle:componentHandle];
}
UIView<RCTComponentViewProtocol> *componentView = [componentViews anyObject];
@@ -162,16 +170,17 @@
return componentView;
}
-- (void)_enqueueComponentViewWithName:(NSString *)componentName
+- (void)_enqueueComponentViewWithComponentHandle:(ComponentHandle)componentHandle
componentView:(UIView<RCTComponentViewProtocol> *)componentView
{
RCTAssertMainQueue();
[componentView prepareForRecycle];
- NSHashTable<UIView<RCTComponentViewProtocol> *> *componentViews = [_recyclePool objectForKey:componentName];
+ NSHashTable<UIView<RCTComponentViewProtocol> *> *componentViews =
+ [_recyclePool objectForKey:(__bridge id)(void *)componentHandle];
if (!componentViews) {
componentViews = [NSHashTable hashTableWithOptions:NSPointerFunctionsObjectPersonality];
- [_recyclePool setObject:componentViews forKey:componentName];
+ [_recyclePool setObject:componentViews forKey:(__bridge id)(void *)componentHandle];
}
if (componentViews.count >= RCTComponentViewRegistryRecyclePoolMaxSize) {
@@ -181,4 +190,9 @@
[componentViews addObject:componentView];
}
+- (void)handleApplicationDidReceiveMemoryWarningNotification
+{
+ [_recyclePool removeAllObjects];
+}
+
@end

React/Fabric/Mounting/RCTMountingManagerDelegate.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Fabric/Mounting/RCTMountingManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,9 +7,11 @@
#import <UIKit/UIKit.h>
-#import <fabric/uimanager/TreeMutationInstruction.h>
-#import <React/RCTPrimitives.h>
#import <React/RCTMountingManagerDelegate.h>
+#import <React/RCTPrimitives.h>
+#import <react/core/ReactPrimitives.h>
+#import <react/mounting/ShadowView.h>
+#import <react/mounting/ShadowViewMutation.h>
NS_ASSUME_NONNULL_BEGIN
@@ -20,7 +22,7 @@
*/
@interface RCTMountingManager : NSObject
-@property (nonatomic, weak) id <RCTMountingManagerDelegate> delegate;
+@property (nonatomic, weak) id<RCTMountingManagerDelegate> delegate;
@property (nonatomic, strong) RCTComponentViewRegistry *componentViewRegistry;
/**
@@ -28,15 +30,14 @@
* The order of mutation tnstructions matters.
* Can be called from any thread.
*/
-- (void)mutateComponentViewTreeWithMutationInstructions:(facebook::react::TreeMutationInstructionList)instructions
- rootTag:(ReactTag)rootTag;
+- (void)performTransactionWithMutations:(facebook::react::ShadowViewMutationList)mutations rootTag:(ReactTag)rootTag;
/**
* Suggests preliminary creation of a component view of given type.
* The receiver is free to ignore the request.
* Can be called from any thread.
*/
-- (void)preliminaryCreateComponentViewWithName:(NSString *)componentName;
+- (void)optimisticallyCreateComponentViewWithComponentHandle:(facebook::react::ComponentHandle)componentHandle;
@end

React/Fabric/Mounting/RCTMountingManager.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,23 +7,24 @@
#import "RCTMountingManager.h"
-#import <fabric/core/LayoutableShadowNode.h>
#import <React/RCTAssert.h>
#import <React/RCTUtils.h>
+#import <react/core/LayoutableShadowNode.h>
+#import <react/debug/SystraceSection.h>
#import "RCTComponentViewProtocol.h"
#import "RCTComponentViewRegistry.h"
#import "RCTMountItemProtocol.h"
-#import "RCTCreateMountItem.h"
#import "RCTConversions.h"
+#import "RCTCreateMountItem.h"
#import "RCTDeleteMountItem.h"
#import "RCTInsertMountItem.h"
#import "RCTRemoveMountItem.h"
-#import "RCTUpdatePropsMountItem.h"
#import "RCTUpdateEventEmitterMountItem.h"
-#import "RCTUpdateLocalDataMountItem.h"
#import "RCTUpdateLayoutMetricsMountItem.h"
+#import "RCTUpdateLocalDataMountItem.h"
+#import "RCTUpdatePropsMountItem.h"
using namespace facebook::react;
@@ -38,138 +39,132 @@
return self;
}
-- (void)mutateComponentViewTreeWithMutationInstructions:(facebook::react::TreeMutationInstructionList)instructions
- rootTag:(ReactTag)rootTag
+- (void)performTransactionWithMutations:(facebook::react::ShadowViewMutationList)mutations rootTag:(ReactTag)rootTag
{
- NSMutableArray<RCTMountItemProtocol> *mountItems =
- [[NSMutableArray<RCTMountItemProtocol> alloc] initWithCapacity:instructions.size() * 2 /* ~ the worst case */];
+ NSMutableArray<RCTMountItemProtocol> *mountItems;
- for (auto instruction : instructions) {
- switch (instruction.getType()) {
- case TreeMutationInstruction::Creation: {
- NSString *componentName = RCTNSStringFromString(instruction.getNewChildNode()->getComponentName(), NSASCIIStringEncoding);
+ {
+ // This section is measured separately from `_performMountItems:rootTag:` because that can be asynchronous.
+ SystraceSection s("-[RCTMountingManager performTransactionWithMutations:rootTag:]");
+
+ mountItems =
+ [[NSMutableArray<RCTMountItemProtocol> alloc] initWithCapacity:mutations.size() * 2 /* ~ the worst case */];
+
+ for (const auto &mutation : mutations) {
+ switch (mutation.type) {
+ case ShadowViewMutation::Create: {
RCTCreateMountItem *mountItem =
- [[RCTCreateMountItem alloc] initWithComponentName:componentName
- tag:instruction.getNewChildNode()->getTag()];
+ [[RCTCreateMountItem alloc] initWithComponentHandle:mutation.newChildShadowView.componentHandle
+ tag:mutation.newChildShadowView.tag];
[mountItems addObject:mountItem];
break;
}
- case TreeMutationInstruction::Deletion: {
- NSString *componentName = RCTNSStringFromString(instruction.getOldChildNode()->getComponentName(), NSASCIIStringEncoding);
+ case ShadowViewMutation::Delete: {
RCTDeleteMountItem *mountItem =
- [[RCTDeleteMountItem alloc] initWithComponentName:componentName
- tag:instruction.getOldChildNode()->getTag()];
+ [[RCTDeleteMountItem alloc] initWithComponentHandle:mutation.oldChildShadowView.componentHandle
+ tag:mutation.oldChildShadowView.tag];
[mountItems addObject:mountItem];
break;
}
- case TreeMutationInstruction::Insertion: {
+ case ShadowViewMutation::Insert: {
// Props
- [mountItems addObject:[[RCTUpdatePropsMountItem alloc] initWithTag:instruction.getNewChildNode()->getTag()
+ [mountItems addObject:[[RCTUpdatePropsMountItem alloc] initWithTag:mutation.newChildShadowView.tag
oldProps:nullptr
- newProps:instruction.getNewChildNode()->getProps()]];
+ newProps:mutation.newChildShadowView.props]];
// EventEmitter
- [mountItems addObject:[[RCTUpdateEventEmitterMountItem alloc] initWithTag:instruction.getNewChildNode()->getTag()
- eventEmitter:instruction.getNewChildNode()->getEventEmitter()]];
+ [mountItems
+ addObject:[[RCTUpdateEventEmitterMountItem alloc] initWithTag:mutation.newChildShadowView.tag
+ eventEmitter:mutation.newChildShadowView.eventEmitter]];
// LocalData
- if (instruction.getNewChildNode()->getLocalData()) {
- [mountItems addObject:[[RCTUpdateLocalDataMountItem alloc] initWithTag:instruction.getNewChildNode()->getTag()
+ if (mutation.newChildShadowView.localData) {
+ [mountItems
+ addObject:[[RCTUpdateLocalDataMountItem alloc] initWithTag:mutation.newChildShadowView.tag
oldLocalData:nullptr
- newLocalData:instruction.getNewChildNode()->getLocalData()]];
+ newLocalData:mutation.newChildShadowView.localData]];
}
// Layout
- auto layoutableNewShadowNode =
- std::dynamic_pointer_cast<const LayoutableShadowNode>(instruction.getNewChildNode());
-
- if (layoutableNewShadowNode) {
- [mountItems addObject:[[RCTUpdateLayoutMetricsMountItem alloc] initWithTag:instruction.getNewChildNode()->getTag()
+ if (mutation.newChildShadowView.layoutMetrics != EmptyLayoutMetrics) {
+ [mountItems addObject:[[RCTUpdateLayoutMetricsMountItem alloc]
+ initWithTag:mutation.newChildShadowView.tag
oldLayoutMetrics:{}
- newLayoutMetrics:layoutableNewShadowNode->getLayoutMetrics()]];
+ newLayoutMetrics:mutation.newChildShadowView.layoutMetrics]];
}
// Insertion
- RCTInsertMountItem *mountItem =
- [[RCTInsertMountItem alloc] initWithChildTag:instruction.getNewChildNode()->getTag()
- parentTag:instruction.getParentNode()->getTag()
- index:instruction.getIndex()];
+ RCTInsertMountItem *mountItem = [[RCTInsertMountItem alloc] initWithChildTag:mutation.newChildShadowView.tag
+ parentTag:mutation.parentShadowView.tag
+ index:mutation.index];
[mountItems addObject:mountItem];
break;
}
- case TreeMutationInstruction::Removal: {
- RCTRemoveMountItem *mountItem =
- [[RCTRemoveMountItem alloc] initWithChildTag:instruction.getOldChildNode()->getTag()
- parentTag:instruction.getParentNode()->getTag()
- index:instruction.getIndex()];
+ case ShadowViewMutation::Remove: {
+ RCTRemoveMountItem *mountItem = [[RCTRemoveMountItem alloc] initWithChildTag:mutation.oldChildShadowView.tag
+ parentTag:mutation.parentShadowView.tag
+ index:mutation.index];
[mountItems addObject:mountItem];
break;
}
- case TreeMutationInstruction::Replacement: {
- SharedShadowNode oldShadowNode = instruction.getOldChildNode();
- SharedShadowNode newShadowNode = instruction.getNewChildNode();
+ case ShadowViewMutation::Update: {
+ auto oldChildShadowView = mutation.oldChildShadowView;
+ auto newChildShadowView = mutation.newChildShadowView;
// Props
- if (oldShadowNode->getProps() != newShadowNode->getProps()) {
+ if (oldChildShadowView.props != newChildShadowView.props) {
RCTUpdatePropsMountItem *mountItem =
- [[RCTUpdatePropsMountItem alloc] initWithTag:instruction.getOldChildNode()->getTag()
- oldProps:instruction.getOldChildNode()->getProps()
- newProps:instruction.getNewChildNode()->getProps()];
+ [[RCTUpdatePropsMountItem alloc] initWithTag:mutation.oldChildShadowView.tag
+ oldProps:mutation.oldChildShadowView.props
+ newProps:mutation.newChildShadowView.props];
[mountItems addObject:mountItem];
}
// EventEmitter
- if (oldShadowNode->getEventEmitter() != newShadowNode->getEventEmitter()) {
+ if (oldChildShadowView.eventEmitter != newChildShadowView.eventEmitter) {
RCTUpdateEventEmitterMountItem *mountItem =
- [[RCTUpdateEventEmitterMountItem alloc] initWithTag:instruction.getOldChildNode()->getTag()
- eventEmitter:instruction.getOldChildNode()->getEventEmitter()];
+ [[RCTUpdateEventEmitterMountItem alloc] initWithTag:mutation.oldChildShadowView.tag
+ eventEmitter:mutation.oldChildShadowView.eventEmitter];
[mountItems addObject:mountItem];
}
// LocalData
- if (oldShadowNode->getLocalData() != newShadowNode->getLocalData()) {
+ if (oldChildShadowView.localData != newChildShadowView.localData) {
RCTUpdateLocalDataMountItem *mountItem =
- [[RCTUpdateLocalDataMountItem alloc] initWithTag:newShadowNode->getTag()
- oldLocalData:oldShadowNode->getLocalData()
- newLocalData:newShadowNode->getLocalData()];
+ [[RCTUpdateLocalDataMountItem alloc] initWithTag:newChildShadowView.tag
+ oldLocalData:oldChildShadowView.localData
+ newLocalData:newChildShadowView.localData];
[mountItems addObject:mountItem];
}
// Layout
- auto layoutableOldShadowNode =
- std::dynamic_pointer_cast<const LayoutableShadowNode>(oldShadowNode);
-
- if (layoutableOldShadowNode) {
- auto layoutableNewShadowNode =
- std::dynamic_pointer_cast<const LayoutableShadowNode>(newShadowNode);
-
- if (layoutableOldShadowNode->getLayoutMetrics() != layoutableNewShadowNode->getLayoutMetrics()) {
+ if (oldChildShadowView.layoutMetrics != newChildShadowView.layoutMetrics) {
RCTUpdateLayoutMetricsMountItem *mountItem =
- [[RCTUpdateLayoutMetricsMountItem alloc] initWithTag:instruction.getOldChildNode()->getTag()
- oldLayoutMetrics:layoutableOldShadowNode->getLayoutMetrics()
- newLayoutMetrics:layoutableNewShadowNode->getLayoutMetrics()];
+ [[RCTUpdateLayoutMetricsMountItem alloc] initWithTag:mutation.oldChildShadowView.tag
+ oldLayoutMetrics:oldChildShadowView.layoutMetrics
+ newLayoutMetrics:newChildShadowView.layoutMetrics];
[mountItems addObject:mountItem];
}
- }
break;
}
}
}
+ }
RCTExecuteOnMainQueue(^{
[self _performMountItems:mountItems rootTag:rootTag];
});
}
-- (void)_performMountItems:(NSArray<RCTMountItemProtocol> *)mountItems
- rootTag:(ReactTag)rootTag
+- (void)_performMountItems:(NSArray<RCTMountItemProtocol> *)mountItems rootTag:(ReactTag)rootTag
{
+ SystraceSection s("-[RCTMountingManager _performMountItems:rootTag:]");
RCTAssertMainQueue();
[self.delegate mountingManager:self willMountComponentsWithRootTag:rootTag];
@@ -181,10 +176,15 @@
[self.delegate mountingManager:self didMountComponentsWithRootTag:rootTag];
}
-- (void)preliminaryCreateComponentViewWithName:(NSString *)componentName
+- (void)optimisticallyCreateComponentViewWithComponentHandle:(ComponentHandle)componentHandle
{
+ if (RCTIsMainQueue()) {
+ // There is no reason to allocate views ahead of time on the main thread.
+ return;
+ }
+
RCTExecuteOnMainQueue(^{
- [self->_componentViewRegistry preliminaryCreateComponentViewWithName:componentName];
+ [self->_componentViewRegistry optimisticallyCreateComponentViewWithComponentHandle:componentHandle];
});
}

React/Fabric/Mounting/UIView+ComponentViewProtocol.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -17,14 +16,11 @@
*/
@interface UIView (ComponentViewProtocol)
-- (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView
- index:(NSInteger)index;
+- (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index;
-- (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView
- index:(NSInteger)index;
+- (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index;
-- (void)updateProps:(facebook::react::SharedProps)props
- oldProps:(facebook::react::SharedProps)oldProps;
+- (void)updateProps:(facebook::react::SharedProps)props oldProps:(facebook::react::SharedProps)oldProps;
- (void)updateEventEmitter:(facebook::react::SharedEventEmitter)eventEmitter;

React/Fabric/Mounting/UIView+ComponentViewProtocol.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -14,21 +14,18 @@
@implementation UIView (ComponentViewProtocol)
-- (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView
- index:(NSInteger)index
+- (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
{
[self insertSubview:childComponentView atIndex:index];
}
-- (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView
- index:(NSInteger)index
+- (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
{
RCTAssert(childComponentView.superview == self, @"Attempt to unmount improperly mounted component view.");
[childComponentView removeFromSuperview];
}
-- (void)updateProps:(SharedProps)props
- oldProps:(SharedProps)oldProps
+- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps
{
// Default implementation does nothing.
}
@@ -38,24 +35,21 @@
// Default implementation does nothing.
}
-- (void)updateLocalData:(SharedLocalData)localData
- oldLocalData:(SharedLocalData)oldLocalData
+- (void)updateLocalData:(SharedLocalData)localData oldLocalData:(SharedLocalData)oldLocalData
{
// Default implementation does nothing.
}
-- (void)updateLayoutMetrics:(LayoutMetrics)layoutMetrics
- oldLayoutMetrics:(LayoutMetrics)oldLayoutMetrics
+- (void)updateLayoutMetrics:(LayoutMetrics)layoutMetrics oldLayoutMetrics:(LayoutMetrics)oldLayoutMetrics
{
if (layoutMetrics.frame != oldLayoutMetrics.frame) {
self.frame = RCTCGRectFromRect(layoutMetrics.frame);
}
if (layoutMetrics.layoutDirection != oldLayoutMetrics.layoutDirection) {
- self.semanticContentAttribute =
- layoutMetrics.layoutDirection == LayoutDirection::RightToLeft ?
- UISemanticContentAttributeForceRightToLeft :
- UISemanticContentAttributeForceLeftToRight;
+ self.semanticContentAttribute = layoutMetrics.layoutDirection == LayoutDirection::RightToLeft
+ ? UISemanticContentAttributeForceRightToLeft
+ : UISemanticContentAttributeForceLeftToRight;
}
if (layoutMetrics.displayType != oldLayoutMetrics.displayType) {

React/Fabric/RCTConversions.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,14 +7,21 @@
#import <UIKit/UIKit.h>
-#import <fabric/components/view/primitives.h>
-#import <fabric/graphics/Color.h>
-#import <fabric/graphics/Geometry.h>
+#import <react/components/view/primitives.h>
+#import <react/components/view/AccessibilityPrimitives.h>
+#import <react/graphics/Color.h>
+#import <react/graphics/Geometry.h>
-inline NSString *_Nullable RCTNSStringFromString(const std::string &string, const NSStringEncoding &encoding = NSUTF8StringEncoding) {
+NS_ASSUME_NONNULL_BEGIN
+
+inline NSString *RCTNSStringFromString(const std::string &string, const NSStringEncoding &encoding = NSUTF8StringEncoding) {
return [NSString stringWithCString:string.c_str() encoding:encoding];
}
+inline NSString *_Nullable RCTNSStringFromStringNilIfEmpty(const std::string &string, const NSStringEncoding &encoding = NSUTF8StringEncoding) {
+ return string.empty() ? nil : RCTNSStringFromString(string, encoding);
+}
+
inline std::string RCTStringFromNSString(NSString *string, const NSStringEncoding &encoding = NSUTF8StringEncoding) {
return [string cStringUsingEncoding:encoding];
}
@@ -43,6 +50,27 @@
return {edgeInsets.top, edgeInsets.left, edgeInsets.bottom, edgeInsets.right};
}
+inline UIAccessibilityTraits RCTUIAccessibilityTraitsFromAccessibilityTraits(facebook::react::AccessibilityTraits accessibilityTraits) {
+ using AccessibilityTraits = facebook::react::AccessibilityTraits;
+ UIAccessibilityTraits result = UIAccessibilityTraitNone;
+ if ((accessibilityTraits & AccessibilityTraits::Button) != AccessibilityTraits::None) { result |= UIAccessibilityTraitButton; }
+ if ((accessibilityTraits & AccessibilityTraits::Link) != AccessibilityTraits::None) { result |= UIAccessibilityTraitLink; }
+ if ((accessibilityTraits & AccessibilityTraits::Image) != AccessibilityTraits::None) { result |= UIAccessibilityTraitImage; }
+ if ((accessibilityTraits & AccessibilityTraits::Selected) != AccessibilityTraits::None) { result |= UIAccessibilityTraitSelected; }
+ if ((accessibilityTraits & AccessibilityTraits::PlaysSound) != AccessibilityTraits::None) { result |= UIAccessibilityTraitPlaysSound; }
+ if ((accessibilityTraits & AccessibilityTraits::KeyboardKey) != AccessibilityTraits::None) { result |= UIAccessibilityTraitKeyboardKey; }
+ if ((accessibilityTraits & AccessibilityTraits::StaticText) != AccessibilityTraits::None) { result |= UIAccessibilityTraitStaticText; }
+ if ((accessibilityTraits & AccessibilityTraits::SummaryElement) != AccessibilityTraits::None) { result |= UIAccessibilityTraitSummaryElement; }
+ if ((accessibilityTraits & AccessibilityTraits::NotEnabled) != AccessibilityTraits::None) { result |= UIAccessibilityTraitNotEnabled; }
+ if ((accessibilityTraits & AccessibilityTraits::UpdatesFrequently) != AccessibilityTraits::None) { result |= UIAccessibilityTraitUpdatesFrequently; }
+ if ((accessibilityTraits & AccessibilityTraits::SearchField) != AccessibilityTraits::None) { result |= UIAccessibilityTraitSearchField; }
+ if ((accessibilityTraits & AccessibilityTraits::StartsMediaSession) != AccessibilityTraits::None) { result |= UIAccessibilityTraitStartsMediaSession; }
+ if ((accessibilityTraits & AccessibilityTraits::Adjustable) != AccessibilityTraits::None) { result |= UIAccessibilityTraitAdjustable; }
+ if ((accessibilityTraits & AccessibilityTraits::AllowsDirectInteraction) != AccessibilityTraits::None) { result |= UIAccessibilityTraitAllowsDirectInteraction; }
+ if ((accessibilityTraits & AccessibilityTraits::CausesPageTurn) != AccessibilityTraits::None) { result |= UIAccessibilityTraitCausesPageTurn; }
+ if ((accessibilityTraits & AccessibilityTraits::Header) != AccessibilityTraits::None) { result |= UIAccessibilityTraitHeader; }
+ return result;
+};
inline CATransform3D RCTCATransform3DFromTransformMatrix(const facebook::react::Transform &transformMatrix) {
return {
@@ -80,3 +108,5 @@
inline facebook::react::EdgeInsets RCTEdgeInsetsFromUIEdgeInsets(const UIEdgeInsets &edgeInsets) {
return {edgeInsets.top, edgeInsets.left, edgeInsets.bottom, edgeInsets.right};
}
+
+NS_ASSUME_NONNULL_END

React/Fabric/RCTImageResponseDelegate.h

@@ -0,0 +1,20 @@
+/**
+ * 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.
+ */
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@protocol RCTImageResponseDelegate <NSObject>
+
+- (void)didReceiveImage:(UIImage *)image fromObserver:(void*)observer;
+- (void)didReceiveProgress:(float)progress fromObserver:(void*)observer;
+- (void)didReceiveFailureFromObserver:(void*)observer;
+
+@end
+
+NS_ASSUME_NONNULL_END

React/Fabric/RCTImageResponseObserverProxy.h

@@ -0,0 +1,32 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#import "RCTImageResponseDelegate.h"
+#import "RCTImageResponseDelegate.h"
+
+#include <react/imagemanager/ImageResponseObserver.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+namespace facebook {
+ namespace react {
+ class RCTImageResponseObserverProxy: public ImageResponseObserver {
+ public:
+ RCTImageResponseObserverProxy(void* delegate);
+ void didReceiveImage(const ImageResponse &imageResponse) override;
+ void didReceiveProgress (float p) override;
+ void didReceiveFailure() override;
+
+ private:
+ id<RCTImageResponseDelegate> delegate_;
+ };
+ }
+}
+
+NS_ASSUME_NONNULL_END

React/Fabric/RCTImageResponseObserverProxy.mm

@@ -0,0 +1,41 @@
+/**
+ * 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.
+ */
+
+#import "RCTImageResponseObserverProxy.h"
+
+#import <react/imagemanager/ImageResponseObserver.h>
+#import <react/imagemanager/ImageResponse.h>
+
+namespace facebook {
+ namespace react {
+
+RCTImageResponseObserverProxy::RCTImageResponseObserverProxy(void* delegate): delegate_((__bridge id<RCTImageResponseDelegate>)delegate) {}
+
+void RCTImageResponseObserverProxy::didReceiveImage(const ImageResponse &imageResponse) {
+ UIImage *image = (__bridge UIImage *)imageResponse.getImage().get();
+ void *this_ = this;
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [delegate_ didReceiveImage:image fromObserver:this_];
+ });
+}
+
+void RCTImageResponseObserverProxy::didReceiveProgress (float p) {
+ void *this_ = this;
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [delegate_ didReceiveProgress:p fromObserver:this_];
+ });
+}
+
+void RCTImageResponseObserverProxy::didReceiveFailure() {
+ void *this_ = this;
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [delegate_ didReceiveFailureFromObserver:this_];
+ });
+}
+
+ } // namespace react
+} // namespace facebook

React/Fabric/RCTPrimitives.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Fabric/RCTScheduler.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,10 +9,9 @@
#import <memory>
#import <React/RCTPrimitives.h>
-#import <fabric/core/LayoutConstraints.h>
-#import <fabric/core/LayoutContext.h>
-#import <fabric/uimanager/FabricUIManager.h>
-#import <fabric/uimanager/TreeMutationInstruction.h>
+#import <react/core/LayoutConstraints.h>
+#import <react/core/LayoutContext.h>
+#import <react/mounting/ShadowViewMutation.h>
NS_ASSUME_NONNULL_BEGIN
@@ -23,9 +22,10 @@
*/
@protocol RCTSchedulerDelegate
-- (void)schedulerDidComputeMutationInstructions:(facebook::react::TreeMutationInstructionList)instructions rootTag:(ReactTag)rootTag;
+- (void)schedulerDidFinishTransaction:(facebook::react::ShadowViewMutationList)mutations
+ rootTag:(ReactTag)rootTag;
-- (void)schedulerDidRequestPreliminaryViewAllocationWithComponentName:(NSString *)componentName;
+- (void)schedulerOptimisticallyCreateComponentViewWithComponentHandle:(facebook::react::ComponentHandle)componentHandle;
@end
@@ -36,23 +36,23 @@
@property (atomic, weak, nullable) id<RCTSchedulerDelegate> delegate;
-- (void)registerRootTag:(ReactTag)tag;
+- (instancetype)initWithContextContainer:(std::shared_ptr<void>)contextContatiner;
-- (void)unregisterRootTag:(ReactTag)tag;
+- (void)startSurfaceWithSurfaceId:(facebook::react::SurfaceId)surfaceId
+ moduleName:(NSString *)moduleName
+ initailProps:(NSDictionary *)initialProps
+ layoutConstraints:(facebook::react::LayoutConstraints)layoutConstraints
+ layoutContext:(facebook::react::LayoutContext)layoutContext;
-- (CGSize)measureWithLayoutConstraints:(facebook::react::LayoutConstraints)layoutConstraints
- layoutContext:(facebook::react::LayoutContext)layoutContext
- rootTag:(ReactTag)rootTag;
+- (void)stopSurfaceWithSurfaceId:(facebook::react::SurfaceId)surfaceId;
-- (void)constraintLayoutWithLayoutConstraints:(facebook::react::LayoutConstraints)layoutConstraints
+- (CGSize)measureSurfaceWithLayoutConstraints:(facebook::react::LayoutConstraints)layoutConstraints
layoutContext:(facebook::react::LayoutContext)layoutContext
- rootTag:(ReactTag)rootTag;
+ surfaceId:(facebook::react::SurfaceId)surfaceId;
-@end
-
-@interface RCTScheduler (Deprecated)
-
-- (std::shared_ptr<facebook::react::FabricUIManager>)uiManager_DO_NOT_USE;
+- (void)constraintSurfaceLayoutWithLayoutConstraints:(facebook::react::LayoutConstraints)layoutConstraints
+ layoutContext:(facebook::react::LayoutContext)layoutContext
+ surfaceId:(facebook::react::SurfaceId)surfaceId;
@end

React/Fabric/RCTScheduler.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,12 +7,13 @@
#import "RCTScheduler.h"
-#import <fabric/imagemanager/ImageManager.h>
-#import <fabric/uimanager/ContextContainer.h>
-#import <fabric/uimanager/Scheduler.h>
-#import <fabric/uimanager/SchedulerDelegate.h>
-#import <React/RCTImageLoader.h>
-#import <React/RCTBridge+Private.h>
+#import <react/debug/SystraceSection.h>
+#import <react/uimanager/ComponentDescriptorFactory.h>
+#import <react/uimanager/ContextContainer.h>
+#import <react/uimanager/Scheduler.h>
+#import <react/uimanager/SchedulerDelegate.h>
+
+#import <React/RCTFollyConvert.h>
#import "RCTConversions.h"
@@ -20,16 +21,21 @@
class SchedulerDelegateProxy: public SchedulerDelegate {
public:
- SchedulerDelegateProxy(void *scheduler): scheduler_(scheduler) {}
+ SchedulerDelegateProxy(void *scheduler):
+ scheduler_(scheduler) {}
- void schedulerDidComputeMutationInstructions(Tag rootTag, const TreeMutationInstructionList &instructions) override {
+ void schedulerDidFinishTransaction(Tag rootTag, const ShadowViewMutationList &mutations, const long commitStartTime, const long layoutTime) override {
RCTScheduler *scheduler = (__bridge RCTScheduler *)scheduler_;
- [scheduler.delegate schedulerDidComputeMutationInstructions:instructions rootTag:rootTag];
+ [scheduler.delegate schedulerDidFinishTransaction:mutations rootTag:rootTag];
+ }
+
+ void schedulerDidRequestPreliminaryViewAllocation(SurfaceId surfaceId, ComponentName componentName, bool isLayoutable, ComponentHandle componentHandle) override {
+ if (!isLayoutable) {
+ return;
}
- void schedulerDidRequestPreliminaryViewAllocation(ComponentName componentName) override {
RCTScheduler *scheduler = (__bridge RCTScheduler *)scheduler_;
- [scheduler.delegate schedulerDidRequestPreliminaryViewAllocationWithComponentName:RCTNSStringFromString(componentName, NSASCIIStringEncoding)];
+ [scheduler.delegate schedulerOptimisticallyCreateComponentViewWithComponentHandle:componentHandle];
}
private:
@@ -41,17 +47,11 @@
std::shared_ptr<SchedulerDelegateProxy> _delegateProxy;
}
-- (instancetype)init
+- (instancetype)initWithContextContainer:(std::shared_ptr<void>)contextContainer
{
if (self = [super init]) {
_delegateProxy = std::make_shared<SchedulerDelegateProxy>((__bridge void *)self);
-
- SharedContextContainer contextContainer = std::make_shared<ContextContainer>();
-
- void *imageLoader = (__bridge void *)[[RCTBridge currentBridge] imageLoader];
- contextContainer->registerInstance(std::make_shared<ImageManager>(imageLoader));
-
- _scheduler = std::make_shared<Scheduler>(contextContainer);
+ _scheduler = std::make_shared<Scheduler>(std::static_pointer_cast<ContextContainer>(contextContainer), getDefaultComponentRegistryFactory());
_scheduler->setDelegate(_delegateProxy.get());
}
@@ -63,37 +63,48 @@
_scheduler->setDelegate(nullptr);
}
-- (void)registerRootTag:(ReactTag)tag
-{
- _scheduler->registerRootTag(tag);
+- (void)startSurfaceWithSurfaceId:(SurfaceId)surfaceId
+ moduleName:(NSString *)moduleName
+ initailProps:(NSDictionary *)initialProps
+ layoutConstraints:(LayoutConstraints)layoutConstraints
+ layoutContext:(LayoutContext)layoutContext;
+{
+ SystraceSection s("-[RCTScheduler startSurfaceWithSurfaceId:...]");
+
+ auto props = convertIdToFollyDynamic(initialProps);
+ _scheduler->startSurface(
+ surfaceId,
+ RCTStringFromNSString(moduleName),
+ props,
+ layoutConstraints,
+ layoutContext);
+ _scheduler->renderTemplateToSurface(
+ surfaceId,
+ props.getDefault("navigationConfig")
+ .getDefault("initialUITemplate", "")
+ .getString());
}
-- (void)unregisterRootTag:(ReactTag)tag
+- (void)stopSurfaceWithSurfaceId:(SurfaceId)surfaceId
{
- _scheduler->unregisterRootTag(tag);
+ SystraceSection s("-[RCTScheduler stopSurfaceWithSurfaceId:]");
+ _scheduler->stopSurface(surfaceId);
}
-- (CGSize)measureWithLayoutConstraints:(LayoutConstraints)layoutConstraints
+- (CGSize)measureSurfaceWithLayoutConstraints:(LayoutConstraints)layoutConstraints
layoutContext:(LayoutContext)layoutContext
- rootTag:(ReactTag)rootTag
+ surfaceId:(SurfaceId)surfaceId
{
- return RCTCGSizeFromSize(_scheduler->measure(rootTag, layoutConstraints, layoutContext));
+ SystraceSection s("-[RCTScheduler measureSurfaceWithLayoutConstraints:]");
+ return RCTCGSizeFromSize(_scheduler->measureSurface(surfaceId, layoutConstraints, layoutContext));
}
-- (void)constraintLayoutWithLayoutConstraints:(LayoutConstraints)layoutConstraints
+- (void)constraintSurfaceLayoutWithLayoutConstraints:(LayoutConstraints)layoutConstraints
layoutContext:(LayoutContext)layoutContext
- rootTag:(ReactTag)rootTag
-{
- _scheduler->constraintLayout(rootTag, layoutConstraints, layoutContext);
-}
-
-@end
-
-@implementation RCTScheduler (Deprecated)
-
-- (std::shared_ptr<FabricUIManager>)uiManager_DO_NOT_USE
+ surfaceId:(SurfaceId)surfaceId
{
- return _scheduler->getUIManager_DO_NOT_USE();
+ SystraceSection s("-[RCTScheduler constraintSurfaceLayoutWithLayoutConstraints:]");
+ _scheduler->constraintSurfaceLayout(surfaceId, layoutConstraints, layoutContext);
}
@end

React/Fabric/RCTSurfacePresenter.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,8 +9,10 @@
#import <memory>
#import <React/RCTBridge.h>
+#import <React/RCTComponentViewFactory.h>
+#import <react/uimanager/ContextContainer.h>
#import <React/RCTPrimitives.h>
-#import <fabric/uimanager/FabricUIManager.h>
+#import <react/config/ReactNativeConfig.h>
NS_ASSUME_NONNULL_BEGIN
@@ -25,18 +27,29 @@
*/
@interface RCTSurfacePresenter : NSObject
-- (instancetype)initWithBridge:(RCTBridge *)bridge;
+- (instancetype)initWithBridge:(RCTBridge *)bridge
+ config:(std::shared_ptr<const facebook::react::ReactNativeConfig>)config;
+
+@property (nonatomic, readonly) RCTComponentViewFactory *componentViewFactory;
+@property (nonatomic, readonly) facebook::react::SharedContextContainer contextContainer;
@end
@interface RCTSurfacePresenter (Surface)
/**
- * Surface uses those methods to register itself in the Presenter.
- * Registering initiates running, rendering and mounting processes.
+ * Surface uses these methods to register itself in the Presenter.
*/
- (void)registerSurface:(RCTFabricSurface *)surface;
+/**
+ * Starting initiates running, rendering and mounting processes.
+ * Should be called after registerSurface and any other surface-specific setup is done
+ */
+- (void)startSurface:(RCTFabricSurface *)surface;
- (void)unregisterSurface:(RCTFabricSurface *)surface;
+- (void)setProps:(NSDictionary *)props
+ surface:(RCTFabricSurface *)surface;
+
- (nullable RCTFabricSurface *)surfaceForRootTag:(ReactTag)rootTag;
/**
@@ -58,21 +71,15 @@
@interface RCTSurfacePresenter (Deprecated)
/**
- * We need to expose `uiManager` for registration
- * purposes. Eventually, we will move this down to C++ side.
- */
-- (std::shared_ptr<facebook::react::FabricUIManager>)uiManager_DO_NOT_USE;
-
-/**
* Returns a underlying bridge.
*/
- (RCTBridge *)bridge_DO_NOT_USE;
@end
-@interface RCTBridge (RCTSurfacePresenter)
+@interface RCTBridge (Deprecated)
-- (RCTSurfacePresenter *)surfacePresenter;
+@property (nonatomic) RCTSurfacePresenter *surfacePresenter;
@end

React/Fabric/RCTSurfacePresenter.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,10 +7,16 @@
#import "RCTSurfacePresenter.h"
+#import <objc/runtime.h>
+#import <mutex>
+#import <jsi/jsi.h>
+#import <cxxreact/MessageQueueThread.h>
+
#import <React/RCTAssert.h>
#import <React/RCTBridge+Private.h>
#import <React/RCTComponentViewRegistry.h>
#import <React/RCTFabricSurface.h>
+#import <React/RCTImageLoader.h>
#import <React/RCTMountingManager.h>
#import <React/RCTMountingManagerDelegate.h>
#import <React/RCTScheduler.h>
@@ -18,37 +24,53 @@
#import <React/RCTSurfaceView.h>
#import <React/RCTSurfaceView+Internal.h>
#import <React/RCTUtils.h>
-#import <fabric/core/LayoutContext.h>
-#import <fabric/core/LayoutConstraints.h>
+#import <react/core/LayoutContext.h>
+#import <react/core/LayoutConstraints.h>
+#import <react/components/root/RootShadowNode.h>
+#import <react/imagemanager/ImageManager.h>
+#import <react/uimanager/ContextContainer.h>
+#import "MainRunLoopEventBeat.h"
+#import "RuntimeEventBeat.h"
#import "RCTConversions.h"
using namespace facebook::react;
+@interface RCTBridge ()
+- (std::shared_ptr<facebook::react::MessageQueueThread>)jsMessageThread;
+@end
+
@interface RCTSurfacePresenter () <RCTSchedulerDelegate, RCTMountingManagerDelegate>
@end
@implementation RCTSurfacePresenter {
- RCTScheduler *_scheduler;
- RCTMountingManager *_mountingManager;
- RCTBridge *_bridge;
+ std::mutex _schedulerMutex;
+ std::mutex _contextContainerMutex;
+ RCTScheduler *_Nullable _scheduler; // Thread-safe. Mutation of the instance variable is protected by `_schedulerMutex`.
+ RCTMountingManager *_mountingManager; // Thread-safe.
+ RCTSurfaceRegistry *_surfaceRegistry; // Thread-safe.
+ RCTBridge *_bridge; // Unsafe. We are moving away from Bridge.
RCTBridge *_batchedBridge;
- RCTSurfaceRegistry *_surfaceRegistry;
+ std::shared_ptr<const ReactNativeConfig> _reactNativeConfig;
}
-- (instancetype)initWithBridge:(RCTBridge *)bridge
+- (instancetype)initWithBridge:(RCTBridge *)bridge config:(std::shared_ptr<const ReactNativeConfig>)config
{
if (self = [super init]) {
_bridge = bridge;
_batchedBridge = [_bridge batchedBridge] ?: _bridge;
- _scheduler = [[RCTScheduler alloc] init];
- _scheduler.delegate = self;
-
_surfaceRegistry = [[RCTSurfaceRegistry alloc] init];
+
_mountingManager = [[RCTMountingManager alloc] init];
_mountingManager.delegate = self;
+ if (config != nullptr) {
+ _reactNativeConfig = config;
+ } else {
+ _reactNativeConfig = std::make_shared<const EmptyReactNativeConfig>();
+ }
+
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleBridgeWillReloadNotification:)
name:RCTBridgeWillReloadNotification
@@ -67,18 +89,9 @@
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
-#pragma mark - RCTSchedulerDelegate
-
-- (void)schedulerDidComputeMutationInstructions:(facebook::react::TreeMutationInstructionList)instructions
- rootTag:(ReactTag)rootTag
+- (RCTComponentViewFactory *)componentViewFactory
{
- [_mountingManager mutateComponentViewTreeWithMutationInstructions:instructions
- rootTag:rootTag];
-}
-
-- (void)schedulerDidRequestPreliminaryViewAllocationWithComponentName:(NSString *)componentName
-{
- [_mountingManager preliminaryCreateComponentViewWithName:componentName];
+ return _mountingManager.componentViewRegistry.componentViewFactory;
}
#pragma mark - Internal Surface-dedicated Interface
@@ -86,20 +99,27 @@
- (void)registerSurface:(RCTFabricSurface *)surface
{
[_surfaceRegistry registerSurface:surface];
- [_scheduler registerRootTag:surface.rootTag];
- [self runSurface:surface];
+}
- // FIXME: Mutation instruction MUST produce instruction for root node.
- [_mountingManager.componentViewRegistry dequeueComponentViewWithName:@"Root" tag:surface.rootTag];
+- (void)startSurface:(RCTFabricSurface *)surface
+{
+ [self _startSurface:surface];
}
- (void)unregisterSurface:(RCTFabricSurface *)surface
{
- [self stopSurface:surface];
- [_scheduler unregisterRootTag:surface.rootTag];
+ [self _stopSurface:surface];
[_surfaceRegistry unregisterSurface:surface];
}
+- (void)setProps:(NSDictionary *)props
+ surface:(RCTFabricSurface *)surface
+{
+ // This implementation is suboptimal indeed but still better than nothing for now.
+ [self _stopSurface:surface];
+ [self _startSurface:surface];
+}
+
- (RCTFabricSurface *)surfaceForRootTag:(ReactTag)rootTag
{
return [_surfaceRegistry surfaceForRootTag:rootTag];
@@ -109,79 +129,204 @@
maximumSize:(CGSize)maximumSize
surface:(RCTFabricSurface *)surface
{
- LayoutContext layoutContext;
- layoutContext.pointScaleFactor = RCTScreenScale();
- LayoutConstraints layoutConstraints = {};
- layoutConstraints.minimumSize = RCTSizeFromCGSize(minimumSize);
- layoutConstraints.maximumSize = RCTSizeFromCGSize(maximumSize);
+ LayoutContext layoutContext = {
+ .pointScaleFactor = RCTScreenScale()
+ };
- return [_scheduler measureWithLayoutConstraints:layoutConstraints
+ LayoutConstraints layoutConstraints = {
+ .minimumSize = RCTSizeFromCGSize(minimumSize),
+ .maximumSize = RCTSizeFromCGSize(maximumSize)
+ };
+
+ return [self._scheduler measureSurfaceWithLayoutConstraints:layoutConstraints
layoutContext:layoutContext
- rootTag:surface.rootTag];
+ surfaceId:surface.rootTag];
}
- (void)setMinimumSize:(CGSize)minimumSize
maximumSize:(CGSize)maximumSize
surface:(RCTFabricSurface *)surface
{
- LayoutContext layoutContext;
- layoutContext.pointScaleFactor = RCTScreenScale();
- LayoutConstraints layoutConstraints = {};
- layoutConstraints.minimumSize = RCTSizeFromCGSize(minimumSize);
- layoutConstraints.maximumSize = RCTSizeFromCGSize(maximumSize);
+ LayoutContext layoutContext = {
+ .pointScaleFactor = RCTScreenScale()
+ };
- [_scheduler constraintLayoutWithLayoutConstraints:layoutConstraints
+ LayoutConstraints layoutConstraints = {
+ .minimumSize = RCTSizeFromCGSize(minimumSize),
+ .maximumSize = RCTSizeFromCGSize(maximumSize)
+ };
+
+ [self._scheduler constraintSurfaceLayoutWithLayoutConstraints:layoutConstraints
layoutContext:layoutContext
- rootTag:surface.rootTag];
+ surfaceId:surface.rootTag];
+}
+
+#pragma mark - Private
+
+- (RCTScheduler *)_scheduler
+{
+ std::lock_guard<std::mutex> lock(_schedulerMutex);
+
+ if (_scheduler) {
+ return _scheduler;
+ }
+
+ _scheduler = [[RCTScheduler alloc] initWithContextContainer:self.contextContainer];
+ _scheduler.delegate = self;
+
+ return _scheduler;
+}
+
+@synthesize contextContainer = _contextContainer;
+
+- (SharedContextContainer)contextContainer
+{
+ std::lock_guard<std::mutex> lock(_contextContainerMutex);
+
+ if (_contextContainer) {
+ return _contextContainer;
+ }
+
+ _contextContainer = std::make_shared<ContextContainer>();
+
+ _contextContainer->registerInstance(_reactNativeConfig, "ReactNativeConfig");
+
+ auto messageQueueThread = _batchedBridge.jsMessageThread;
+ auto runtime = (facebook::jsi::Runtime *)((RCTCxxBridge *)_batchedBridge).runtime;
+
+ RuntimeExecutor runtimeExecutor =
+ [runtime, messageQueueThread](std::function<void(facebook::jsi::Runtime &runtime)> &&callback) {
+ messageQueueThread->runOnQueue([runtime, callback = std::move(callback)]() {
+ callback(*runtime);
+ });
+ };
+
+ EventBeatFactory synchronousBeatFactory = [runtimeExecutor]() {
+ return std::make_unique<MainRunLoopEventBeat>(runtimeExecutor);
+ };
+
+ EventBeatFactory asynchronousBeatFactory = [runtimeExecutor]() {
+ return std::make_unique<RuntimeEventBeat>(runtimeExecutor);
+ };
+
+ _contextContainer->registerInstance<EventBeatFactory>(synchronousBeatFactory, "synchronous");
+ _contextContainer->registerInstance<EventBeatFactory>(asynchronousBeatFactory, "asynchronous");
+
+ _contextContainer->registerInstance(runtimeExecutor, "runtime-executor");
+
+ _contextContainer->registerInstance(std::make_shared<ImageManager>((__bridge void *)[_bridge imageLoader]), "ImageManager");
+ return _contextContainer;
}
-- (void)runSurface:(RCTFabricSurface *)surface
+- (void)_startSurface:(RCTFabricSurface *)surface
{
- NSDictionary *applicationParameters = @{
- @"rootTag": @(surface.rootTag),
- @"initialProps": surface.properties,
+ [_mountingManager.componentViewRegistry dequeueComponentViewWithComponentHandle:RootShadowNode::Handle()
+ tag:surface.rootTag];
+
+ LayoutContext layoutContext = {
+ .pointScaleFactor = RCTScreenScale()
+ };
+
+ LayoutConstraints layoutConstraints = {
+ .minimumSize = RCTSizeFromCGSize(surface.minimumSize),
+ .maximumSize = RCTSizeFromCGSize(surface.maximumSize)
};
- [_batchedBridge enqueueJSCall:@"AppRegistry" method:@"runApplication" args:@[surface.moduleName, applicationParameters] completion:NULL];
+ [self._scheduler startSurfaceWithSurfaceId:surface.rootTag
+ moduleName:surface.moduleName
+ initailProps:surface.properties
+ layoutConstraints:layoutConstraints
+ layoutContext:layoutContext];
+}
+
+- (void)_stopSurface:(RCTFabricSurface *)surface
+{
+ [self._scheduler stopSurfaceWithSurfaceId:surface.rootTag];
+
+ UIView<RCTComponentViewProtocol> *rootView =
+ [_mountingManager.componentViewRegistry componentViewByTag:surface.rootTag];
+ [_mountingManager.componentViewRegistry enqueueComponentViewWithComponentHandle:RootShadowNode::Handle()
+ tag:surface.rootTag
+ componentView:rootView];
+
+ [surface _unsetStage:(RCTSurfaceStagePrepared | RCTSurfaceStageMounted)];
+}
+
+- (void)_startAllSurfaces
+{
+ for (RCTFabricSurface *surface in _surfaceRegistry.enumerator) {
+ [self _startSurface:surface];
+ }
+}
+
+- (void)_stopAllSurfaces
+{
+ for (RCTFabricSurface *surface in _surfaceRegistry.enumerator) {
+ [self _stopSurface:surface];
+ }
+}
+
+#pragma mark - RCTSchedulerDelegate
+
+- (void)schedulerDidFinishTransaction:(facebook::react::ShadowViewMutationList)mutations
+ rootTag:(ReactTag)rootTag
+{
+ RCTFabricSurface *surface = [_surfaceRegistry surfaceForRootTag:rootTag];
+
+ [surface _setStage:RCTSurfaceStagePrepared];
+
+ [_mountingManager performTransactionWithMutations:mutations
+ rootTag:rootTag];
}
-- (void)stopSurface:(RCTFabricSurface *)surface
+- (void)schedulerOptimisticallyCreateComponentViewWithComponentHandle:(ComponentHandle)componentHandle
{
- [_batchedBridge enqueueJSCall:@"AppRegistry" method:@"unmountApplicationComponentAtRootTag" args:@[@(surface.rootTag)] completion:NULL];
+ [_mountingManager optimisticallyCreateComponentViewWithComponentHandle:componentHandle];
}
#pragma mark - RCTMountingManagerDelegate
- (void)mountingManager:(RCTMountingManager *)mountingManager willMountComponentsWithRootTag:(ReactTag)rootTag
{
- RCTIsMainQueue();
- // TODO: Propagate state change to Surface.
+ RCTAssertMainQueue();
+
+ // Does nothing.
}
- (void)mountingManager:(RCTMountingManager *)mountingManager didMountComponentsWithRootTag:(ReactTag)rootTag
{
- RCTIsMainQueue();
- RCTFabricSurface *surface = [_surfaceRegistry surfaceForRootTag:rootTag];
-
- // FIXME: Implement proper state propagation mechanism.
- [surface _setStage:RCTSurfaceStageSurfaceDidInitialRendering];
- [surface _setStage:RCTSurfaceStageSurfaceDidInitialLayout];
- [surface _setStage:RCTSurfaceStageSurfaceDidInitialMounting];
+ RCTAssertMainQueue();
+ RCTFabricSurface *surface = [_surfaceRegistry surfaceForRootTag:rootTag];
+ RCTSurfaceStage stage = surface.stage;
+ if (stage & RCTSurfaceStagePrepared) {
+ // We have to progress the stage only if the preparing phase is done.
+ if ([surface _setStage:RCTSurfaceStageMounted]) {
UIView *rootComponentView = [_mountingManager.componentViewRegistry componentViewByTag:rootTag];
-
surface.view.rootView = (RCTSurfaceRootView *)rootComponentView;
+ }
+ }
}
#pragma mark - Bridge events
- (void)handleBridgeWillReloadNotification:(NSNotification *)notification
{
- // TODO: Define a lifecycle contract for the pieces involved here including the scheduler, mounting manager, and
- // the surface registry. For now simply recreate the scheduler on reload.
- // The goal is to deallocate the Scheduler and its underlying references before the JS runtime is destroyed.
- _scheduler = [[RCTScheduler alloc] init];
- _scheduler.delegate = self;
+ {
+ std::lock_guard<std::mutex> lock(_schedulerMutex);
+ if (!_scheduler) {
+ // Seems we are already in the realoding process.
+ return;
+ }
+ }
+
+ [self _stopAllSurfaces];
+
+ {
+ std::lock_guard<std::mutex> lock(_schedulerMutex);
+ _scheduler = nil;
+ _contextContainer = nil;
+ }
}
- (void)handleJavaScriptDidLoadNotification:(NSNotification *)notification
@@ -189,6 +334,8 @@
RCTBridge *bridge = notification.userInfo[@"bridge"];
if (bridge != _batchedBridge) {
_batchedBridge = bridge;
+
+ [self _startAllSurfaces];
}
}
@@ -196,11 +343,6 @@
@implementation RCTSurfacePresenter (Deprecated)
-- (std::shared_ptr<FabricUIManager>)uiManager_DO_NOT_USE
-{
- return _scheduler.uiManager_DO_NOT_USE;
-}
-
- (RCTBridge *)bridge_DO_NOT_USE
{
return _bridge;
@@ -208,11 +350,16 @@
@end
-@implementation RCTBridge (RCTSurfacePresenter)
+@implementation RCTBridge (Deprecated)
+
+- (void)setSurfacePresenter:(RCTSurfacePresenter *)surfacePresenter
+{
+ objc_setAssociatedObject(self, @selector(surfacePresenter), surfacePresenter, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
- (RCTSurfacePresenter *)surfacePresenter
{
- return [self jsBoundExtraModuleForClass:[RCTSurfacePresenter class]];
+ return objc_getAssociatedObject(self, @selector(surfacePresenter));
}
@end

React/Fabric/RCTSurfaceRegistry.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -21,6 +21,8 @@
*/
@interface RCTSurfaceRegistry : NSObject
+- (NSEnumerator<RCTFabricSurface *> *)enumerator;
+
/**
* Adds Surface object into the registry.
* The registry does not retain Surface references.

React/Fabric/RCTSurfaceRegistry.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -20,12 +20,19 @@
{
if (self = [super init]) {
_registry = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsIntegerPersonality | NSPointerFunctionsOpaqueMemory
- valueOptions:NSPointerFunctionsObjectPersonality];
+ valueOptions:NSPointerFunctionsObjectPersonality | NSPointerFunctionsWeakMemory];
}
return self;
}
+- (NSEnumerator<RCTFabricSurface *> *)enumerator
+{
+ std::lock_guard<std::mutex> lock(_mutex);
+
+ return [_registry objectEnumerator];
+}
+
- (void)registerSurface:(RCTFabricSurface *)surface
{
std::lock_guard<std::mutex> lock(_mutex);

React/Fabric/RCTSurfaceTouchHandler.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Fabric/RCTSurfaceTouchHandler.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -8,11 +8,11 @@
#import "RCTSurfaceTouchHandler.h"
#import <UIKit/UIGestureRecognizerSubclass.h>
-#import <fabric/components/view/ViewEventEmitter.h>
#import <React/RCTUtils.h>
#import <React/RCTViewComponentView.h>
#import "RCTConversions.h"
+#import "RCTTouchableComponentViewProtocol.h"
using namespace facebook::react;
@@ -46,10 +46,6 @@
int lastIndex;
};
-@protocol RCTTouchableComponentViewProtocol <NSObject>
- - (SharedViewEventEmitter)touchEventEmitter;
-@end
-
typedef NS_ENUM(NSInteger, RCTTouchEventType) {
RCTTouchEventTypeTouchStart,
RCTTouchEventTypeTouchMove,
@@ -59,7 +55,7 @@
struct ActiveTouch {
Touch touch;
- SharedViewEventEmitter eventEmitter;
+ SharedTouchEventEmitter eventEmitter;
struct Hasher {
size_t operator()(const ActiveTouch &activeTouch) const {
@@ -95,8 +91,8 @@
ActiveTouch activeTouch = {};
- if ([componentView respondsToSelector:@selector(touchEventEmitter)]) {
- activeTouch.eventEmitter = [(id<RCTTouchableComponentViewProtocol>)componentView touchEventEmitter];
+ if ([componentView respondsToSelector:@selector(touchEventEmitterAtPoint:)]) {
+ activeTouch.eventEmitter = [(id<RCTTouchableComponentViewProtocol>)componentView touchEventEmitterAtPoint:[uiTouch locationInView:componentView]];
activeTouch.touch.target = (Tag)componentView.tag;
}
@@ -134,7 +130,7 @@
template<typename PointerT>
struct PointerHasher {
constexpr std::size_t operator()(const PointerT &value) const {
- return reinterpret_cast<size_t>(&value);
+ return reinterpret_cast<size_t>(value);
}
};
@@ -200,29 +196,39 @@
- (void)_updateTouches:(NSSet<UITouch *> *)touches
{
for (UITouch *touch in touches) {
- UpdateActiveTouchWithUITouch(_activeTouches[touch], touch, _rootComponentView);
+ UpdateActiveTouchWithUITouch(_activeTouches.at(touch), touch, _rootComponentView);
}
}
- (void)_unregisterTouches:(NSSet<UITouch *> *)touches
{
for (UITouch *touch in touches) {
- const auto &activeTouch = _activeTouches[touch];
+ const auto &activeTouch = _activeTouches.at(touch);
_identifierPool.enqueue(activeTouch.touch.identifier);
_activeTouches.erase(touch);
}
}
-- (void)_dispatchTouches:(NSSet<UITouch *> *)touches eventType:(RCTTouchEventType)eventType
+- (std::vector<ActiveTouch>)_activeTouchesFromTouches:(NSSet<UITouch *> *)touches
+{
+ std::vector<ActiveTouch> activeTouches;
+ activeTouches.reserve(touches.count);
+
+ for (UITouch *touch in touches) {
+ activeTouches.push_back(_activeTouches.at(touch));
+ }
+
+ return activeTouches;
+}
+
+- (void)_dispatchActiveTouches:(std::vector<ActiveTouch>)activeTouches eventType:(RCTTouchEventType)eventType
{
TouchEvent event = {};
std::unordered_set<ActiveTouch, ActiveTouch::Hasher, ActiveTouch::Comparator> changedActiveTouches = {};
- std::unordered_set<SharedViewEventEmitter> uniqueEventEmitter = {};
+ std::unordered_set<SharedTouchEventEmitter> uniqueEventEmitter = {};
BOOL isEndishEventType = eventType == RCTTouchEventTypeTouchEnd || eventType == RCTTouchEventTypeTouchCancel;
- for (UITouch *touch in touches) {
- const auto &activeTouch = _activeTouches[touch];
-
+ for (const auto &activeTouch : activeTouches) {
if (!activeTouch.eventEmitter) {
continue;
}
@@ -280,7 +286,8 @@
[super touchesBegan:touches withEvent:event];
[self _registerTouches:touches];
- [self _dispatchTouches:touches eventType:RCTTouchEventTypeTouchStart];
+ [self _dispatchActiveTouches:[self _activeTouchesFromTouches:touches]
+ eventType:RCTTouchEventTypeTouchStart];
if (self.state == UIGestureRecognizerStatePossible) {
self.state = UIGestureRecognizerStateBegan;
@@ -294,7 +301,8 @@
[super touchesMoved:touches withEvent:event];
[self _updateTouches:touches];
- [self _dispatchTouches:touches eventType:RCTTouchEventTypeTouchMove];
+ [self _dispatchActiveTouches:[self _activeTouchesFromTouches:touches]
+ eventType:RCTTouchEventTypeTouchMove];
self.state = UIGestureRecognizerStateChanged;
}
@@ -304,7 +312,8 @@
[super touchesEnded:touches withEvent:event];
[self _updateTouches:touches];
- [self _dispatchTouches:touches eventType:RCTTouchEventTypeTouchEnd];
+ [self _dispatchActiveTouches:[self _activeTouchesFromTouches:touches]
+ eventType:RCTTouchEventTypeTouchEnd];
[self _unregisterTouches:touches];
if (AllTouchesAreCancelledOrEnded(event.allTouches)) {
@@ -319,7 +328,8 @@
[super touchesCancelled:touches withEvent:event];
[self _updateTouches:touches];
- [self _dispatchTouches:touches eventType:RCTTouchEventTypeTouchCancel];
+ [self _dispatchActiveTouches:[self _activeTouchesFromTouches:touches]
+ eventType:RCTTouchEventTypeTouchCancel];
[self _unregisterTouches:touches];
if (AllTouchesAreCancelledOrEnded(event.allTouches)) {
@@ -331,10 +341,23 @@
- (void)reset
{
- // Technically, `_activeTouches` must be already empty at this point,
- // but just to be sure, we clear it explicitly.
+ [super reset];
+
+ if (_activeTouches.size() != 0) {
+ std::vector<ActiveTouch> activeTouches;
+ activeTouches.reserve(_activeTouches.size());
+
+ for (auto const &pair : _activeTouches) {
+ activeTouches.push_back(pair.second);
+ }
+
+ [self _dispatchActiveTouches:activeTouches
+ eventType:RCTTouchEventTypeTouchCancel];
+
+ // Force-unregistering all the touches.
_activeTouches.clear();
_identifierPool.reset();
+ }
}
- (BOOL)canPreventGestureRecognizer:(__unused UIGestureRecognizer *)preventedGestureRecognizer

React/Fabric/RCTTouchableComponentViewProtocol.h

@@ -0,0 +1,13 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#import <UIKit/UIKit.h>
+#import <react/components/view/TouchEventEmitter.h>
+
+@protocol RCTTouchableComponentViewProtocol <NSObject>
+- (facebook::react::SharedTouchEventEmitter)touchEventEmitterAtPoint:(CGPoint)point;
+@end

React/Fabric/Surface/RCTFabricSurface.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -43,10 +43,6 @@
@property (atomic, copy, readwrite) NSDictionary *properties;
-- (instancetype)initWithBridge:(RCTBridge *)bridge
- moduleName:(NSString *)moduleName
- initialProperties:(NSDictionary *)initialProperties;
-
- (instancetype)initWithSurfacePresenter:(RCTSurfacePresenter *)surfacePresenter
moduleName:(NSString *)moduleName
initialProperties:(NSDictionary *)initialProperties;
@@ -67,13 +63,28 @@
*/
- (RCTSurfaceView *)view;
+#pragma mark - Start & Stop
+
+/**
+ * Starts or stops the Surface.
+ * A Surface object can be stopped and then restarted.
+ * The starting process includes initializing all underlying React Native
+ * infrastructure and running React app.
+ * Just initialized Surface object starts automatically, there is no need
+ * to call `start` explicitly. Surface also stops itself on deallocation
+ * automatically.
+ * Returns YES in case of success. Returns NO if the Surface is already
+ * started or stopped.
+ */
+- (BOOL)start;
+- (BOOL)stop;
+
#pragma mark - Layout: Setting the size constrains
/**
* Sets `minimumSize` and `maximumSize` layout constraints for the Surface.
*/
-- (void)setMinimumSize:(CGSize)minimumSize
- maximumSize:(CGSize)maximumSize;
+- (void)setMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize;
/**
* Previously set `minimumSize` layout constraint.
@@ -98,8 +109,7 @@
* Measures the Surface with given constraints.
* This method does not cause any side effects on the surface object.
*/
-- (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize
- maximumSize:(CGSize)maximumSize;
+- (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize;
/**
* Return the current size of the root view based on (but not clamp by) current
@@ -120,13 +130,25 @@
@interface RCTFabricSurface (Internal)
-- (void)_setStage:(RCTSurfaceStage)stage;
+/**
+ * Sets and clears given stage flags (bitmask).
+ * Returns `YES` if the actual state was changed.
+ */
+- (BOOL)_setStage:(RCTSurfaceStage)stage;
+- (BOOL)_unsetStage:(RCTSurfaceStage)stage;
@end
@interface RCTFabricSurface (Deprecated)
/**
+ * Deprecated. Use `initWithSurfacePresenter:moduleName:initialProperties` instead.
+ */
+- (instancetype)initWithBridge:(RCTBridge *)bridge
+ moduleName:(NSString *)moduleName
+ initialProperties:(NSDictionary *)initialProperties;
+
+/**
* Deprecated. Use `rootTag` instead.
*/
@property (atomic, readonly) NSNumber *rootViewTag;

React/Fabric/Surface/RCTFabricSurfaceHostingProxyRootView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Fabric/Surface/RCTFabricSurfaceHostingProxyRootView.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,9 +11,13 @@
@implementation RCTFabricSurfaceHostingProxyRootView
-- (RCTSurface *)createSurfaceWithBridge:(RCTBridge *)bridge moduleName:(NSString *)moduleName initialProperties:(NSDictionary *)initialProperties
++ (RCTSurface *)createSurfaceWithBridge:(RCTBridge *)bridge
+ moduleName:(NSString *)moduleName
+ initialProperties:(NSDictionary *)initialProperties
{
- return (RCTSurface *)[[RCTFabricSurface alloc] initWithBridge:bridge moduleName:moduleName initialProperties:initialProperties];
+ return (RCTSurface *)[[RCTFabricSurface alloc] initWithBridge:bridge
+ moduleName:moduleName
+ initialProperties:initialProperties];
}
@end

React/Fabric/Surface/RCTFabricSurfaceHostingView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Fabric/Surface/RCTFabricSurfaceHostingView.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,6 +7,7 @@
#import "RCTFabricSurfaceHostingView.h"
+#import <React/RCTSurface.h>
#import "RCTFabricSurface.h"
@implementation RCTFabricSurfaceHostingView
@@ -19,6 +20,7 @@
RCTSurface *surface = (RCTSurface *)[[RCTFabricSurface alloc] initWithBridge:bridge
moduleName:moduleName
initialProperties:initialProperties];
+ [surface start];
return [self initWithSurface:surface sizeMeasureMode:sizeMeasureMode];
}

React/Fabric/Surface/RCTFabricSurface.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,22 +7,18 @@
#import "RCTFabricSurface.h"
-#import <React/RCTSurfaceView+Internal.h>
-
#import <mutex>
-#import <stdatomic.h>
#import <React/RCTAssert.h>
-#import <React/RCTBridge.h>
#import <React/RCTSurfaceDelegate.h>
#import <React/RCTSurfaceRootView.h>
-#import <React/RCTSurfaceView.h>
#import <React/RCTSurfaceTouchHandler.h>
+#import <React/RCTSurfaceView+Internal.h>
+#import <React/RCTSurfaceView.h>
#import <React/RCTUIManagerUtils.h>
#import <React/RCTUtils.h>
#import "RCTSurfacePresenter.h"
-#import "RCTMountingManager.h"
@implementation RCTFabricSurface {
// Immutable
@@ -42,19 +38,6 @@
RCTSurfaceTouchHandler *_Nullable _touchHandler;
}
-- (instancetype)initWithBridge:(RCTBridge *)bridge
- moduleName:(NSString *)moduleName
- initialProperties:(NSDictionary *)initialProperties
-{
- RCTAssert(bridge.valid, @"Valid bridge is required to instanciate `RCTSurface`.");
-
- self = [self initWithSurfacePresenter:bridge.surfacePresenter
- moduleName:moduleName
- initialProperties:initialProperties];
-
- return self;
-}
-
- (instancetype)initWithSurfacePresenter:(RCTSurfacePresenter *)surfacePresenter
moduleName:(NSString *)moduleName
initialProperties:(NSDictionary *)initialProperties
@@ -66,35 +49,43 @@
_rootTag = [RCTAllocateRootViewTag() integerValue];
_minimumSize = CGSizeZero;
- _maximumSize = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX);
+ // FIXME: Replace with `_maximumSize = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX);`.
+ _maximumSize = RCTScreenSize();
+
+ _touchHandler = [RCTSurfaceTouchHandler new];
_stage = RCTSurfaceStageSurfaceDidInitialize;
- _touchHandler = [RCTSurfaceTouchHandler new];
+ [_surfacePresenter registerSurface:self];
+ }
+
+ return self;
+}
+
+- (BOOL)start
+{
+ if (![self _setStage:RCTSurfaceStageStarted]) {
+ return NO;
+ }
- [self _run];
+ [_surfacePresenter startSurface:self];
- // TODO: This will be moved to RCTSurfacePresenter.
- RCTBridge *bridge = surfacePresenter.bridge_DO_NOT_USE;
+ return YES;
+}
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(handleJavaScriptWillStartLoadingNotification:)
- name:RCTJavaScriptWillStartLoadingNotification
- object:bridge];
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(handleJavaScriptDidLoadNotification:)
- name:RCTJavaScriptDidLoadNotification
- object:bridge];
+- (BOOL)stop
+{
+ if (![self _unsetStage:RCTSurfaceStageStarted]) {
+ return NO;
}
- return self;
+ [_surfacePresenter unregisterSurface:self];
+ return YES;
}
- (void)dealloc
{
- [[NSNotificationCenter defaultCenter] removeObserver:self];
-
- [self _stop];
+ [self stop];
}
#pragma mark - Immutable Properties (no need to enforce synchonization)
@@ -104,11 +95,6 @@
return _moduleName;
}
-- (NSNumber *)rootViewTag
-{
- return @(_rootTag);
-}
-
#pragma mark - Main-Threaded Routines
- (RCTSurfaceView *)view
@@ -131,21 +117,37 @@
return _stage;
}
-- (void)_setStage:(RCTSurfaceStage)stage
+- (BOOL)_setStage:(RCTSurfaceStage)stage
+{
+ return [self _setStage:stage setOrUnset:YES];
+}
+
+- (BOOL)_unsetStage:(RCTSurfaceStage)stage
+{
+ return [self _setStage:stage setOrUnset:NO];
+}
+
+- (BOOL)_setStage:(RCTSurfaceStage)stage setOrUnset:(BOOL)setOrUnset
{
RCTSurfaceStage updatedStage;
{
std::lock_guard<std::mutex> lock(_mutex);
- if (_stage & stage) {
- return;
+ if (setOrUnset) {
+ updatedStage = (RCTSurfaceStage)(_stage | stage);
+ } else {
+ updatedStage = (RCTSurfaceStage)(_stage & ~stage);
+ }
+
+ if (updatedStage == _stage) {
+ return NO;
}
- updatedStage = (RCTSurfaceStage)(_stage | stage);
_stage = updatedStage;
}
[self _propagateStageChange:updatedStage];
+ return YES;
}
- (void)_propagateStageChange:(RCTSurfaceStage)stage
@@ -182,31 +184,14 @@
_properties = [properties copy];
}
- [self _run];
-}
-
-#pragma mark - Running
-
-- (void)_run
-{
- [_surfacePresenter registerSurface:self];
- [self _setStage:RCTSurfaceStageSurfaceDidRun];
-}
-
-- (void)_stop
-{
- [_surfacePresenter unregisterSurface:self];
- [self _setStage:RCTSurfaceStageSurfaceDidStop];
+ [_surfacePresenter setProps:properties surface:self];
}
#pragma mark - Layout
-- (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize
- maximumSize:(CGSize)maximumSize
+- (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize
{
- return [_surfacePresenter sizeThatFitsMinimumSize:minimumSize
- maximumSize:maximumSize
- surface:self];
+ return [_surfacePresenter sizeThatFitsMinimumSize:minimumSize maximumSize:maximumSize surface:self];
}
#pragma mark - Size Constraints
@@ -216,13 +201,11 @@
[self setMinimumSize:size maximumSize:size];
}
-- (void)setMinimumSize:(CGSize)minimumSize
- maximumSize:(CGSize)maximumSize
+- (void)setMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize
{
{
std::lock_guard<std::mutex> lock(_mutex);
- if (CGSizeEqualToSize(minimumSize, _minimumSize) &&
- CGSizeEqualToSize(maximumSize, _maximumSize)) {
+ if (CGSizeEqualToSize(minimumSize, _minimumSize) && CGSizeEqualToSize(maximumSize, _maximumSize)) {
return;
}
@@ -230,9 +213,7 @@
_minimumSize = minimumSize;
}
- return [_surfacePresenter setMinimumSize:minimumSize
- maximumSize:maximumSize
- surface:self];
+ [_surfacePresenter setMinimumSize:minimumSize maximumSize:maximumSize surface:self];
}
- (CGSize)minimumSize
@@ -281,41 +262,20 @@
return NO;
}
-#pragma mark - Bridge events
+#pragma mark - Deprecated
-- (void)handleJavaScriptWillStartLoadingNotification:(NSNotification *)notification
+- (instancetype)initWithBridge:(RCTBridge *)bridge
+ moduleName:(NSString *)moduleName
+ initialProperties:(NSDictionary *)initialProperties
{
- // TODO: Move the bridge lifecycle handling up to the RCTSurfacePresenter.
-
- RCTAssertMainQueue();
-
- // Reset states because the bridge is reloading. This is similar to initialization phase.
- _stage = RCTSurfaceStageSurfaceDidInitialize;
- _view = nil;
- _touchHandler = [RCTSurfaceTouchHandler new];
- [self _setStage:RCTSurfaceStageBridgeDidLoad];
+ return [self initWithSurfacePresenter:bridge.surfacePresenter
+ moduleName:moduleName
+ initialProperties:initialProperties];
}
-- (void)handleJavaScriptDidLoadNotification:(NSNotification *)notification
+- (NSNumber *)rootViewTag
{
- // TODO: Move the bridge lifecycle handling up to the RCTSurfacePresenter.
-
- // Note: this covers both JS reloads and initial load after the bridge starts.
- // When it's not a reload, surface should already be running since we run it immediately in the initializer, so do
- // nothing.
- // When it's a reload, we rely on the `RCTJavaScriptWillStartLoadingNotification` notification to reset the stage,
- // then we need to run the surface and update its size.
- if (!RCTSurfaceStageIsRunning(_stage)) {
- [self _setStage:RCTSurfaceStageModuleDidLoad];
- [self _run];
-
- // After a reload surfacePresenter needs to know the last min/max size for this surface, because the surface hosting
- // view was already attached to the ViewController's view.
- // TODO: Find a better automatic way.
- [_surfacePresenter setMinimumSize:_minimumSize
- maximumSize:_maximumSize
- surface:self];
- }
+ return @(_rootTag);
}
@end

React/Fabric/Utils/MainQueueExecutor.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,10 +10,8 @@
namespace facebook {
namespace react {
-class MainQueueExecutor:
- public folly::Executor {
-
-public:
+class MainQueueExecutor : public folly::Executor {
+ public:
static MainQueueExecutor &instance();
void add(folly::Func function) override;

React/Fabric/Utils/MainQueueExecutor.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -13,12 +13,14 @@
namespace facebook {
namespace react {
-MainQueueExecutor &MainQueueExecutor::instance() {
+MainQueueExecutor &MainQueueExecutor::instance()
+{
static auto instance = folly::Indestructible<MainQueueExecutor>{};
return *instance;
}
-void MainQueueExecutor::add(folly::Func function) {
+void MainQueueExecutor::add(folly::Func function)
+{
__block folly::Func blockFunction = std::move(function);
dispatch_async(dispatch_get_main_queue(), ^{
blockFunction();

React/Fabric/Utils/MainRunLoopEventBeat.h

@@ -0,0 +1,35 @@
+// 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.
+
+#pragma once
+
+#include <CoreFoundation/CFRunLoop.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <react/events/EventBeat.h>
+#include <react/uimanager/primitives.h>
+
+namespace facebook {
+namespace react {
+
+/*
+ * Event beat associated with main run loop cycle.
+ * The callback is always called on the main thread.
+ */
+class MainRunLoopEventBeat final : public EventBeat {
+ public:
+ MainRunLoopEventBeat(RuntimeExecutor runtimeExecutor);
+ ~MainRunLoopEventBeat();
+
+ void induce() const override;
+
+ private:
+ void lockExecutorAndBeat() const;
+
+ const RuntimeExecutor runtimeExecutor_;
+ CFRunLoopObserverRef mainRunLoopObserver_;
+};
+
+} // namespace react
+} // namespace facebook

React/Fabric/Utils/MainRunLoopEventBeat.mm

@@ -0,0 +1,82 @@
+// 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.
+
+#import "MainRunLoopEventBeat.h"
+
+#import <React/RCTUtils.h>
+#import <mutex>
+
+namespace facebook {
+namespace react {
+
+MainRunLoopEventBeat::MainRunLoopEventBeat(RuntimeExecutor runtimeExecutor)
+ : runtimeExecutor_(std::move(runtimeExecutor))
+{
+ mainRunLoopObserver_ = CFRunLoopObserverCreateWithHandler(
+ NULL /* allocator */,
+ kCFRunLoopBeforeWaiting /* activities */,
+ true /* repeats */,
+ 0 /* order */,
+ ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
+ if (!this->isRequested_) {
+ return;
+ }
+
+ this->lockExecutorAndBeat();
+ });
+
+ assert(mainRunLoopObserver_);
+
+ CFRunLoopAddObserver(CFRunLoopGetMain(), mainRunLoopObserver_, kCFRunLoopCommonModes);
+}
+
+MainRunLoopEventBeat::~MainRunLoopEventBeat()
+{
+ CFRunLoopRemoveObserver(CFRunLoopGetMain(), mainRunLoopObserver_, kCFRunLoopCommonModes);
+ CFRelease(mainRunLoopObserver_);
+}
+
+void MainRunLoopEventBeat::induce() const
+{
+ if (!this->isRequested_) {
+ return;
+ }
+
+ RCTExecuteOnMainQueue(^{
+ this->lockExecutorAndBeat();
+ });
+}
+
+void MainRunLoopEventBeat::lockExecutorAndBeat() const
+{
+ // Note: We need the third mutex to get back to the main thread before
+ // the lambda is finished (because all mutexes are allocated on the stack).
+
+ std::mutex mutex1;
+ std::mutex mutex2;
+ std::mutex mutex3;
+
+ mutex1.lock();
+ mutex2.lock();
+ mutex3.lock();
+
+ jsi::Runtime *runtimePtr;
+
+ runtimeExecutor_([&](jsi::Runtime &runtime) {
+ runtimePtr = &runtime;
+ mutex1.unlock();
+ // `beat` is called somewhere here.
+ mutex2.lock();
+ mutex3.unlock();
+ });
+
+ mutex1.lock();
+ beat(*runtimePtr);
+ mutex2.unlock();
+ mutex3.lock();
+}
+
+} // namespace react
+} // namespace facebook

React/Fabric/Utils/RuntimeEventBeat.h

@@ -0,0 +1,35 @@
+/**
+ * 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.
+ */
+
+#include <CoreFoundation/CFRunLoop.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <react/events/EventBeat.h>
+#include <react/uimanager/primitives.h>
+
+namespace facebook {
+namespace react {
+
+/*
+ * Event beat associated with JavaScript runtime.
+ * The beat is called on `RuntimeExecutor`'s thread induced by the main thread
+ * event loop.
+ */
+class RuntimeEventBeat : public EventBeat {
+ public:
+ RuntimeEventBeat(RuntimeExecutor runtimeExecutor);
+ ~RuntimeEventBeat();
+
+ void induce() const override;
+
+ private:
+ const RuntimeExecutor runtimeExecutor_;
+ CFRunLoopObserverRef mainRunLoopObserver_;
+ mutable std::atomic<bool> isBusy_{false};
+};
+
+} // namespace react
+} // namespace facebook

React/Fabric/Utils/RuntimeEventBeat.mm

@@ -0,0 +1,70 @@
+/**
+ * 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.
+ */
+
+#include "RuntimeEventBeat.h"
+
+namespace facebook {
+namespace react {
+
+RuntimeEventBeat::RuntimeEventBeat(RuntimeExecutor runtimeExecutor) : runtimeExecutor_(std::move(runtimeExecutor))
+{
+ mainRunLoopObserver_ = CFRunLoopObserverCreateWithHandler(
+ NULL /* allocator */,
+ kCFRunLoopBeforeWaiting /* activities */,
+ true /* repeats */,
+ 0 /* order */,
+ ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
+ // Note: We only `induce` beat here; actual beat will be performed on
+ // a different thread.
+ this->induce();
+ });
+
+ assert(mainRunLoopObserver_);
+
+ CFRunLoopAddObserver(CFRunLoopGetMain(), mainRunLoopObserver_, kCFRunLoopCommonModes);
+}
+
+RuntimeEventBeat::~RuntimeEventBeat()
+{
+ CFRunLoopRemoveObserver(CFRunLoopGetMain(), mainRunLoopObserver_, kCFRunLoopCommonModes);
+ CFRelease(mainRunLoopObserver_);
+}
+
+void RuntimeEventBeat::induce() const
+{
+ if (!isRequested_ || isBusy_) {
+ return;
+ }
+
+#ifndef NDEBUG
+ // We do a trick here.
+ // If `wasExecuted` was destroyed before set to `true`,
+ // it means that the execution block was deallocated not being executed.
+ // This indicates that `messageQueueThread_` is being deallocated.
+ // This trick is quite expensive due to deallocation and messing with atomic
+ // counters. Seems we need this only for making hot-reloading mechanism
+ // thread-safe. Hence, let's leave it to be DEBUG-only for now.
+ auto wasExecuted = std::shared_ptr<bool>(new bool{false}, [this](bool *wasExecuted) {
+ if (!*wasExecuted && failCallback_) {
+ failCallback_();
+ }
+ delete wasExecuted;
+ });
+#endif
+
+ isBusy_ = true;
+ runtimeExecutor_([=](jsi::Runtime &runtime) mutable {
+ this->beat(runtime);
+ isBusy_ = false;
+#ifndef NDEBUG
+ *wasExecuted = true;
+#endif
+ });
+}
+
+} // namespace react
+} // namespace facebook

React/Inspector/RCTInspector.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

React/Inspector/RCTInspector.mm

@@ -1,9 +1,12 @@
+// 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.
#import "RCTInspector.h"
#if RCT_DEV
-#include <jschelpers/JavaScriptCore.h>
#include <jsinspector/InspectorInterfaces.h>
#import "RCTDefines.h"

React/Inspector/RCTInspectorPackagerConnection.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

React/Inspector/RCTInspectorPackagerConnection.m

@@ -1,3 +1,8 @@
+// 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.
+
#import "RCTInspectorPackagerConnection.h"
#if RCT_DEV
@@ -196,7 +201,7 @@
[self abort:@"Websocket exception"
withCause:error];
}
- if (!_closed) {
+ if (!_closed && [error code] != ECONNREFUSED) {
[self reconnect];
}
}

React/Modules/RCTAccessibilityManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTAccessibilityManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTAlertManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTAlertManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -177,7 +177,9 @@
}
[_alertControllers addObject:alertController];
+ dispatch_async(dispatch_get_main_queue(), ^{
[presentingController presentViewController:alertController animated:YES completion:nil];
+ });
}
@end

React/Modules/RCTAppState.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTAppState.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -49,6 +49,11 @@
- (NSDictionary *)constantsToExport
{
+ return [self getConstants];
+}
+
+- (NSDictionary *)getConstants
+{
return @{@"initialAppState": RCTCurrentAppBackgroundState()};
}

React/Modules/RCTAsyncLocalStorage.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -31,4 +31,11 @@
// For clearing data when the bridge may not exist, e.g. when logging out.
+ (void)clearAllData;
+// Grab data from the cache. ResponseBlock result array will have an error at position 0, and an array of arrays at position 1.
+- (void)multiGet:(NSArray<NSString *> *)keys callback:(RCTResponseSenderBlock)callback;
+
+// Add multiple key value pairs to the cache.
+- (void)multiSet:(NSArray<NSArray<NSString *> *> *)kvPairs callback:(RCTResponseSenderBlock)callback;
+
+
@end

React/Modules/RCTAsyncLocalStorage.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -423,10 +423,8 @@
NSString *filePath = [self _filePathForKey:key];
[[NSFileManager defaultManager] removeItemAtPath:filePath error:nil];
[RCTGetCache() removeObjectForKey:key];
- // remove the key from manifest, but no need to mark as changed just for
- // this, as the cost of checking again next time is negligible.
- [_manifest removeObjectForKey:key];
- } else if (_manifest[key]) {
+ }
+ if (_manifest[key]) {
changedManifest = YES;
[_manifest removeObjectForKey:key];
}

React/Modules/RCTClipboard.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTClipboard.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTDeviceInfo.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTDeviceInfo.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -105,6 +105,11 @@
- (NSDictionary<NSString *, id> *)constantsToExport
{
+ return [self getConstants];
+}
+
+- (NSDictionary<NSString *, id> *)getConstants
+{
return @{
@"Dimensions": RCTExportedDimensions(_bridge),
// Note:

React/Modules/RCTDevSettings.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -72,11 +72,6 @@
- (void)toggleElementInspector;
/**
- * Toggle JSC's sampling profiler.
- */
-- (void)toggleJSCSamplingProfiler;
-
-/**
* Enables starting of profiling sampler on launch
*/
@property (nonatomic, assign) BOOL startSamplingProfilerOnLaunch;

React/Modules/RCTDevSettings.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,14 +9,9 @@
#import <objc/runtime.h>
-#import <JavaScriptCore/JavaScriptCore.h>
-
-#import <jschelpers/JavaScriptCore.h>
-
#import "RCTBridge+Private.h"
#import "RCTBridgeModule.h"
#import "RCTEventDispatcher.h"
-#import "RCTJSCSamplingProfiler.h"
#import "RCTLog.h"
#import "RCTProfile.h"
#import "RCTUtils.h"
@@ -29,7 +24,6 @@
static NSString *const kRCTDevSettingExecutorOverrideClass = @"executor-override";
static NSString *const kRCTDevSettingShakeToShowDevMenu = @"shakeToShow";
static NSString *const kRCTDevSettingIsPerfMonitorShown = @"RCTPerfMonitorKey";
-static NSString *const kRCTDevSettingStartSamplingProfilerOnLaunch = @"startSamplingProfilerOnLaunch";
static NSString *const kRCTDevSettingsUserDefaultsKey = @"RCTDevMenu";
@@ -40,7 +34,6 @@
#if RCT_ENABLE_INSPECTOR
#import "RCTInspectorDevServerHelper.h"
-#import <jschelpers/JSCWrapper.h>
#endif
#if RCT_DEV
@@ -112,7 +105,6 @@
BOOL _isJSLoaded;
#if ENABLE_PACKAGER_CONNECTION
RCTHandlerToken _reloadToken;
- RCTHandlerToken _pokeSamplingProfilerToken;
#endif
}
@@ -177,14 +169,6 @@
}
queue:dispatch_get_main_queue()
forMethod:@"reload"];
-
- _pokeSamplingProfilerToken =
- [[RCTPackagerConnection sharedPackagerConnection]
- addRequestHandler:^(NSDictionary<NSString *, id> *params, RCTPackagerClientResponder *responder) {
- pokeSamplingProfiler(weakBridge, responder);
- }
- queue:dispatch_get_main_queue()
- forMethod:@"pokeSamplingProfiler"];
#endif
#if RCT_ENABLE_INSPECTOR
@@ -201,32 +185,6 @@
#endif
}
-#if ENABLE_PACKAGER_CONNECTION
-static void pokeSamplingProfiler(RCTBridge *const bridge, RCTPackagerClientResponder *const responder)
-{
- if (!bridge) {
- [responder respondWithError:@"The bridge is nil. Try again."];
- return;
- }
-
- JSGlobalContextRef globalContext = bridge.jsContextRef;
- if (!JSC_JSSamplingProfilerEnabled(globalContext)) {
- [responder respondWithError:@"The JSSamplingProfiler is disabled. See 'iOS specific setup' section here https://fburl.com/u4lw7xeq for some help"];
- return;
- }
-
- // JSPokeSamplingProfiler() toggles the profiling process
- JSValueRef jsResult = JSC_JSPokeSamplingProfiler(globalContext);
- if (JSC_JSValueGetType(globalContext, jsResult) == kJSTypeNull) {
- [responder respondWithResult:@"started"];
- } else {
- JSContext *context = [JSC_JSContext(globalContext) contextWithJSGlobalContextRef:globalContext];
- NSString *results = [[JSC_JSValue(globalContext) valueWithJSValueRef:jsResult inContext:context] toObject];
- [responder respondWithResult:results];
- }
-}
-#endif
-
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
@@ -237,7 +195,6 @@
[_liveReloadUpdateTask cancel];
#if ENABLE_PACKAGER_CONNECTION
[[RCTPackagerConnection sharedPackagerConnection] removeHandler:_reloadToken];
- [[RCTPackagerConnection sharedPackagerConnection] removeHandler:_pokeSamplingProfilerToken];
#endif
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
@@ -277,11 +234,6 @@
return (_liveReloadURL != nil);
}
-- (BOOL)isJSCSamplingProfilerAvailable
-{
- return JSC_JSSamplingProfilerEnabled(_bridge.jsContextRef);
-}
-
RCT_EXPORT_METHOD(reload)
{
[_bridge reload];
@@ -394,20 +346,6 @@
}
}
-- (void)toggleJSCSamplingProfiler
-{
- JSGlobalContextRef globalContext = _bridge.jsContextRef;
- // JSPokeSamplingProfiler() toggles the profiling process
- JSValueRef jsResult = JSC_JSPokeSamplingProfiler(globalContext);
-
- if (JSC_JSValueGetType(globalContext, jsResult) != kJSTypeNull) {
- JSContext *context = [JSC_JSContext(globalContext) contextWithJSGlobalContextRef:globalContext];
- NSString *results = [[JSC_JSValue(globalContext) valueWithJSValueRef:jsResult inContext:context] toObject];
- RCTJSCSamplingProfiler *profilerModule = [_bridge moduleForClass:[RCTJSCSamplingProfiler class]];
- [profilerModule operationCompletedWithResults:results];
- }
-}
-
- (BOOL)isElementInspectorShown
{
return [[self settingForKey:kRCTDevSettingIsInspectorShown] boolValue];
@@ -423,16 +361,6 @@
return [[self settingForKey:kRCTDevSettingIsPerfMonitorShown] boolValue];
}
-- (void)setStartSamplingProfilerOnLaunch:(BOOL)startSamplingProfilerOnLaunch
-{
- [self _updateSettingWithValue:@(startSamplingProfilerOnLaunch) forKey:kRCTDevSettingStartSamplingProfilerOnLaunch];
-}
-
-- (BOOL)startSamplingProfilerOnLaunch
-{
- return [[self settingForKey:kRCTDevSettingStartSamplingProfilerOnLaunch] boolValue];
-}
-
- (void)setExecutorClass:(Class)executorClass
{
_executorClass = executorClass;
@@ -554,7 +482,6 @@
- (id)settingForKey:(NSString *)key { return nil; }
- (void)reload {}
- (void)toggleElementInspector {}
-- (void)toggleJSCSamplingProfiler {}
@end

React/Modules/RCTEventEmitter.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTEventEmitter.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTExceptionsManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTExceptionsManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTI18nManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTI18nManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -34,6 +34,11 @@
- (NSDictionary *)constantsToExport
{
+ return [self getConstants];
+}
+
+- (NSDictionary *)getConstants
+{
return @{
@"isRTL": @([[RCTI18nUtil sharedInstance] isRTL]),
@"doLeftAndRightSwapInRTL": @([[RCTI18nUtil sharedInstance] doLeftAndRightSwapInRTL])

React/Modules/RCTI18nUtil.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTI18nUtil.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTJSCSamplingProfiler.h

@@ -1,21 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#import <Foundation/Foundation.h>
-
-#import <React/RCTBridgeModule.h>
-
-@interface RCTJSCSamplingProfiler : NSObject <RCTBridgeModule>
-
-/**
- * Receives a JSON string containing the result of a JSC CPU Profiling run,
- * and sends them to the packager to be symbolicated and saved to disk.
- * It is safe to call this method from any thread.
- */
-- (void)operationCompletedWithResults:(NSString *)results;
-
-@end

React/Modules/RCTJSCSamplingProfiler.m

@@ -1,59 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#import "RCTJSCSamplingProfiler.h"
-
-#import "RCTBridge.h"
-#import "RCTLog.h"
-
-@implementation RCTJSCSamplingProfiler
-
-@synthesize methodQueue = _methodQueue;
-@synthesize bridge = _bridge;
-
-RCT_EXPORT_MODULE(RCTJSCSamplingProfiler);
-
-#ifdef RCT_PROFILE
-RCT_EXPORT_METHOD(operationComplete:(__unused int)token result:(id)profileData error:(id)error)
-{
- if (error) {
- RCTLogError(@"JSC Sampling profiler ended with error: %@", error);
- return;
- }
-
- // Create a POST request with all of the datas
- NSURL *url = [NSURL URLWithString:@"/jsc-profile" relativeToURL:self.bridge.bundleURL];
- NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
- cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
- timeoutInterval:60];
- [request setHTTPMethod:@"POST"];
- [request setHTTPBody:[profileData dataUsingEncoding:NSUTF8StringEncoding]];
-
- // Send the request
- NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
- NSURLSessionDataTask *sessionDataTask = [session dataTaskWithRequest:request completionHandler:^(__unused NSData *data, __unused NSURLResponse *response, NSError *sessionError) {
- if (sessionError) {
- RCTLogWarn(@"JS CPU Profile data failed to send. Is the packager server running locally?\nDetails: %@", error);
- } else {
- RCTLogInfo(@"JS CPU Profile data sent successfully.");
- }
- }];
-
- [sessionDataTask resume];
-}
-
-- (void)operationCompletedWithResults:(NSString *)results
-{
- // Send the results to the packager, using the module's queue.
- dispatch_async(self.methodQueue, ^{
- [self operationComplete:0 result:results error:nil];
- });
-}
-
-#endif
-
-@end

React/Modules/RCTKeyboardObserver.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTKeyboardObserver.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -110,12 +110,14 @@
CGRect endFrame = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
NSTimeInterval duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
UIViewAnimationCurve curve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];
+ NSInteger isLocalUserInfoKey = [userInfo[UIKeyboardIsLocalUserInfoKey] integerValue];
return @{
@"startCoordinates": RCTRectDictionaryValue(beginFrame),
@"endCoordinates": RCTRectDictionaryValue(endFrame),
@"duration": @(duration * 1000.0), // ms
@"easing": RCTAnimationNameForCurve(curve),
+ @"isEventFromThisApp": isLocalUserInfoKey == 1 ? @YES : @NO,
};
#endif
}

React/Modules/RCTLayoutAnimationGroup.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTLayoutAnimationGroup.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTLayoutAnimation.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTLayoutAnimation.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTRedBoxExtraDataViewController.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTRedBoxExtraDataViewController.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTRedBox.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTRedBox.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -47,7 +47,7 @@
#else
self.windowLevel = UIWindowLevelStatusBar - 1;
#endif
- self.backgroundColor = [UIColor colorWithRed:0.8 green:0 blue:0 alpha:1];
+ self.backgroundColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1];
self.hidden = YES;
UIViewController *rootController = [UIViewController new];
@@ -58,7 +58,7 @@
const CGFloat buttonHeight = 60;
CGRect detailsFrame = rootView.bounds;
- detailsFrame.size.height -= buttonHeight;
+ detailsFrame.size.height -= buttonHeight + [self bottomSafeViewHeight];
_stackTraceTableView = [[UITableView alloc] initWithFrame:detailsFrame style:UITableViewStylePlain];
_stackTraceTableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
@@ -73,10 +73,10 @@
[rootView addSubview:_stackTraceTableView];
#if TARGET_OS_SIMULATOR
- NSString *reloadText = @"Reload JS (\u2318R)";
- NSString *dismissText = @"Dismiss (ESC)";
- NSString *copyText = @"Copy (\u2325\u2318C)";
- NSString *extraText = @"Extra Info (\u2318E)";
+ NSString *reloadText = @"Reload\n(\u2318R)";
+ NSString *dismissText = @"Dismiss\n(ESC)";
+ NSString *copyText = @"Copy\n(\u2325\u2318C)";
+ NSString *extraText = @"Extra Info\n(\u2318E)";
#else
NSString *reloadText = @"Reload JS";
NSString *dismissText = @"Dismiss";
@@ -88,53 +88,85 @@
dismissButton.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin;
dismissButton.accessibilityIdentifier = @"redbox-dismiss";
dismissButton.titleLabel.font = [UIFont systemFontOfSize:13];
+ dismissButton.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
+ dismissButton.titleLabel.textAlignment = NSTextAlignmentCenter;
+ dismissButton.backgroundColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1];
[dismissButton setTitle:dismissText forState:UIControlStateNormal];
- [dismissButton setTitleColor:[UIColor colorWithWhite:1 alpha:0.5] forState:UIControlStateNormal];
- [dismissButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted];
+ [dismissButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
+ [dismissButton setTitleColor:[UIColor colorWithWhite:1 alpha:0.5] forState:UIControlStateHighlighted];
[dismissButton addTarget:self action:@selector(dismiss) forControlEvents:UIControlEventTouchUpInside];
UIButton *reloadButton = [UIButton buttonWithType:UIButtonTypeCustom];
reloadButton.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin;
reloadButton.accessibilityIdentifier = @"redbox-reload";
reloadButton.titleLabel.font = [UIFont systemFontOfSize:13];
-
+ reloadButton.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
+ reloadButton.titleLabel.textAlignment = NSTextAlignmentCenter;
+ reloadButton.backgroundColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1];
[reloadButton setTitle:reloadText forState:UIControlStateNormal];
- [reloadButton setTitleColor:[UIColor colorWithWhite:1 alpha:0.5] forState:UIControlStateNormal];
- [reloadButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted];
+ [reloadButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
+ [reloadButton setTitleColor:[UIColor colorWithWhite:1 alpha:0.5] forState:UIControlStateHighlighted];
[reloadButton addTarget:self action:@selector(reload) forControlEvents:UIControlEventTouchUpInside];
UIButton *copyButton = [UIButton buttonWithType:UIButtonTypeCustom];
copyButton.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin;
copyButton.accessibilityIdentifier = @"redbox-copy";
copyButton.titleLabel.font = [UIFont systemFontOfSize:13];
+ copyButton.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
+ copyButton.titleLabel.textAlignment = NSTextAlignmentCenter;
+ copyButton.backgroundColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1];
[copyButton setTitle:copyText forState:UIControlStateNormal];
- [copyButton setTitleColor:[UIColor colorWithWhite:1 alpha:0.5] forState:UIControlStateNormal];
- [copyButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted];
+ [copyButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
+ [copyButton setTitleColor:[UIColor colorWithWhite:1 alpha:0.5] forState:UIControlStateHighlighted];
[copyButton addTarget:self action:@selector(copyStack) forControlEvents:UIControlEventTouchUpInside];
UIButton *extraButton = [UIButton buttonWithType:UIButtonTypeCustom];
extraButton.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin;
extraButton.accessibilityIdentifier = @"redbox-extra";
extraButton.titleLabel.font = [UIFont systemFontOfSize:13];
+ extraButton.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
+ extraButton.titleLabel.textAlignment = NSTextAlignmentCenter;
+ extraButton.backgroundColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1];
[extraButton setTitle:extraText forState:UIControlStateNormal];
- [extraButton setTitleColor:[UIColor colorWithWhite:1 alpha:0.5] forState:UIControlStateNormal];
- [extraButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted];
+ [extraButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
+ [extraButton setTitleColor:[UIColor colorWithWhite:1 alpha:0.5] forState:UIControlStateHighlighted];
[extraButton addTarget:self action:@selector(showExtraDataViewController) forControlEvents:UIControlEventTouchUpInside];
CGFloat buttonWidth = self.bounds.size.width / 4;
- dismissButton.frame = CGRectMake(0, self.bounds.size.height - buttonHeight, buttonWidth, buttonHeight);
- reloadButton.frame = CGRectMake(buttonWidth, self.bounds.size.height - buttonHeight, buttonWidth, buttonHeight);
- copyButton.frame = CGRectMake(buttonWidth * 2, self.bounds.size.height - buttonHeight, buttonWidth, buttonHeight);
- extraButton.frame = CGRectMake(buttonWidth * 3, self.bounds.size.height - buttonHeight, buttonWidth, buttonHeight);
+ CGFloat bottomButtonHeight = self.bounds.size.height - buttonHeight - [self bottomSafeViewHeight];
+
+ dismissButton.frame = CGRectMake(0, bottomButtonHeight, buttonWidth, buttonHeight);
+ reloadButton.frame = CGRectMake(buttonWidth, bottomButtonHeight, buttonWidth, buttonHeight);
+ copyButton.frame = CGRectMake(buttonWidth * 2, bottomButtonHeight, buttonWidth, buttonHeight);
+ extraButton.frame = CGRectMake(buttonWidth * 3, bottomButtonHeight, buttonWidth, buttonHeight);
+
+ UIView *topBorder = [[UIView alloc] initWithFrame:CGRectMake(0, bottomButtonHeight + 1, rootView.frame.size.width, 1)];
+ topBorder.backgroundColor = [UIColor colorWithRed:0.70 green:0.70 blue:0.70 alpha:1.0];
[rootView addSubview:dismissButton];
[rootView addSubview:reloadButton];
[rootView addSubview:copyButton];
[rootView addSubview:extraButton];
+ [rootView addSubview:topBorder];
+
+ UIView *bottomSafeView = [UIView new];
+ bottomSafeView.backgroundColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1];
+ bottomSafeView.frame = CGRectMake(0, self.bounds.size.height - [self bottomSafeViewHeight], self.bounds.size.width, [self bottomSafeViewHeight]);
+
+ [rootView addSubview:bottomSafeView];
}
return self;
}
+- (NSInteger)bottomSafeViewHeight
+{
+ if (@available(iOS 11.0, *)) {
+ return [UIApplication sharedApplication].delegate.window.safeAreaInsets.bottom;
+ } else {
+ return 0;
+ }
+}
+
RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
- (void)dealloc
@@ -247,14 +279,14 @@
- (UITableViewCell *)reuseCell:(UITableViewCell *)cell forErrorMessage:(NSString *)message
{
if (!cell) {
- cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"msg-cell"];
+ cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"msg-cell"];
cell.textLabel.accessibilityIdentifier = @"redbox-error";
cell.textLabel.textColor = [UIColor whiteColor];
cell.textLabel.font = [UIFont boldSystemFontOfSize:16];
cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
cell.textLabel.numberOfLines = 0;
cell.detailTextLabel.textColor = [UIColor whiteColor];
- cell.backgroundColor = [UIColor clearColor];
+ cell.backgroundColor = [UIColor colorWithRed:0.82 green:0.10 blue:0.15 alpha:1.0];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
@@ -267,11 +299,11 @@
{
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cell"];
- cell.textLabel.textColor = [UIColor colorWithWhite:1 alpha:0.9];
+ cell.textLabel.textColor = [UIColor whiteColor];
cell.textLabel.font = [UIFont fontWithName:@"Menlo-Regular" size:14];
cell.textLabel.lineBreakMode = NSLineBreakByCharWrapping;
cell.textLabel.numberOfLines = 2;
- cell.detailTextLabel.textColor = [UIColor colorWithWhite:1 alpha:0.7];
+ cell.detailTextLabel.textColor = [UIColor colorWithRed:0.70 green:0.70 blue:0.70 alpha:1.0];
cell.detailTextLabel.font = [UIFont fontWithName:@"Menlo-Regular" size:11];
cell.detailTextLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
cell.backgroundColor = [UIColor clearColor];

React/Modules/RCTSourceCode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTSourceCode.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -22,6 +22,11 @@
- (NSDictionary<NSString *, id> *)constantsToExport
{
+ return [self getConstants];
+}
+
+- (NSDictionary<NSString *, id> *)getConstants
+{
return @{
@"scriptURL": self.bridge.bundleURL.absoluteString ?: @"",
};

React/Modules/RCTStatusBarManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTStatusBarManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTTiming.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTTiming.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTTVNavigationEventEmitter.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTTVNavigationEventEmitter.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTUIManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTUIManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -68,7 +68,7 @@
NSHashTable<RCTShadowView *> *_shadowViewsWithUpdatedChildren; // UIManager queue only.
// Keyed by viewName
- NSDictionary *_componentDataByName;
+ NSMutableDictionary *_componentDataByName;
}
@synthesize bridge = _bridge;
@@ -148,18 +148,16 @@
_observerCoordinator = [RCTUIManagerObserverCoordinator new];
- // Get view managers from bridge
- NSMutableDictionary *componentDataByName = [NSMutableDictionary new];
+ // Get view managers from bridge=
+ _componentDataByName = [NSMutableDictionary new];
for (Class moduleClass in _bridge.moduleClasses) {
if ([moduleClass isSubclassOfClass:[RCTViewManager class]]) {
RCTComponentData *componentData = [[RCTComponentData alloc] initWithManagerClass:moduleClass
bridge:_bridge];
- componentDataByName[componentData.name] = componentData;
+ _componentDataByName[componentData.name] = componentData;
}
}
- _componentDataByName = [componentDataByName copy];
-
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(didReceiveNewContentSizeMultiplier)
name:RCTAccessibilityManagerDidUpdateMultiplierNotification
@@ -1350,59 +1348,6 @@
RCTMeasureLayout(shadowView, shadowView.reactSuperview, callback);
}
-/**
- * Returns an array of computed offset layouts in a dictionary form. The layouts are of any React subviews
- * that are immediate descendants to the parent view found within a specified rect. The dictionary result
- * contains left, top, width, height and an index. The index specifies the position among the other subviews.
- * Only layouts for views that are within the rect passed in are returned. Invokes the error callback if the
- * passed in parent view does not exist. Invokes the supplied callback with the array of computed layouts.
- */
-RCT_EXPORT_METHOD(measureViewsInRect:(CGRect)rect
- parentView:(nonnull NSNumber *)reactTag
- errorCallback:(__unused RCTResponseSenderBlock)errorCallback
- callback:(RCTResponseSenderBlock)callback)
-{
- RCTShadowView *shadowView = _shadowViewRegistry[reactTag];
- if (!shadowView) {
- RCTLogError(@"Attempting to measure view that does not exist (tag #%@)", reactTag);
- return;
- }
- NSArray<RCTShadowView *> *childShadowViews = [shadowView reactSubviews];
- NSMutableArray<NSDictionary *> *results =
- [[NSMutableArray alloc] initWithCapacity:childShadowViews.count];
-
- [childShadowViews enumerateObjectsUsingBlock:
- ^(RCTShadowView *childShadowView, NSUInteger idx, __unused BOOL *stop) {
- CGRect childLayout = [childShadowView measureLayoutRelativeToAncestor:shadowView];
- if (CGRectIsNull(childLayout)) {
- RCTLogError(@"View %@ (tag #%@) is not a descendant of %@ (tag #%@)",
- childShadowView, childShadowView.reactTag, shadowView, shadowView.reactTag);
- return;
- }
-
- CGFloat leftOffset = childLayout.origin.x;
- CGFloat topOffset = childLayout.origin.y;
- CGFloat width = childLayout.size.width;
- CGFloat height = childLayout.size.height;
-
- if (leftOffset <= rect.origin.x + rect.size.width &&
- leftOffset + width >= rect.origin.x &&
- topOffset <= rect.origin.y + rect.size.height &&
- topOffset + height >= rect.origin.y) {
-
- // This view is within the layout rect
- NSDictionary *result = @{@"index": @(idx),
- @"left": @(leftOffset),
- @"top": @(topOffset),
- @"width": @(width),
- @"height": @(height)};
-
- [results addObject:result];
- }
- }];
- callback(@[results]);
-}
-
RCT_EXPORT_METHOD(takeSnapshot:(id /* NSString or NSNumber */)target
withOptions:(NSDictionary *)options
resolve:(RCTPromiseResolveBlock)resolve
@@ -1492,13 +1437,10 @@
}];
}
-- (NSDictionary<NSString *, id> *)constantsToExport
-{
- NSMutableDictionary<NSString *, NSDictionary *> *constants = [NSMutableDictionary new];
- NSMutableDictionary<NSString *, NSDictionary *> *directEvents = [NSMutableDictionary new];
- NSMutableDictionary<NSString *, NSDictionary *> *bubblingEvents = [NSMutableDictionary new];
-
- [_componentDataByName enumerateKeysAndObjectsUsingBlock:^(NSString *name, RCTComponentData *componentData, __unused BOOL *stop) {
+static NSMutableDictionary<NSString *, id> *moduleConstantsForComponent(
+ NSMutableDictionary<NSString *, NSDictionary *> *directEvents,
+ NSMutableDictionary<NSString *, NSDictionary *> *bubblingEvents,
+ RCTComponentData *componentData) {
NSMutableDictionary<NSString *, id> *moduleConstants = [NSMutableDictionary new];
// Register which event-types this view dispatches.
@@ -1548,13 +1490,74 @@
}
}
+ return moduleConstants;
+}
+
+- (NSDictionary<NSString *, id> *)constantsToExport
+{
+ return [self getConstants];
+}
+
+- (NSDictionary<NSString *, id> *)getConstants
+{
+ NSMutableDictionary<NSString *, NSDictionary *> *constants = [NSMutableDictionary new];
+ NSMutableDictionary<NSString *, NSDictionary *> *directEvents = [NSMutableDictionary new];
+ NSMutableDictionary<NSString *, NSDictionary *> *bubblingEvents = [NSMutableDictionary new];
+
+ [_componentDataByName enumerateKeysAndObjectsUsingBlock:^(NSString *name, RCTComponentData *componentData, __unused BOOL *stop) {
RCTAssert(!constants[name], @"UIManager already has constants for %@", componentData.name);
+ NSMutableDictionary<NSString *, id> *moduleConstants = moduleConstantsForComponent(directEvents, bubblingEvents, componentData);
constants[name] = moduleConstants;
}];
return constants;
}
+RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(lazilyLoadView:(NSString *)name)
+{
+ if (_componentDataByName[name]) {
+ return @{};
+ }
+
+ id<RCTBridgeDelegate> delegate = self.bridge.delegate;
+ if (![delegate respondsToSelector:@selector(bridge:didNotFindModule:)]) {
+ return @{};
+ }
+
+ NSString *moduleName = name;
+ BOOL result = [delegate bridge:self.bridge didNotFindModule:moduleName];
+ if (!result) {
+ moduleName = [name stringByAppendingString:@"Manager"];
+ result = [delegate bridge:self.bridge didNotFindModule:moduleName];
+ }
+ if (!result) {
+ return @{};
+ }
+
+ id module = [self.bridge moduleForName:moduleName];
+ if (module == nil) {
+ // There is all sorts of code in this codebase that drops prefixes.
+ //
+ // If we didn't find a module, it's possible because it's stored under a key
+ // which had RCT Prefixes stripped. Lets check one more time...
+ module = [self.bridge moduleForName:RCTDropReactPrefixes(moduleName)];
+ }
+
+ if (!module) {
+ return @{};
+ }
+
+ RCTComponentData *componentData = [[RCTComponentData alloc] initWithManagerClass:[module class] bridge:self.bridge];
+ _componentDataByName[componentData.name] = componentData;
+ NSMutableDictionary *directEvents = [NSMutableDictionary new];
+ NSMutableDictionary *bubblingEvents = [NSMutableDictionary new];
+ NSMutableDictionary<NSString *, id> *moduleConstants = moduleConstantsForComponent(directEvents, bubblingEvents, componentData);
+ return
+ @{
+ @"viewConfig": moduleConstants,
+ };
+}
+
RCT_EXPORT_METHOD(configureNextLayoutAnimation:(NSDictionary *)config
withCallback:(RCTResponseSenderBlock)callback
errorCallback:(__unused RCTResponseSenderBlock)errorCallback)

React/Modules/RCTUIManagerObserverCoordinator.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTUIManagerObserverCoordinator.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTUIManagerUtils.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Modules/RCTUIManagerUtils.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Profiler/RCTFPSGraph.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Profiler/RCTFPSGraph.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Profiler/RCTMacros.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Profiler/RCTPerfMonitor.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -156,6 +156,9 @@
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) ?

React/Profiler/RCTProfile.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Profiler/RCTProfile.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Profiler/RCTProfileTrampoline-arm64.S

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Profiler/RCTProfileTrampoline-arm.S

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Profiler/RCTProfileTrampoline-i386.S

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Profiler/RCTProfileTrampoline-x86_64.S

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/React.xcodeproj/project.pbxproj

@@ -56,22 +56,8 @@
134D63C31F1FEC4B008872B5 /* RCTCxxBridgeDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 134D63C21F1FEC4B008872B5 /* RCTCxxBridgeDelegate.h */; };
134D63C41F1FEC65008872B5 /* RCTCxxBridgeDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 134D63C21F1FEC4B008872B5 /* RCTCxxBridgeDelegate.h */; };
13513F3C1B1F43F400FCE529 /* RCTProgressViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13513F3B1B1F43F400FCE529 /* RCTProgressViewManager.m */; };
- 135A9BFB1E7B0EAE00587AEB /* RCTJSCErrorHandling.h in Headers */ = {isa = PBXBuildFile; fileRef = 135A9BF91E7B0EAE00587AEB /* RCTJSCErrorHandling.h */; };
- 135A9BFC1E7B0EAE00587AEB /* RCTJSCErrorHandling.mm in Sources */ = {isa = PBXBuildFile; fileRef = 135A9BFA1E7B0EAE00587AEB /* RCTJSCErrorHandling.mm */; };
- 135A9BFF1E7B0EE600587AEB /* RCTJSCHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 135A9BFD1E7B0EE600587AEB /* RCTJSCHelpers.h */; };
- 135A9C001E7B0EE600587AEB /* RCTJSCHelpers.mm in Sources */ = {isa = PBXBuildFile; fileRef = 135A9BFE1E7B0EE600587AEB /* RCTJSCHelpers.mm */; };
- 135A9C011E7B0F4700587AEB /* systemJSCWrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 19DED2281E77E29200F089BB /* systemJSCWrapper.cpp */; };
- 135A9C021E7B0F4800587AEB /* systemJSCWrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 19DED2281E77E29200F089BB /* systemJSCWrapper.cpp */; };
- 135A9C031E7B0F6100587AEB /* RCTJSCErrorHandling.h in Headers */ = {isa = PBXBuildFile; fileRef = 135A9BF91E7B0EAE00587AEB /* RCTJSCErrorHandling.h */; };
- 135A9C041E7B0F6400587AEB /* RCTJSCErrorHandling.mm in Sources */ = {isa = PBXBuildFile; fileRef = 135A9BFA1E7B0EAE00587AEB /* RCTJSCErrorHandling.mm */; };
- 135A9C051E7B0F7500587AEB /* RCTJSCHelpers.mm in Sources */ = {isa = PBXBuildFile; fileRef = 135A9BFE1E7B0EE600587AEB /* RCTJSCHelpers.mm */; };
- 135A9C061E7B0F7800587AEB /* RCTJSCHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 135A9BFD1E7B0EE600587AEB /* RCTJSCHelpers.h */; };
13723B501A82FD3C00F88898 /* RCTStatusBarManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13723B4F1A82FD3C00F88898 /* RCTStatusBarManager.m */; };
1372B70A1AB030C200659ED6 /* RCTAppState.m in Sources */ = {isa = PBXBuildFile; fileRef = 1372B7091AB030C200659ED6 /* RCTAppState.m */; };
- 137327E71AA5CF210034F82E /* RCTTabBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 137327E01AA5CF210034F82E /* RCTTabBar.m */; };
- 137327E81AA5CF210034F82E /* RCTTabBarItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 137327E21AA5CF210034F82E /* RCTTabBarItem.m */; };
- 137327E91AA5CF210034F82E /* RCTTabBarItemManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 137327E41AA5CF210034F82E /* RCTTabBarItemManager.m */; };
- 137327EA1AA5CF210034F82E /* RCTTabBarManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 137327E61AA5CF210034F82E /* RCTTabBarManager.m */; };
1384E2081E806D4E00545659 /* RCTNativeModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 1384E2061E806D4E00545659 /* RCTNativeModule.h */; };
1384E2091E806D4E00545659 /* RCTNativeModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1384E2071E806D4E00545659 /* RCTNativeModule.mm */; };
1384E20A1E806D5700545659 /* RCTNativeModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 1384E2061E806D4E00545659 /* RCTNativeModule.h */; };
@@ -101,7 +87,6 @@
139D7F061E25DE1100323FB7 /* utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 139D7EE01E25DBDC00323FB7 /* utilities.cc */; };
139D7F071E25DE1100323FB7 /* vlog_is_on.cc in Sources */ = {isa = PBXBuildFile; fileRef = 139D7EE21E25DBDC00323FB7 /* vlog_is_on.cc */; };
139D7F091E25DE3700323FB7 /* demangle.cc in Sources */ = {isa = PBXBuildFile; fileRef = 139D7F081E25DE3700323FB7 /* demangle.cc */; };
- 139D84AF1E273B5600323FB7 /* Bits.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 139D849D1E273B5600323FB7 /* Bits.cpp */; };
139D84B01E273B5600323FB7 /* Conv.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 139D849F1E273B5600323FB7 /* Conv.cpp */; };
139D84B11E273B5600323FB7 /* dynamic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 139D84A21E273B5600323FB7 /* dynamic.cpp */; };
139D84B31E273B5600323FB7 /* json.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 139D84A71E273B5600323FB7 /* json.cpp */; };
@@ -114,10 +99,6 @@
13B07FEF1A69327A00A75B9A /* RCTAlertManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FE81A69327A00A75B9A /* RCTAlertManager.m */; };
13B07FF01A69327A00A75B9A /* RCTExceptionsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FEA1A69327A00A75B9A /* RCTExceptionsManager.m */; };
13B07FF21A69327A00A75B9A /* RCTTiming.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FEE1A69327A00A75B9A /* RCTTiming.m */; };
- 13B0801A1A69489C00A75B9A /* RCTNavigator.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B0800D1A69489C00A75B9A /* RCTNavigator.m */; };
- 13B0801B1A69489C00A75B9A /* RCTNavigatorManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B0800F1A69489C00A75B9A /* RCTNavigatorManager.m */; };
- 13B0801C1A69489C00A75B9A /* RCTNavItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B080111A69489C00A75B9A /* RCTNavItem.m */; };
- 13B0801D1A69489C00A75B9A /* RCTNavItemManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B080131A69489C00A75B9A /* RCTNavItemManager.m */; };
13B080201A69489C00A75B9A /* RCTActivityIndicatorViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B080191A69489C00A75B9A /* RCTActivityIndicatorViewManager.m */; };
13B080261A694A8400A75B9A /* RCTWrapperViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B080241A694A8400A75B9A /* RCTWrapperViewController.m */; };
13BB3D021BECD54500932C10 /* RCTImageSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 13BB3D011BECD54500932C10 /* RCTImageSource.m */; };
@@ -137,56 +118,24 @@
13E067571A70F44B002CDEE1 /* RCTView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E067501A70F44B002CDEE1 /* RCTView.m */; };
13E067591A70F44B002CDEE1 /* UIView+React.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E067541A70F44B002CDEE1 /* UIView+React.m */; };
13E41EEB1C05CA0B00CD8DAC /* RCTProfileTrampoline-i386.S in Sources */ = {isa = PBXBuildFile; fileRef = 14BF717F1C04793D00C97D0C /* RCTProfileTrampoline-i386.S */; };
- 13EBC6711E2870DE00880AC5 /* JSCWrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D7A27DD1DE32541002E3F95 /* JSCWrapper.cpp */; };
- 13EBC6731E2870DE00880AC5 /* Value.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B10C1E0369AD0018521A /* Value.cpp */; };
- 13EBC6771E2870E400880AC5 /* JSCHelpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B1071E0369AD0018521A /* JSCHelpers.cpp */; };
- 13EBC6781E2870E400880AC5 /* JSCWrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D7A27DD1DE32541002E3F95 /* JSCWrapper.cpp */; };
- 13EBC6791E2870E400880AC5 /* Unicode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B10A1E0369AD0018521A /* Unicode.cpp */; };
- 13EBC67A1E2870E400880AC5 /* Value.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B10C1E0369AD0018521A /* Value.cpp */; };
- 13EBC67B1E28723000880AC5 /* Unicode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B10A1E0369AD0018521A /* Unicode.cpp */; };
- 13EBC67D1E28725900880AC5 /* JSCHelpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B1071E0369AD0018521A /* JSCHelpers.cpp */; };
- 13EBC67E1E28726000880AC5 /* JSCHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B1081E0369AD0018521A /* JSCHelpers.h */; };
- 13EBC6801E28733C00880AC5 /* noncopyable.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B1091E0369AD0018521A /* noncopyable.h */; };
- 13EBC6811E28733C00880AC5 /* Unicode.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B10B1E0369AD0018521A /* Unicode.h */; };
- 13EBC6821E28733C00880AC5 /* Value.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B10D1E0369AD0018521A /* Value.h */; };
13F17A851B8493E5007D4C75 /* RCTRedBox.m in Sources */ = {isa = PBXBuildFile; fileRef = 13F17A841B8493E5007D4C75 /* RCTRedBox.m */; };
- 13F880381E296D2800C3C7A1 /* JSCWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D7A27DE1DE32541002E3F95 /* JSCWrapper.h */; };
13F887581E2971D400C3C7A1 /* Demangle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 13F887521E2971C500C3C7A1 /* Demangle.cpp */; };
- 13F887591E2971D400C3C7A1 /* StringBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 13F887531E2971C500C3C7A1 /* StringBase.cpp */; };
13F8875A1E2971D400C3C7A1 /* Unicode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 13F887541E2971C500C3C7A1 /* Unicode.cpp */; };
13F8876E1E29726200C3C7A1 /* CxxNativeModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0A81E03699D0018521A /* CxxNativeModule.cpp */; };
13F887701E29726200C3C7A1 /* Instance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0AE1E03699D0018521A /* Instance.cpp */; };
13F887711E29726200C3C7A1 /* JSBundleType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AC70D2EB1DE48A22002E6351 /* JSBundleType.cpp */; };
- 13F887721E29726200C3C7A1 /* JSCExecutor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0B21E03699D0018521A /* JSCExecutor.cpp */; };
- 13F887741E29726200C3C7A1 /* JSCLegacyTracing.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0B61E03699D0018521A /* JSCLegacyTracing.cpp */; };
- 13F887751E29726200C3C7A1 /* JSCMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0B81E03699D0018521A /* JSCMemory.cpp */; };
- 13F887761E29726200C3C7A1 /* JSCNativeModules.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0BA1E03699D0018521A /* JSCNativeModules.cpp */; };
- 13F887771E29726200C3C7A1 /* JSCPerfStats.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0BC1E03699D0018521A /* JSCPerfStats.cpp */; };
- 13F887781E29726200C3C7A1 /* JSCSamplingProfiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0BE1E03699D0018521A /* JSCSamplingProfiler.cpp */; };
- 13F887791E29726200C3C7A1 /* JSCUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0C21E03699D0018521A /* JSCUtils.cpp */; };
13F8877B1E29726200C3C7A1 /* JSIndexedRAMBundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0C61E03699D0018521A /* JSIndexedRAMBundle.cpp */; };
13F8877C1E29726200C3C7A1 /* MethodCall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0CA1E03699D0018521A /* MethodCall.cpp */; };
13F8877D1E29726200C3C7A1 /* ModuleRegistry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0CC1E03699D0018521A /* ModuleRegistry.cpp */; };
13F8877E1E29726200C3C7A1 /* NativeToJsBridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0CF1E03699D0018521A /* NativeToJsBridge.cpp */; };
- 13F8877F1E29726200C3C7A1 /* Platform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0D11E03699D0018521A /* Platform.cpp */; };
13F887801E29726200C3C7A1 /* SampleCxxModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0D31E03699D0018521A /* SampleCxxModule.cpp */; };
13F887821E29726300C3C7A1 /* CxxNativeModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0A81E03699D0018521A /* CxxNativeModule.cpp */; };
13F887841E29726300C3C7A1 /* Instance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0AE1E03699D0018521A /* Instance.cpp */; };
- 13F887851E29726300C3C7A1 /* JSCExecutor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0B21E03699D0018521A /* JSCExecutor.cpp */; };
- 13F887871E29726300C3C7A1 /* JSCLegacyTracing.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0B61E03699D0018521A /* JSCLegacyTracing.cpp */; };
- 13F887881E29726300C3C7A1 /* JSCMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0B81E03699D0018521A /* JSCMemory.cpp */; };
- 13F887891E29726300C3C7A1 /* JSCNativeModules.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0BA1E03699D0018521A /* JSCNativeModules.cpp */; };
- 13F8878A1E29726300C3C7A1 /* JSCPerfStats.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0BC1E03699D0018521A /* JSCPerfStats.cpp */; };
- 13F8878B1E29726300C3C7A1 /* JSCSamplingProfiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0BE1E03699D0018521A /* JSCSamplingProfiler.cpp */; };
- 13F8878C1E29726300C3C7A1 /* JSCUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0C21E03699D0018521A /* JSCUtils.cpp */; };
13F8878E1E29726300C3C7A1 /* JSIndexedRAMBundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0C61E03699D0018521A /* JSIndexedRAMBundle.cpp */; };
13F8878F1E29726300C3C7A1 /* MethodCall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0CA1E03699D0018521A /* MethodCall.cpp */; };
13F887901E29726300C3C7A1 /* ModuleRegistry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0CC1E03699D0018521A /* ModuleRegistry.cpp */; };
13F887911E29726300C3C7A1 /* NativeToJsBridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0CF1E03699D0018521A /* NativeToJsBridge.cpp */; };
- 13F887921E29726300C3C7A1 /* Platform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0D11E03699D0018521A /* Platform.cpp */; };
13F887931E29726300C3C7A1 /* SampleCxxModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0D31E03699D0018521A /* SampleCxxModule.cpp */; };
- 13F8879F1E29741900C3C7A1 /* BitsFunctexcept.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 13F8879C1E29740700C3C7A1 /* BitsFunctexcept.cpp */; };
- 13F887A21E2977FF00C3C7A1 /* MallocImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 13F887A01E2977D800C3C7A1 /* MallocImpl.cpp */; };
142014191B32094000CC17BA /* RCTPerformanceLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 142014171B32094000CC17BA /* RCTPerformanceLogger.m */; };
1450FF861BCFF28A00208362 /* RCTProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF811BCFF28A00208362 /* RCTProfile.m */; };
1450FF871BCFF28A00208362 /* RCTProfileTrampoline-arm.S in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF821BCFF28A00208362 /* RCTProfileTrampoline-arm.S */; };
@@ -213,30 +162,18 @@
19F61C011E8495CD00571D81 /* ieee.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 139D7E471E25C5A300323FB7 /* ieee.h */; };
19F61C021E8495CD00571D81 /* strtod.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 139D7E491E25C5A300323FB7 /* strtod.h */; };
19F61C031E8495CD00571D81 /* utils.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 139D7E4A1E25C5A300323FB7 /* utils.h */; };
- 19F61C041E8495FF00571D81 /* JSCHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B1081E0369AD0018521A /* JSCHelpers.h */; };
- 19F61C051E8495FF00571D81 /* noncopyable.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B1091E0369AD0018521A /* noncopyable.h */; };
- 19F61C061E8495FF00571D81 /* Unicode.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B10B1E0369AD0018521A /* Unicode.h */; };
- 19F61C071E8495FF00571D81 /* Value.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B10D1E0369AD0018521A /* Value.h */; };
27595AA41E575C7800CCE2B1 /* CxxModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0A71E03699D0018521A /* CxxModule.h */; };
27595AA51E575C7800CCE2B1 /* CxxNativeModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0A91E03699D0018521A /* CxxNativeModule.h */; };
27595AA61E575C7800CCE2B1 /* JSExecutor.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0AB1E03699D0018521A /* JSExecutor.h */; };
27595AA91E575C7800CCE2B1 /* Instance.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0AF1E03699D0018521A /* Instance.h */; };
27595AAA1E575C7800CCE2B1 /* JsArgumentHelpers-inl.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0B01E03699D0018521A /* JsArgumentHelpers-inl.h */; };
27595AAB1E575C7800CCE2B1 /* JsArgumentHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0B11E03699D0018521A /* JsArgumentHelpers.h */; };
- 27595AAC1E575C7800CCE2B1 /* JSCExecutor.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0B31E03699D0018521A /* JSCExecutor.h */; };
- 27595AAE1E575C7800CCE2B1 /* JSCLegacyTracing.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0B71E03699D0018521A /* JSCLegacyTracing.h */; };
- 27595AAF1E575C7800CCE2B1 /* JSCMemory.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0B91E03699D0018521A /* JSCMemory.h */; };
- 27595AB01E575C7800CCE2B1 /* JSCNativeModules.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0BB1E03699D0018521A /* JSCNativeModules.h */; };
- 27595AB11E575C7800CCE2B1 /* JSCPerfStats.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0BD1E03699D0018521A /* JSCPerfStats.h */; };
- 27595AB21E575C7800CCE2B1 /* JSCSamplingProfiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0BF1E03699D0018521A /* JSCSamplingProfiler.h */; };
- 27595AB31E575C7800CCE2B1 /* JSCUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C31E03699D0018521A /* JSCUtils.h */; };
27595AB51E575C7800CCE2B1 /* JSIndexedRAMBundle.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C71E03699D0018521A /* JSIndexedRAMBundle.h */; };
27595AB61E575C7800CCE2B1 /* MessageQueueThread.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C91E03699D0018521A /* MessageQueueThread.h */; };
27595AB71E575C7800CCE2B1 /* MethodCall.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0CB1E03699D0018521A /* MethodCall.h */; };
27595AB81E575C7800CCE2B1 /* ModuleRegistry.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0CD1E03699D0018521A /* ModuleRegistry.h */; };
27595AB91E575C7800CCE2B1 /* NativeModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0CE1E03699D0018521A /* NativeModule.h */; };
27595ABA1E575C7800CCE2B1 /* NativeToJsBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0D01E03699D0018521A /* NativeToJsBridge.h */; };
- 27595ABB1E575C7800CCE2B1 /* Platform.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0D21E03699D0018521A /* Platform.h */; };
27595ABC1E575C7800CCE2B1 /* SampleCxxModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0D41E03699D0018521A /* SampleCxxModule.h */; };
27595ABD1E575C7800CCE2B1 /* SystraceSection.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0D51E03699D0018521A /* SystraceSection.h */; };
27595ABF1E575C7800CCE2B1 /* CxxModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0A71E03699D0018521A /* CxxModule.h */; };
@@ -245,25 +182,16 @@
27595AC41E575C7800CCE2B1 /* Instance.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0AF1E03699D0018521A /* Instance.h */; };
27595AC51E575C7800CCE2B1 /* JsArgumentHelpers-inl.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0B01E03699D0018521A /* JsArgumentHelpers-inl.h */; };
27595AC61E575C7800CCE2B1 /* JsArgumentHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0B11E03699D0018521A /* JsArgumentHelpers.h */; };
- 27595AC71E575C7800CCE2B1 /* JSCExecutor.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0B31E03699D0018521A /* JSCExecutor.h */; };
- 27595AC91E575C7800CCE2B1 /* JSCLegacyTracing.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0B71E03699D0018521A /* JSCLegacyTracing.h */; };
- 27595ACA1E575C7800CCE2B1 /* JSCMemory.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0B91E03699D0018521A /* JSCMemory.h */; };
- 27595ACB1E575C7800CCE2B1 /* JSCNativeModules.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0BB1E03699D0018521A /* JSCNativeModules.h */; };
- 27595ACC1E575C7800CCE2B1 /* JSCPerfStats.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0BD1E03699D0018521A /* JSCPerfStats.h */; };
- 27595ACD1E575C7800CCE2B1 /* JSCSamplingProfiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0BF1E03699D0018521A /* JSCSamplingProfiler.h */; };
- 27595ACE1E575C7800CCE2B1 /* JSCUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C31E03699D0018521A /* JSCUtils.h */; };
27595AD01E575C7800CCE2B1 /* JSIndexedRAMBundle.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C71E03699D0018521A /* JSIndexedRAMBundle.h */; };
27595AD11E575C7800CCE2B1 /* MessageQueueThread.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C91E03699D0018521A /* MessageQueueThread.h */; };
27595AD21E575C7800CCE2B1 /* MethodCall.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0CB1E03699D0018521A /* MethodCall.h */; };
27595AD31E575C7800CCE2B1 /* ModuleRegistry.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0CD1E03699D0018521A /* ModuleRegistry.h */; };
27595AD41E575C7800CCE2B1 /* NativeModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0CE1E03699D0018521A /* NativeModule.h */; };
27595AD51E575C7800CCE2B1 /* NativeToJsBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0D01E03699D0018521A /* NativeToJsBridge.h */; };
- 27595AD61E575C7800CCE2B1 /* Platform.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0D21E03699D0018521A /* Platform.h */; };
27595AD71E575C7800CCE2B1 /* SampleCxxModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0D41E03699D0018521A /* SampleCxxModule.h */; };
27595AD81E575C7800CCE2B1 /* SystraceSection.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0D51E03699D0018521A /* SystraceSection.h */; };
2D0EB9F32021067800CAF88A /* RCTUIUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = F1EFDA4E201F660F00EE6E4C /* RCTUIUtils.m */; };
2D16E68E1FA4FD3900B85C8A /* RCTTVNavigationEventEmitter.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D0B842D1EC0B51200B2BD8E /* RCTTVNavigationEventEmitter.h */; };
- 2D1D83CD1F74E2CE00615550 /* libprivatedata-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9936F32F1F5F2E5B0010BF04 /* libprivatedata-tvOS.a */; };
2D1D83CE1F74E2DA00615550 /* libdouble-conversion.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D383D621EBD27B9005632C8 /* libdouble-conversion.a */; };
2D3B5E931D9B087300451313 /* RCTErrorInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 3EDCA8A41D3591E700450C31 /* RCTErrorInfo.m */; };
2D3B5E941D9B087900451313 /* RCTBundleURLProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 68EFE4ED1CF6EB3900A1DE13 /* RCTBundleURLProvider.m */; };
@@ -315,18 +243,10 @@
2D3B5ED41D9B097D00451313 /* RCTModalHostView.m in Sources */ = {isa = PBXBuildFile; fileRef = 83A1FE8B1B62640A00BE0E65 /* RCTModalHostView.m */; };
2D3B5ED51D9B098000451313 /* RCTModalHostViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 83392EB21B6634E10013B15F /* RCTModalHostViewController.m */; };
2D3B5ED61D9B098400451313 /* RCTModalHostViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 83A1FE8E1B62643A00BE0E65 /* RCTModalHostViewManager.m */; };
- 2D3B5ED71D9B098700451313 /* RCTNavigator.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B0800D1A69489C00A75B9A /* RCTNavigator.m */; };
- 2D3B5ED81D9B098A00451313 /* RCTNavigatorManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B0800F1A69489C00A75B9A /* RCTNavigatorManager.m */; };
- 2D3B5ED91D9B098E00451313 /* RCTNavItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B080111A69489C00A75B9A /* RCTNavItem.m */; };
- 2D3B5EDA1D9B099100451313 /* RCTNavItemManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B080131A69489C00A75B9A /* RCTNavItemManager.m */; };
2D3B5EDD1D9B09A300451313 /* RCTProgressViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13513F3B1B1F43F400FCE529 /* RCTProgressViewManager.m */; };
2D3B5EE01D9B09AD00451313 /* RCTRootShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13BCE8081C99CB9D00DD7AAD /* RCTRootShadowView.m */; };
2D3B5EE31D9B09B700451313 /* RCTSegmentedControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 131B6AF11AF1093D00FFC3E0 /* RCTSegmentedControl.m */; };
2D3B5EE41D9B09BB00451313 /* RCTSegmentedControlManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 131B6AF31AF1093D00FFC3E0 /* RCTSegmentedControlManager.m */; };
- 2D3B5EEA1D9B09CD00451313 /* RCTTabBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 137327E01AA5CF210034F82E /* RCTTabBar.m */; };
- 2D3B5EEB1D9B09D000451313 /* RCTTabBarItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 137327E21AA5CF210034F82E /* RCTTabBarItem.m */; };
- 2D3B5EEC1D9B09D400451313 /* RCTTabBarItemManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 137327E41AA5CF210034F82E /* RCTTabBarItemManager.m */; };
- 2D3B5EED1D9B09D700451313 /* RCTTabBarManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 137327E61AA5CF210034F82E /* RCTTabBarManager.m */; };
2D3B5EEE1D9B09DA00451313 /* RCTView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E067501A70F44B002CDEE1 /* RCTView.m */; };
2D3B5EEF1D9B09DC00451313 /* RCTViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E0674E1A70F44B002CDEE1 /* RCTViewManager.m */; };
2D3B5EF01D9B09E300451313 /* RCTWrapperViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B080241A694A8400A75B9A /* RCTWrapperViewController.m */; };
@@ -335,7 +255,6 @@
2D8C2E331DA40441000EE098 /* RCTMultipartStreamReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 001BFCCF1D8381DE008E587E /* RCTMultipartStreamReader.m */; };
2DD0EFE11DA84F2800B0C975 /* RCTStatusBarManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13723B4F1A82FD3C00F88898 /* RCTStatusBarManager.m */; };
352DCFF01D19F4C20056D623 /* RCTI18nUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 352DCFEF1D19F4C20056D623 /* RCTI18nUtil.m */; };
- 369123E11DDC75850095B341 /* RCTJSCSamplingProfiler.m in Sources */ = {isa = PBXBuildFile; fileRef = 369123E01DDC75850095B341 /* RCTJSCSamplingProfiler.m */; };
391E86A41C623EC800009732 /* RCTTouchEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 391E86A21C623EC800009732 /* RCTTouchEvent.m */; };
39C50FF92046EACF00CEE534 /* RCTVersion.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 199B8A6E1F44DB16005DEF67 /* RCTVersion.h */; };
39C50FFB2046EE3500CEE534 /* RCTVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = 39C50FFA2046EE3500CEE534 /* RCTVersion.m */; };
@@ -353,14 +272,10 @@
3D0B842F1EC0B51200B2BD8E /* RCTTVNavigationEventEmitter.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D0B842D1EC0B51200B2BD8E /* RCTTVNavigationEventEmitter.h */; };
3D0B84301EC0B51200B2BD8E /* RCTTVNavigationEventEmitter.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D0B842E1EC0B51200B2BD8E /* RCTTVNavigationEventEmitter.m */; };
3D0E378A1F1CC40000DCAC9F /* RCTWebSocketModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D0E37891F1CC40000DCAC9F /* RCTWebSocketModule.h */; };
- 3D0E378C1F1CC58C00DCAC9F /* RCTWebSocketObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D0E378B1F1CC58C00DCAC9F /* RCTWebSocketObserver.h */; };
- 3D0E378D1F1CC58F00DCAC9F /* RCTWebSocketObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D0E378B1F1CC58C00DCAC9F /* RCTWebSocketObserver.h */; };
3D0E378E1F1CC59100DCAC9F /* RCTWebSocketModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D0E37891F1CC40000DCAC9F /* RCTWebSocketModule.h */; };
3D0E378F1F1CC5CF00DCAC9F /* RCTWebSocketModule.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D0E37891F1CC40000DCAC9F /* RCTWebSocketModule.h */; };
3D0E37901F1CC5E100DCAC9F /* RCTWebSocketModule.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D0E37891F1CC40000DCAC9F /* RCTWebSocketModule.h */; };
3D1E68DB1CABD13900DD7465 /* RCTDisplayLink.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D1E68D91CABD13900DD7465 /* RCTDisplayLink.m */; };
- 3D302F1E1DF8265A00D6DDAE /* JavaScriptCore.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D7A27DC1DE32541002E3F95 /* JavaScriptCore.h */; };
- 3D302F1F1DF8265A00D6DDAE /* JSCWrapper.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D7A27DE1DE32541002E3F95 /* JSCWrapper.h */; };
3D302F241DF828F800D6DDAE /* RCTImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D1FA0831DE4F3A000E03CC6 /* RCTImageLoader.h */; };
3D302F251DF828F800D6DDAE /* RCTImageStoreManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D1FA0841DE4F3A000E03CC6 /* RCTImageStoreManager.h */; };
3D302F261DF828F800D6DDAE /* RCTResizeMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D1FA0851DE4F3A000E03CC6 /* RCTResizeMode.h */; };
@@ -405,7 +320,6 @@
3D302F4D1DF828F800D6DDAE /* RCTURLRequestDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1345A83A1B265A0E00583190 /* RCTURLRequestDelegate.h */; };
3D302F4E1DF828F800D6DDAE /* RCTURLRequestHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 1345A83B1B265A0E00583190 /* RCTURLRequestHandler.h */; };
3D302F4F1DF828F800D6DDAE /* RCTUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CBBA4F1A601E3B00E9B192 /* RCTUtils.h */; };
- 3D302F541DF828F800D6DDAE /* RCTJSCSamplingProfiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 369123DF1DDC75850095B341 /* RCTJSCSamplingProfiler.h */; };
3D302F551DF828F800D6DDAE /* RCTAccessibilityManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E9B20B791B500126007A2DA7 /* RCTAccessibilityManager.h */; };
3D302F561DF828F800D6DDAE /* RCTAlertManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 13B07FE71A69327A00A75B9A /* RCTAlertManager.h */; };
3D302F571DF828F800D6DDAE /* RCTAppState.h in Headers */ = {isa = PBXBuildFile; fileRef = 1372B7081AB030C200659ED6 /* RCTAppState.h */; };
@@ -439,10 +353,6 @@
3D302F7B1DF828F800D6DDAE /* RCTModalHostView.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A1FE8A1B62640A00BE0E65 /* RCTModalHostView.h */; };
3D302F7C1DF828F800D6DDAE /* RCTModalHostViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 83392EB11B6634E10013B15F /* RCTModalHostViewController.h */; };
3D302F7D1DF828F800D6DDAE /* RCTModalHostViewManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A1FE8D1B62643A00BE0E65 /* RCTModalHostViewManager.h */; };
- 3D302F7E1DF828F800D6DDAE /* RCTNavigator.h in Headers */ = {isa = PBXBuildFile; fileRef = 13B0800C1A69489C00A75B9A /* RCTNavigator.h */; };
- 3D302F7F1DF828F800D6DDAE /* RCTNavigatorManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 13B0800E1A69489C00A75B9A /* RCTNavigatorManager.h */; };
- 3D302F801DF828F800D6DDAE /* RCTNavItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 13B080101A69489C00A75B9A /* RCTNavItem.h */; };
- 3D302F811DF828F800D6DDAE /* RCTNavItemManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 13B080121A69489C00A75B9A /* RCTNavItemManager.h */; };
3D302F841DF828F800D6DDAE /* RCTPointerEvents.h in Headers */ = {isa = PBXBuildFile; fileRef = 13442BF31AA90E0B0037E5B0 /* RCTPointerEvents.h */; };
3D302F851DF828F800D6DDAE /* RCTProgressViewManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 13513F3A1B1F43F400FCE529 /* RCTProgressViewManager.h */; };
3D302F861DF828F800D6DDAE /* RCTRefreshControl.h in Headers */ = {isa = PBXBuildFile; fileRef = 191E3EBF1C29DC3800C180A6 /* RCTRefreshControl.h */; };
@@ -455,29 +365,20 @@
3D302F901DF828F800D6DDAE /* RCTSliderManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 14F484541AABFCE100FDF6B9 /* RCTSliderManager.h */; };
3D302F911DF828F800D6DDAE /* RCTSwitch.h in Headers */ = {isa = PBXBuildFile; fileRef = 14F362071AABD06A001CE568 /* RCTSwitch.h */; };
3D302F921DF828F800D6DDAE /* RCTSwitchManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 14F362091AABD06A001CE568 /* RCTSwitchManager.h */; };
- 3D302F931DF828F800D6DDAE /* RCTTabBar.h in Headers */ = {isa = PBXBuildFile; fileRef = 137327DF1AA5CF210034F82E /* RCTTabBar.h */; };
- 3D302F941DF828F800D6DDAE /* RCTTabBarItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 137327E11AA5CF210034F82E /* RCTTabBarItem.h */; };
- 3D302F951DF828F800D6DDAE /* RCTTabBarItemManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 137327E31AA5CF210034F82E /* RCTTabBarItemManager.h */; };
- 3D302F961DF828F800D6DDAE /* RCTTabBarManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 137327E51AA5CF210034F82E /* RCTTabBarManager.h */; };
3D302F971DF828F800D6DDAE /* RCTTextDecorationLineType.h in Headers */ = {isa = PBXBuildFile; fileRef = E3BBC8EB1ADE6F47001BBD81 /* RCTTextDecorationLineType.h */; };
3D302F981DF828F800D6DDAE /* RCTView.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E0674F1A70F44B002CDEE1 /* RCTView.h */; };
3D302F9A1DF828F800D6DDAE /* RCTViewManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E0674D1A70F44B002CDEE1 /* RCTViewManager.h */; };
3D302F9D1DF828F800D6DDAE /* RCTWrapperViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 13B080231A694A8400A75B9A /* RCTWrapperViewController.h */; };
3D302F9F1DF828F800D6DDAE /* UIView+React.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E067531A70F44B002CDEE1 /* UIView+React.h */; };
3D3030221DF8294C00D6DDAE /* JSBundleType.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D3CD8F51DE5FB2300167DC4 /* JSBundleType.h */; };
- 3D3030251DF8295E00D6DDAE /* JavaScriptCore.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D7A27DC1DE32541002E3F95 /* JavaScriptCore.h */; };
- 3D3030261DF8295E00D6DDAE /* JSCWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D7A27DE1DE32541002E3F95 /* JSCWrapper.h */; };
3D37B5821D522B190042D5B5 /* RCTFont.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3D37B5811D522B190042D5B5 /* RCTFont.mm */; };
3D383D1F1EBD27A8005632C8 /* RCTBridge+Private.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 14A43DB81C1F849600794BC8 /* RCTBridge+Private.h */; };
3D383D201EBD27AF005632C8 /* RCTBridge+Private.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 14A43DB81C1F849600794BC8 /* RCTBridge+Private.h */; };
3D383D251EBD27B6005632C8 /* Conv.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 139D849F1E273B5600323FB7 /* Conv.cpp */; };
- 3D383D261EBD27B6005632C8 /* StringBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 13F887531E2971C500C3C7A1 /* StringBase.cpp */; };
3D383D271EBD27B6005632C8 /* raw_logging.cc in Sources */ = {isa = PBXBuildFile; fileRef = 139D7EDB1E25DBDC00323FB7 /* raw_logging.cc */; };
3D383D281EBD27B6005632C8 /* signalhandler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 139D7EDC1E25DBDC00323FB7 /* signalhandler.cc */; };
3D383D291EBD27B6005632C8 /* dynamic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 139D84A21E273B5600323FB7 /* dynamic.cpp */; };
3D383D2A1EBD27B6005632C8 /* utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 139D7EE01E25DBDC00323FB7 /* utilities.cc */; };
- 3D383D2B1EBD27B6005632C8 /* MallocImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 13F887A01E2977D800C3C7A1 /* MallocImpl.cpp */; };
- 3D383D2C1EBD27B6005632C8 /* Bits.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 139D849D1E273B5600323FB7 /* Bits.cpp */; };
3D383D2D1EBD27B6005632C8 /* symbolize.cc in Sources */ = {isa = PBXBuildFile; fileRef = 139D7EDE1E25DBDC00323FB7 /* symbolize.cc */; };
3D383D2E1EBD27B6005632C8 /* vlog_is_on.cc in Sources */ = {isa = PBXBuildFile; fileRef = 139D7EE21E25DBDC00323FB7 /* vlog_is_on.cc */; };
3D383D2F1EBD27B6005632C8 /* Unicode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 13F887541E2971C500C3C7A1 /* Unicode.cpp */; };
@@ -485,7 +386,6 @@
3D383D311EBD27B6005632C8 /* Demangle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 13F887521E2971C500C3C7A1 /* Demangle.cpp */; };
3D383D331EBD27B6005632C8 /* logging.cc in Sources */ = {isa = PBXBuildFile; fileRef = 139D7EDA1E25DBDC00323FB7 /* logging.cc */; };
3D383D341EBD27B6005632C8 /* json.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 139D84A71E273B5600323FB7 /* json.cpp */; };
- 3D383D351EBD27B6005632C8 /* BitsFunctexcept.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 13F8879C1E29740700C3C7A1 /* BitsFunctexcept.cpp */; };
3D383D401EBD27B9005632C8 /* bignum-dtoa.cc in Sources */ = {isa = PBXBuildFile; fileRef = 139D7E391E25C5A300323FB7 /* bignum-dtoa.cc */; };
3D383D411EBD27B9005632C8 /* bignum.cc in Sources */ = {isa = PBXBuildFile; fileRef = 139D7E3B1E25C5A300323FB7 /* bignum.cc */; };
3D383D421EBD27B9005632C8 /* cached-powers.cc in Sources */ = {isa = PBXBuildFile; fileRef = 139D7E3D1E25C5A300323FB7 /* cached-powers.cc */; };
@@ -515,12 +415,8 @@
3D383D5D1EBD27B9005632C8 /* strtod.h in Headers */ = {isa = PBXBuildFile; fileRef = 139D7E491E25C5A300323FB7 /* strtod.h */; };
3D383D5E1EBD27B9005632C8 /* utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 139D7E4A1E25C5A300323FB7 /* utils.h */; };
3D383D6D1EBD2940005632C8 /* libdouble-conversion.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139D7E881E25C6D100323FB7 /* libdouble-conversion.a */; };
- 3D383D6E1EBD2940005632C8 /* libjschelpers.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D3CD90B1DE5FBD600167DC4 /* libjschelpers.a */; };
3D383D6F1EBD2940005632C8 /* libthird-party.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139D7ECE1E25DB7D00323FB7 /* libthird-party.a */; };
- 3D383D711EBD2949005632C8 /* libjschelpers.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D3CD9181DE5FBD800167DC4 /* libjschelpers.a */; };
3D383D721EBD2949005632C8 /* libthird-party.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D383D3C1EBD27B6005632C8 /* libthird-party.a */; };
- 3D3CD93D1DE5FC1400167DC4 /* JavaScriptCore.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D7A27DC1DE32541002E3F95 /* JavaScriptCore.h */; };
- 3D3CD93E1DE5FC1400167DC4 /* JSCWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D7A27DE1DE32541002E3F95 /* JSCWrapper.h */; };
3D3CD9411DE5FC5300167DC4 /* libcxxreact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D3CD9251DE5FBEC00167DC4 /* libcxxreact.a */; };
3D3CD9451DE5FC7100167DC4 /* JSBundleType.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D3CD8F51DE5FB2300167DC4 /* JSBundleType.h */; };
3D74547C1E54758900E74ADD /* JSBigString.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D7454781E54757500E74ADD /* JSBigString.h */; };
@@ -593,7 +489,6 @@
3D80D9481DF6FA890028D040 /* RCTURLRequestDelegate.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 1345A83A1B265A0E00583190 /* RCTURLRequestDelegate.h */; };
3D80D9491DF6FA890028D040 /* RCTURLRequestHandler.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 1345A83B1B265A0E00583190 /* RCTURLRequestHandler.h */; };
3D80D94A1DF6FA890028D040 /* RCTUtils.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 83CBBA4F1A601E3B00E9B192 /* RCTUtils.h */; };
- 3D80D94F1DF6FA890028D040 /* RCTJSCSamplingProfiler.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 369123DF1DDC75850095B341 /* RCTJSCSamplingProfiler.h */; };
3D80D9501DF6FA890028D040 /* RCTAccessibilityManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = E9B20B791B500126007A2DA7 /* RCTAccessibilityManager.h */; };
3D80D9511DF6FA890028D040 /* RCTAlertManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13B07FE71A69327A00A75B9A /* RCTAlertManager.h */; };
3D80D9521DF6FA890028D040 /* RCTAppState.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 1372B7081AB030C200659ED6 /* RCTAppState.h */; };
@@ -627,10 +522,6 @@
3D80D9761DF6FA890028D040 /* RCTModalHostView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 83A1FE8A1B62640A00BE0E65 /* RCTModalHostView.h */; };
3D80D9771DF6FA890028D040 /* RCTModalHostViewController.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 83392EB11B6634E10013B15F /* RCTModalHostViewController.h */; };
3D80D9781DF6FA890028D040 /* RCTModalHostViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 83A1FE8D1B62643A00BE0E65 /* RCTModalHostViewManager.h */; };
- 3D80D9791DF6FA890028D040 /* RCTNavigator.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13B0800C1A69489C00A75B9A /* RCTNavigator.h */; };
- 3D80D97A1DF6FA890028D040 /* RCTNavigatorManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13B0800E1A69489C00A75B9A /* RCTNavigatorManager.h */; };
- 3D80D97B1DF6FA890028D040 /* RCTNavItem.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13B080101A69489C00A75B9A /* RCTNavItem.h */; };
- 3D80D97C1DF6FA890028D040 /* RCTNavItemManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13B080121A69489C00A75B9A /* RCTNavItemManager.h */; };
3D80D97D1DF6FA890028D040 /* RCTPicker.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 58114A121AAE854800E7D092 /* RCTPicker.h */; };
3D80D97E1DF6FA890028D040 /* RCTPickerManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 58114A141AAE854800E7D092 /* RCTPickerManager.h */; };
3D80D97F1DF6FA890028D040 /* RCTPointerEvents.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13442BF31AA90E0B0037E5B0 /* RCTPointerEvents.h */; };
@@ -645,10 +536,6 @@
3D80D98B1DF6FA890028D040 /* RCTSliderManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 14F484541AABFCE100FDF6B9 /* RCTSliderManager.h */; };
3D80D98C1DF6FA890028D040 /* RCTSwitch.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 14F362071AABD06A001CE568 /* RCTSwitch.h */; };
3D80D98D1DF6FA890028D040 /* RCTSwitchManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 14F362091AABD06A001CE568 /* RCTSwitchManager.h */; };
- 3D80D98E1DF6FA890028D040 /* RCTTabBar.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 137327DF1AA5CF210034F82E /* RCTTabBar.h */; };
- 3D80D98F1DF6FA890028D040 /* RCTTabBarItem.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 137327E11AA5CF210034F82E /* RCTTabBarItem.h */; };
- 3D80D9901DF6FA890028D040 /* RCTTabBarItemManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 137327E31AA5CF210034F82E /* RCTTabBarItemManager.h */; };
- 3D80D9911DF6FA890028D040 /* RCTTabBarManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 137327E51AA5CF210034F82E /* RCTTabBarManager.h */; };
3D80D9921DF6FA890028D040 /* RCTTextDecorationLineType.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = E3BBC8EB1ADE6F47001BBD81 /* RCTTextDecorationLineType.h */; };
3D80D9931DF6FA890028D040 /* RCTView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13E0674F1A70F44B002CDEE1 /* RCTView.h */; };
3D80D9951DF6FA890028D040 /* RCTViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13E0674D1A70F44B002CDEE1 /* RCTViewManager.h */; };
@@ -700,7 +587,6 @@
3D80DA421DF820620028D040 /* RCTURLRequestDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1345A83A1B265A0E00583190 /* RCTURLRequestDelegate.h */; };
3D80DA431DF820620028D040 /* RCTURLRequestHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 1345A83B1B265A0E00583190 /* RCTURLRequestHandler.h */; };
3D80DA441DF820620028D040 /* RCTUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CBBA4F1A601E3B00E9B192 /* RCTUtils.h */; };
- 3D80DA491DF820620028D040 /* RCTJSCSamplingProfiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 369123DF1DDC75850095B341 /* RCTJSCSamplingProfiler.h */; };
3D80DA4A1DF820620028D040 /* RCTAccessibilityManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E9B20B791B500126007A2DA7 /* RCTAccessibilityManager.h */; };
3D80DA4B1DF820620028D040 /* RCTAlertManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 13B07FE71A69327A00A75B9A /* RCTAlertManager.h */; };
3D80DA4C1DF820620028D040 /* RCTAppState.h in Headers */ = {isa = PBXBuildFile; fileRef = 1372B7081AB030C200659ED6 /* RCTAppState.h */; };
@@ -734,10 +620,6 @@
3D80DA701DF820620028D040 /* RCTModalHostView.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A1FE8A1B62640A00BE0E65 /* RCTModalHostView.h */; };
3D80DA711DF820620028D040 /* RCTModalHostViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 83392EB11B6634E10013B15F /* RCTModalHostViewController.h */; };
3D80DA721DF820620028D040 /* RCTModalHostViewManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A1FE8D1B62643A00BE0E65 /* RCTModalHostViewManager.h */; };
- 3D80DA731DF820620028D040 /* RCTNavigator.h in Headers */ = {isa = PBXBuildFile; fileRef = 13B0800C1A69489C00A75B9A /* RCTNavigator.h */; };
- 3D80DA741DF820620028D040 /* RCTNavigatorManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 13B0800E1A69489C00A75B9A /* RCTNavigatorManager.h */; };
- 3D80DA751DF820620028D040 /* RCTNavItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 13B080101A69489C00A75B9A /* RCTNavItem.h */; };
- 3D80DA761DF820620028D040 /* RCTNavItemManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 13B080121A69489C00A75B9A /* RCTNavItemManager.h */; };
3D80DA771DF820620028D040 /* RCTPicker.h in Headers */ = {isa = PBXBuildFile; fileRef = 58114A121AAE854800E7D092 /* RCTPicker.h */; };
3D80DA781DF820620028D040 /* RCTPickerManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 58114A141AAE854800E7D092 /* RCTPickerManager.h */; };
3D80DA791DF820620028D040 /* RCTPointerEvents.h in Headers */ = {isa = PBXBuildFile; fileRef = 13442BF31AA90E0B0037E5B0 /* RCTPointerEvents.h */; };
@@ -752,10 +634,6 @@
3D80DA851DF820620028D040 /* RCTSliderManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 14F484541AABFCE100FDF6B9 /* RCTSliderManager.h */; };
3D80DA861DF820620028D040 /* RCTSwitch.h in Headers */ = {isa = PBXBuildFile; fileRef = 14F362071AABD06A001CE568 /* RCTSwitch.h */; };
3D80DA871DF820620028D040 /* RCTSwitchManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 14F362091AABD06A001CE568 /* RCTSwitchManager.h */; };
- 3D80DA881DF820620028D040 /* RCTTabBar.h in Headers */ = {isa = PBXBuildFile; fileRef = 137327DF1AA5CF210034F82E /* RCTTabBar.h */; };
- 3D80DA891DF820620028D040 /* RCTTabBarItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 137327E11AA5CF210034F82E /* RCTTabBarItem.h */; };
- 3D80DA8A1DF820620028D040 /* RCTTabBarItemManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 137327E31AA5CF210034F82E /* RCTTabBarItemManager.h */; };
- 3D80DA8B1DF820620028D040 /* RCTTabBarManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 137327E51AA5CF210034F82E /* RCTTabBarManager.h */; };
3D80DA8C1DF820620028D040 /* RCTTextDecorationLineType.h in Headers */ = {isa = PBXBuildFile; fileRef = E3BBC8EB1ADE6F47001BBD81 /* RCTTextDecorationLineType.h */; };
3D80DA8D1DF820620028D040 /* RCTView.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E0674F1A70F44B002CDEE1 /* RCTView.h */; };
3D80DA8F1DF820620028D040 /* RCTViewManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E0674D1A70F44B002CDEE1 /* RCTViewManager.h */; };
@@ -765,7 +643,6 @@
3D80DA931DF820620028D040 /* UIView+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 83F15A171B7CC46900F10295 /* UIView+Private.h */; };
3D80DA941DF820620028D040 /* UIView+React.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E067531A70F44B002CDEE1 /* UIView+React.h */; };
3D8ED92C1E5B120100D83D20 /* libcxxreact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D3CD9321DE5FBEE00167DC4 /* libcxxreact.a */; };
- 3D8ED92D1E5B120100D83D20 /* libyoga.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D3C06751DE3340C00C268FA /* libyoga.a */; };
3DA9819E1E5B0DBB004F2374 /* NSDataBigString.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D7454B31E54786200E74ADD /* NSDataBigString.h */; };
3DA981A01E5B0E34004F2374 /* CxxModule.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0A71E03699D0018521A /* CxxModule.h */; };
3DA981A11E5B0E34004F2374 /* CxxNativeModule.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0A91E03699D0018521A /* CxxNativeModule.h */; };
@@ -775,13 +652,6 @@
3DA981A71E5B0E34004F2374 /* JsArgumentHelpers.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0B11E03699D0018521A /* JsArgumentHelpers.h */; };
3DA981A81E5B0E34004F2374 /* JSBigString.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D7454781E54757500E74ADD /* JSBigString.h */; };
3DA981A91E5B0E34004F2374 /* JSBundleType.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D3CD8F51DE5FB2300167DC4 /* JSBundleType.h */; };
- 3DA981AA1E5B0E34004F2374 /* JSCExecutor.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0B31E03699D0018521A /* JSCExecutor.h */; };
- 3DA981AC1E5B0E34004F2374 /* JSCLegacyTracing.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0B71E03699D0018521A /* JSCLegacyTracing.h */; };
- 3DA981AD1E5B0E34004F2374 /* JSCMemory.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0B91E03699D0018521A /* JSCMemory.h */; };
- 3DA981AE1E5B0E34004F2374 /* JSCNativeModules.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0BB1E03699D0018521A /* JSCNativeModules.h */; };
- 3DA981AF1E5B0E34004F2374 /* JSCPerfStats.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0BD1E03699D0018521A /* JSCPerfStats.h */; };
- 3DA981B01E5B0E34004F2374 /* JSCSamplingProfiler.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0BF1E03699D0018521A /* JSCSamplingProfiler.h */; };
- 3DA981B11E5B0E34004F2374 /* JSCUtils.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C31E03699D0018521A /* JSCUtils.h */; };
3DA981B31E5B0E34004F2374 /* JSIndexedRAMBundle.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C71E03699D0018521A /* JSIndexedRAMBundle.h */; };
3DA981B41E5B0E34004F2374 /* JSModulesUnbundle.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C81E03699D0018521A /* JSModulesUnbundle.h */; };
3DA981B51E5B0E34004F2374 /* MessageQueueThread.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C91E03699D0018521A /* MessageQueueThread.h */; };
@@ -789,7 +659,6 @@
3DA981B71E5B0E34004F2374 /* ModuleRegistry.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0CD1E03699D0018521A /* ModuleRegistry.h */; };
3DA981B81E5B0E34004F2374 /* NativeModule.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0CE1E03699D0018521A /* NativeModule.h */; };
3DA981B91E5B0E34004F2374 /* NativeToJsBridge.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0D01E03699D0018521A /* NativeToJsBridge.h */; };
- 3DA981BB1E5B0E34004F2374 /* Platform.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0D21E03699D0018521A /* Platform.h */; };
3DA981BC1E5B0E34004F2374 /* RecoverableError.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D7454791E54757500E74ADD /* RecoverableError.h */; };
3DA981BD1E5B0E34004F2374 /* SampleCxxModule.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0D41E03699D0018521A /* SampleCxxModule.h */; };
3DA981BE1E5B0E34004F2374 /* SystraceSection.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0D51E03699D0018521A /* SystraceSection.h */; };
@@ -830,7 +699,6 @@
3DA981E31E5B0F29004F2374 /* RCTURLRequestDelegate.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 1345A83A1B265A0E00583190 /* RCTURLRequestDelegate.h */; };
3DA981E41E5B0F29004F2374 /* RCTURLRequestHandler.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 1345A83B1B265A0E00583190 /* RCTURLRequestHandler.h */; };
3DA981E51E5B0F29004F2374 /* RCTUtils.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 83CBBA4F1A601E3B00E9B192 /* RCTUtils.h */; };
- 3DA981E91E5B0F7F004F2374 /* RCTJSCSamplingProfiler.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 369123DF1DDC75850095B341 /* RCTJSCSamplingProfiler.h */; };
3DA981EA1E5B0F7F004F2374 /* RCTAccessibilityManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = E9B20B791B500126007A2DA7 /* RCTAccessibilityManager.h */; };
3DA981EB1E5B0F7F004F2374 /* RCTAlertManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13B07FE71A69327A00A75B9A /* RCTAlertManager.h */; };
3DA981EC1E5B0F7F004F2374 /* RCTAppState.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 1372B7081AB030C200659ED6 /* RCTAppState.h */; };
@@ -864,10 +732,6 @@
3DA982111E5B0F7F004F2374 /* RCTModalHostView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 83A1FE8A1B62640A00BE0E65 /* RCTModalHostView.h */; };
3DA982121E5B0F7F004F2374 /* RCTModalHostViewController.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 83392EB11B6634E10013B15F /* RCTModalHostViewController.h */; };
3DA982131E5B0F7F004F2374 /* RCTModalHostViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 83A1FE8D1B62643A00BE0E65 /* RCTModalHostViewManager.h */; };
- 3DA982141E5B0F7F004F2374 /* RCTNavigator.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13B0800C1A69489C00A75B9A /* RCTNavigator.h */; };
- 3DA982151E5B0F7F004F2374 /* RCTNavigatorManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13B0800E1A69489C00A75B9A /* RCTNavigatorManager.h */; };
- 3DA982161E5B0F7F004F2374 /* RCTNavItem.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13B080101A69489C00A75B9A /* RCTNavItem.h */; };
- 3DA982171E5B0F7F004F2374 /* RCTNavItemManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13B080121A69489C00A75B9A /* RCTNavItemManager.h */; };
3DA982181E5B0F7F004F2374 /* RCTPicker.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 58114A121AAE854800E7D092 /* RCTPicker.h */; };
3DA982191E5B0F7F004F2374 /* RCTPickerManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 58114A141AAE854800E7D092 /* RCTPickerManager.h */; };
3DA9821A1E5B0F7F004F2374 /* RCTPointerEvents.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13442BF31AA90E0B0037E5B0 /* RCTPointerEvents.h */; };
@@ -882,10 +746,6 @@
3DA982281E5B0F7F004F2374 /* RCTSliderManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 14F484541AABFCE100FDF6B9 /* RCTSliderManager.h */; };
3DA982291E5B0F7F004F2374 /* RCTSwitch.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 14F362071AABD06A001CE568 /* RCTSwitch.h */; };
3DA9822A1E5B0F7F004F2374 /* RCTSwitchManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 14F362091AABD06A001CE568 /* RCTSwitchManager.h */; };
- 3DA9822B1E5B0F7F004F2374 /* RCTTabBar.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 137327DF1AA5CF210034F82E /* RCTTabBar.h */; };
- 3DA9822C1E5B0F7F004F2374 /* RCTTabBarItem.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 137327E11AA5CF210034F82E /* RCTTabBarItem.h */; };
- 3DA9822D1E5B0F7F004F2374 /* RCTTabBarItemManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 137327E31AA5CF210034F82E /* RCTTabBarItemManager.h */; };
- 3DA9822E1E5B0F7F004F2374 /* RCTTabBarManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 137327E51AA5CF210034F82E /* RCTTabBarManager.h */; };
3DA9822F1E5B0F7F004F2374 /* RCTTextDecorationLineType.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = E3BBC8EB1ADE6F47001BBD81 /* RCTTextDecorationLineType.h */; };
3DA982301E5B0F7F004F2374 /* RCTTVView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 130443D61E401AD800D93A67 /* RCTTVView.h */; };
3DA982311E5B0F7F004F2374 /* RCTView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13E0674F1A70F44B002CDEE1 /* RCTView.h */; };
@@ -903,13 +763,6 @@
3DA982421E5B1053004F2374 /* JsArgumentHelpers.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0B11E03699D0018521A /* JsArgumentHelpers.h */; };
3DA982431E5B1053004F2374 /* JSBigString.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D7454781E54757500E74ADD /* JSBigString.h */; };
3DA982441E5B1053004F2374 /* JSBundleType.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D3CD8F51DE5FB2300167DC4 /* JSBundleType.h */; };
- 3DA982451E5B1053004F2374 /* JSCExecutor.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0B31E03699D0018521A /* JSCExecutor.h */; };
- 3DA982471E5B1053004F2374 /* JSCLegacyTracing.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0B71E03699D0018521A /* JSCLegacyTracing.h */; };
- 3DA982481E5B1053004F2374 /* JSCMemory.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0B91E03699D0018521A /* JSCMemory.h */; };
- 3DA982491E5B1053004F2374 /* JSCNativeModules.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0BB1E03699D0018521A /* JSCNativeModules.h */; };
- 3DA9824A1E5B1053004F2374 /* JSCPerfStats.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0BD1E03699D0018521A /* JSCPerfStats.h */; };
- 3DA9824B1E5B1053004F2374 /* JSCSamplingProfiler.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0BF1E03699D0018521A /* JSCSamplingProfiler.h */; };
- 3DA9824C1E5B1053004F2374 /* JSCUtils.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C31E03699D0018521A /* JSCUtils.h */; };
3DA9824E1E5B1053004F2374 /* JSIndexedRAMBundle.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C71E03699D0018521A /* JSIndexedRAMBundle.h */; };
3DA9824F1E5B1053004F2374 /* JSModulesUnbundle.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C81E03699D0018521A /* JSModulesUnbundle.h */; };
3DA982501E5B1053004F2374 /* MessageQueueThread.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C91E03699D0018521A /* MessageQueueThread.h */; };
@@ -917,20 +770,9 @@
3DA982521E5B1053004F2374 /* ModuleRegistry.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0CD1E03699D0018521A /* ModuleRegistry.h */; };
3DA982531E5B1053004F2374 /* NativeModule.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0CE1E03699D0018521A /* NativeModule.h */; };
3DA982541E5B1053004F2374 /* NativeToJsBridge.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0D01E03699D0018521A /* NativeToJsBridge.h */; };
- 3DA982561E5B1053004F2374 /* Platform.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0D21E03699D0018521A /* Platform.h */; };
3DA982571E5B1053004F2374 /* RecoverableError.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D7454791E54757500E74ADD /* RecoverableError.h */; };
3DA982581E5B1053004F2374 /* SampleCxxModule.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0D41E03699D0018521A /* SampleCxxModule.h */; };
3DA982591E5B1053004F2374 /* SystraceSection.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0D51E03699D0018521A /* SystraceSection.h */; };
- 3DA9825A1E5B1079004F2374 /* JavaScriptCore.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D7A27DC1DE32541002E3F95 /* JavaScriptCore.h */; };
- 3DA9825B1E5B1079004F2374 /* JSCHelpers.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B1081E0369AD0018521A /* JSCHelpers.h */; };
- 3DA9825C1E5B1079004F2374 /* JSCWrapper.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D7A27DE1DE32541002E3F95 /* JSCWrapper.h */; };
- 3DA9825D1E5B1079004F2374 /* noncopyable.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B1091E0369AD0018521A /* noncopyable.h */; };
- 3DA9825E1E5B1079004F2374 /* Unicode.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B10B1E0369AD0018521A /* Unicode.h */; };
- 3DA9825F1E5B1079004F2374 /* Value.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B10D1E0369AD0018521A /* Value.h */; };
- 3DA982601E5B1089004F2374 /* JSCHelpers.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B1081E0369AD0018521A /* JSCHelpers.h */; };
- 3DA982611E5B1089004F2374 /* noncopyable.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B1091E0369AD0018521A /* noncopyable.h */; };
- 3DA982621E5B1089004F2374 /* Unicode.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B10B1E0369AD0018521A /* Unicode.h */; };
- 3DA982631E5B1089004F2374 /* Value.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B10D1E0369AD0018521A /* Value.h */; };
3DC159E41E83E1AE007B1282 /* RCTRootContentView.m in Sources */ = {isa = PBXBuildFile; fileRef = 59A7B9FC1E577DBF0068EDBF /* RCTRootContentView.m */; };
3DC159E51E83E1E9007B1282 /* JSBigString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27B958731E57587D0096647A /* JSBigString.cpp */; };
3DC159E61E83E1FA007B1282 /* JSBigString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27B958731E57587D0096647A /* JSBigString.cpp */; };
@@ -942,14 +784,9 @@
3DCE53291FEAB23100613583 /* RCTDatePicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 133CAE8D1B8E5CFD00F6AD92 /* RCTDatePicker.m */; };
3DCE532A1FEAB23100613583 /* RCTDatePickerManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 58C571C01AA56C1900CDF9C8 /* RCTDatePickerManager.h */; };
3DCE532B1FEAB23100613583 /* RCTDatePickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 58C571BF1AA56C1900CDF9C8 /* RCTDatePickerManager.m */; };
- 3DDEC1521DDCE0CA0020BBDF /* RCTJSCSamplingProfiler.m in Sources */ = {isa = PBXBuildFile; fileRef = 369123E01DDC75850095B341 /* RCTJSCSamplingProfiler.m */; };
3DE4F8681DF85D8E00B9E5A0 /* YGEnums.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 130A77031DF767AF001F9587 /* YGEnums.h */; };
3DE4F8691DF85D8E00B9E5A0 /* YGMacros.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 130A77041DF767AF001F9587 /* YGMacros.h */; };
3DE4F86A1DF85D8E00B9E5A0 /* Yoga.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 130A77081DF767AF001F9587 /* Yoga.h */; };
- 3DF1BE821F26576400068F1A /* JSCTracing.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DF1BE801F26576400068F1A /* JSCTracing.cpp */; };
- 3DF1BE831F26576400068F1A /* JSCTracing.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DF1BE811F26576400068F1A /* JSCTracing.h */; };
- 3DF1BE841F26577000068F1A /* JSCTracing.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DF1BE811F26576400068F1A /* JSCTracing.h */; };
- 3DF1BE851F26577300068F1A /* JSCTracing.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DF1BE801F26576400068F1A /* JSCTracing.cpp */; };
3DFE0D161DF8574D00459392 /* YGEnums.h in Headers */ = {isa = PBXBuildFile; fileRef = 130A77031DF767AF001F9587 /* YGEnums.h */; };
3DFE0D171DF8574D00459392 /* YGMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 130A77041DF767AF001F9587 /* YGMacros.h */; };
3DFE0D191DF8574D00459392 /* Yoga.h in Headers */ = {isa = PBXBuildFile; fileRef = 130A77081DF767AF001F9587 /* Yoga.h */; };
@@ -985,8 +822,6 @@
53D1239F1FBF1EFB001B8A10 /* Yoga-internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 53CBF1851FB4FE80002CBB31 /* Yoga-internal.h */; };
53D123A01FBF1EFF001B8A10 /* Yoga.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53CBF1871FB4FE80002CBB31 /* Yoga.cpp */; };
53D123A11FBF1EFF001B8A10 /* Yoga.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53CBF1871FB4FE80002CBB31 /* Yoga.cpp */; };
- 53DEF6EA205AE5A0006A3890 /* YGFloatOptional.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53DEF6E6205AE59B006A3890 /* YGFloatOptional.cpp */; };
- 53DEF6EB205AE5A1006A3890 /* YGFloatOptional.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53DEF6E6205AE59B006A3890 /* YGFloatOptional.cpp */; };
53DEF6EC205AE5A6006A3890 /* YGFloatOptional.h in Headers */ = {isa = PBXBuildFile; fileRef = 53DEF6E7205AE59C006A3890 /* YGFloatOptional.h */; };
53DEF6ED205AE5A7006A3890 /* YGFloatOptional.h in Headers */ = {isa = PBXBuildFile; fileRef = 53DEF6E7205AE59C006A3890 /* YGFloatOptional.h */; };
53EC85E21FDEC75F0051B2B5 /* YGNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53EC85DF1FDEC75A0051B2B5 /* YGNode.cpp */; };
@@ -1057,8 +892,6 @@
597633381F4E021D005BE8A4 /* RCTShadowView+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 597633351F4E021D005BE8A4 /* RCTShadowView+Internal.h */; };
597633391F4E021D005BE8A4 /* RCTShadowView+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 597633351F4E021D005BE8A4 /* RCTShadowView+Internal.h */; };
598FD1921F816A2A006C54CB /* RAMBundleRegistry.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = C6D380181F71D75B00621378 /* RAMBundleRegistry.h */; };
- 598FD1931F817284006C54CB /* PrivateDataBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9936F3351F5F2F480010BF04 /* PrivateDataBase.cpp */; };
- 598FD1941F8172A9006C54CB /* PrivateDataBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 9936F3361F5F2F480010BF04 /* PrivateDataBase.h */; };
598FD1951F817335006C54CB /* RCTModalManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 91076A881F743AB00081B4FA /* RCTModalManager.h */; };
598FD1961F817335006C54CB /* RCTModalManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 91076A871F743AB00081B4FA /* RCTModalManager.m */; };
598FD1971F817336006C54CB /* RCTModalManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 91076A881F743AB00081B4FA /* RCTModalManager.h */; };
@@ -1123,7 +956,6 @@
59EDBCA71FDF4E0C003573DE /* RCTScrollableProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EDBC9C1FDF4E0C003573DE /* RCTScrollableProtocol.h */; };
59EDBCA81FDF4E0C003573DE /* RCTScrollableProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EDBC9C1FDF4E0C003573DE /* RCTScrollableProtocol.h */; };
59EDBCA91FDF4E0C003573DE /* (null) in Headers */ = {isa = PBXBuildFile; };
- 59EDBCAA1FDF4E0C003573DE /* (null) in Headers */ = {isa = PBXBuildFile; };
59EDBCAB1FDF4E0C003573DE /* (null) in Sources */ = {isa = PBXBuildFile; };
59EDBCAC1FDF4E0C003573DE /* (null) in Sources */ = {isa = PBXBuildFile; };
59EDBCAD1FDF4E0C003573DE /* RCTScrollContentView.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EDBC9F1FDF4E0C003573DE /* RCTScrollContentView.h */; };
@@ -1131,7 +963,6 @@
59EDBCAF1FDF4E0C003573DE /* RCTScrollContentView.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EDBCA01FDF4E0C003573DE /* RCTScrollContentView.m */; };
59EDBCB01FDF4E0C003573DE /* RCTScrollContentView.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EDBCA01FDF4E0C003573DE /* RCTScrollContentView.m */; };
59EDBCB11FDF4E0C003573DE /* (null) in Headers */ = {isa = PBXBuildFile; };
- 59EDBCB21FDF4E0C003573DE /* (null) in Headers */ = {isa = PBXBuildFile; };
59EDBCB31FDF4E0C003573DE /* (null) in Sources */ = {isa = PBXBuildFile; };
59EDBCB41FDF4E0C003573DE /* (null) in Sources */ = {isa = PBXBuildFile; };
59EDBCB51FDF4E0C003573DE /* RCTScrollView.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EDBCA31FDF4E0C003573DE /* RCTScrollView.h */; };
@@ -1154,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 */; };
@@ -1178,7 +1008,27 @@
66CD94B81F1045E700CB3C7C /* RCTMaskedViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 66CD94B01F1045E700CB3C7C /* RCTMaskedViewManager.m */; };
68EFE4EE1CF6EB3900A1DE13 /* RCTBundleURLProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 68EFE4ED1CF6EB3900A1DE13 /* RCTBundleURLProvider.m */; };
830A229E1A66C68A008503DA /* RCTRootView.m in Sources */ = {isa = PBXBuildFile; fileRef = 830A229D1A66C68A008503DA /* RCTRootView.m */; };
+ 83281384217EB70900574D55 /* MallocImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83281383217EB70800574D55 /* MallocImpl.cpp */; };
+ 83281385217EB71200574D55 /* MallocImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83281383217EB70800574D55 /* MallocImpl.cpp */; };
+ 83281387217EB73400574D55 /* String.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83281386217EB73400574D55 /* String.cpp */; };
+ 83281388217EB73400574D55 /* String.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83281386217EB73400574D55 /* String.cpp */; };
+ 8328138A217EB74C00574D55 /* json_pointer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83281389217EB74C00574D55 /* json_pointer.cpp */; };
+ 8328138B217EB74C00574D55 /* json_pointer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83281389217EB74C00574D55 /* json_pointer.cpp */; };
+ 8328138D217EB75C00574D55 /* ColdClass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8328138C217EB75C00574D55 /* ColdClass.cpp */; };
+ 8328138E217EB75C00574D55 /* ColdClass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8328138C217EB75C00574D55 /* ColdClass.cpp */; };
+ 83281390217EB76C00574D55 /* Demangle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8328138F217EB76B00574D55 /* Demangle.cpp */; };
+ 83281391217EB76C00574D55 /* Demangle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8328138F217EB76B00574D55 /* Demangle.cpp */; };
+ 83281393217EB77D00574D55 /* SpookyHashV2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83281392217EB77C00574D55 /* SpookyHashV2.cpp */; };
+ 83281394217EB77D00574D55 /* SpookyHashV2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83281392217EB77C00574D55 /* SpookyHashV2.cpp */; };
+ 83281396217EB79000574D55 /* F14Table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83281395217EB78F00574D55 /* F14Table.cpp */; };
+ 83281397217EB79000574D55 /* F14Table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83281395217EB78F00574D55 /* F14Table.cpp */; };
+ 83281399217EB79D00574D55 /* ScopeGuard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83281398217EB79D00574D55 /* ScopeGuard.cpp */; };
+ 8328139A217EB79D00574D55 /* ScopeGuard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83281398217EB79D00574D55 /* ScopeGuard.cpp */; };
83392EB31B6634E10013B15F /* RCTModalHostViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 83392EB21B6634E10013B15F /* RCTModalHostViewController.m */; };
+ 833D02BA217EBCFA00A23750 /* Assume.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 833D02B9217EBCFA00A23750 /* Assume.cpp */; };
+ 833D02BB217EBCFA00A23750 /* Assume.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 833D02B9217EBCFA00A23750 /* Assume.cpp */; };
+ 833D02BD217EBD2600A23750 /* Format.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 833D02BC217EBD2600A23750 /* Format.cpp */; };
+ 833D02BE217EBD2600A23750 /* Format.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 833D02BC217EBD2600A23750 /* Format.cpp */; };
83A1FE8C1B62640A00BE0E65 /* RCTModalHostView.m in Sources */ = {isa = PBXBuildFile; fileRef = 83A1FE8B1B62640A00BE0E65 /* RCTModalHostView.m */; };
83A1FE8F1B62643A00BE0E65 /* RCTModalHostViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 83A1FE8E1B62643A00BE0E65 /* RCTModalHostViewManager.m */; };
83CBBA511A601E3B00E9B192 /* RCTAssert.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA4B1A601E3B00E9B192 /* RCTAssert.m */; };
@@ -1188,25 +1038,44 @@
83CBBA691A601EF300E9B192 /* RCTEventDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA661A601EF300E9B192 /* RCTEventDispatcher.m */; };
83CBBA981A6020BB00E9B192 /* RCTTouchHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA971A6020BB00E9B192 /* RCTTouchHandler.m */; };
83CBBACC1A6023D300E9B192 /* RCTConvert.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBACB1A6023D300E9B192 /* RCTConvert.m */; };
+ 8507BBBE21EDACC200AEAFCA /* JSCExecutorFactory.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8507BBBC21EDACC200AEAFCA /* JSCExecutorFactory.mm */; };
+ 8507BBBF21EDACC200AEAFCA /* JSCExecutorFactory.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8507BBBC21EDACC200AEAFCA /* JSCExecutorFactory.mm */; };
+ 8507BBC021EDACC200AEAFCA /* JSCExecutorFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = 8507BBBD21EDACC200AEAFCA /* JSCExecutorFactory.h */; };
+ 8507BBC121EDACC200AEAFCA /* JSCExecutorFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = 8507BBBD21EDACC200AEAFCA /* JSCExecutorFactory.h */; };
916F9C2D1F743F57002E5920 /* RCTModalManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 91076A871F743AB00081B4FA /* RCTModalManager.m */; };
- 9936F3371F5F2F480010BF04 /* PrivateDataBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9936F3351F5F2F480010BF04 /* PrivateDataBase.cpp */; };
- 9936F3381F5F2F480010BF04 /* PrivateDataBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 9936F3361F5F2F480010BF04 /* PrivateDataBase.h */; };
- 9936F3391F5F2F5C0010BF04 /* PrivateDataBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 9936F3361F5F2F480010BF04 /* PrivateDataBase.h */; };
- 9936F33A1F5F2F7C0010BF04 /* PrivateDataBase.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 9936F3361F5F2F480010BF04 /* PrivateDataBase.h */; };
- 9936F33B1F5F2F9D0010BF04 /* PrivateDataBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9936F3351F5F2F480010BF04 /* PrivateDataBase.cpp */; };
- 9936F33C1F5F2FE70010BF04 /* PrivateDataBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 9936F3361F5F2F480010BF04 /* PrivateDataBase.h */; };
- 9936F33D1F5F2FF40010BF04 /* PrivateDataBase.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 9936F3361F5F2F480010BF04 /* PrivateDataBase.h */; };
- 9936F33E1F5F2FFC0010BF04 /* PrivateDataBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9936F3351F5F2F480010BF04 /* PrivateDataBase.cpp */; };
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 */; };
+ 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 */; };
+ 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 */; };
+ AC6B69E721B146B400B2B68A /* YGValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AC6B69E121B1467C00B2B68A /* YGValue.cpp */; };
+ AC6B69E821B146C500B2B68A /* YGValue.h in Headers */ = {isa = PBXBuildFile; fileRef = AC6B69E221B1467C00B2B68A /* YGValue.h */; };
+ AC6B69E921B146DB00B2B68A /* YGValue.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = AC6B69E221B1467C00B2B68A /* YGValue.h */; };
+ AC6B69EA21B146E700B2B68A /* YGValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AC6B69E121B1467C00B2B68A /* YGValue.cpp */; };
AC70D2E91DE489E4002E6351 /* RCTJavaScriptLoader.mm in Sources */ = {isa = PBXBuildFile; fileRef = AC70D2E81DE489E4002E6351 /* RCTJavaScriptLoader.mm */; };
+ AC71763521B0274000C06877 /* YGConfig.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5CE2080120772F7C009A43B3 /* YGConfig.h */; };
+ AC71763621B0274A00C06877 /* YGMarker.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = AC8360CC21B0256A00FC46B9 /* YGMarker.h */; };
+ AC8360CD21B0256A00FC46B9 /* YGMarker.h in Headers */ = {isa = PBXBuildFile; fileRef = AC8360CC21B0256A00FC46B9 /* YGMarker.h */; };
+ AC8360CE21B0256A00FC46B9 /* YGMarker.h in Headers */ = {isa = PBXBuildFile; fileRef = AC8360CC21B0256A00FC46B9 /* YGMarker.h */; };
+ AC8360CF21B0258B00FC46B9 /* YGConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CE2080120772F7C009A43B3 /* YGConfig.h */; };
+ AC8360D121B025BC00FC46B9 /* YGConfig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5CE2080020772F7C009A43B3 /* YGConfig.cpp */; };
+ AC8360D221B025EF00FC46B9 /* YGConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CE2080120772F7C009A43B3 /* YGConfig.h */; };
+ AC8360D321B0263000FC46B9 /* YGMarker.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = AC8360CC21B0256A00FC46B9 /* YGMarker.h */; };
+ AC90463E21C91CC2005B24B3 /* CompactValue.h in Headers */ = {isa = PBXBuildFile; fileRef = AC90463D21C91CC2005B24B3 /* CompactValue.h */; };
+ AC90463F21C91D02005B24B3 /* CompactValue.h in Headers */ = {isa = PBXBuildFile; fileRef = AC90463D21C91CC2005B24B3 /* CompactValue.h */; };
+ AC90464021C91D14005B24B3 /* CompactValue.h in Headers */ = {isa = PBXBuildFile; fileRef = AC90463D21C91CC2005B24B3 /* CompactValue.h */; };
+ AC90464121C91DB8005B24B3 /* YGConfig.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5CE2080120772F7C009A43B3 /* YGConfig.h */; };
B233E6EA1D2D845D00BC68BA /* RCTI18nManager.m in Sources */ = {isa = PBXBuildFile; fileRef = B233E6E91D2D845D00BC68BA /* RCTI18nManager.m */; };
B95154321D1B34B200FE7B80 /* RCTActivityIndicatorView.m in Sources */ = {isa = PBXBuildFile; fileRef = B95154311D1B34B200FE7B80 /* RCTActivityIndicatorView.m */; };
BA0501AD2109DCF200A6BBC4 /* ReactMarker.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13DA8A2F2097A90A00276ED4 /* ReactMarker.h */; };
BA0501AE2109DD0600A6BBC4 /* JSExecutor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E223624320875A8000108244 /* JSExecutor.cpp */; };
BA0501B02109DD1800A6BBC4 /* YGConfig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5CE2080020772F7C009A43B3 /* YGConfig.cpp */; };
- BA0501B12109DD1C00A6BBC4 /* YGConfig.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5CE2080120772F7C009A43B3 /* YGConfig.h */; };
C60128AB1F3D1258009DF9FF /* RCTCxxConvert.h in Headers */ = {isa = PBXBuildFile; fileRef = C60128A91F3D1258009DF9FF /* RCTCxxConvert.h */; };
C60128AC1F3D1258009DF9FF /* RCTCxxConvert.h in Headers */ = {isa = PBXBuildFile; fileRef = C60128A91F3D1258009DF9FF /* RCTCxxConvert.h */; };
C60128AD1F3D1258009DF9FF /* RCTCxxConvert.m in Sources */ = {isa = PBXBuildFile; fileRef = C60128AA1F3D1258009DF9FF /* RCTCxxConvert.m */; };
@@ -1229,26 +1098,72 @@
E223624420875A8000108244 /* JSExecutor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E223624320875A8000108244 /* JSExecutor.cpp */; };
E9B20B7B1B500126007A2DA7 /* RCTAccessibilityManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E9B20B7A1B500126007A2DA7 /* RCTAccessibilityManager.m */; };
EBF21BBC1FC498270052F4D5 /* InspectorInterfaces.h in Headers */ = {isa = PBXBuildFile; fileRef = EBF21BBA1FC498270052F4D5 /* InspectorInterfaces.h */; };
- EBF21BBD1FC498270052F4D5 /* InspectorInterfaces.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EBF21BBB1FC498270052F4D5 /* InspectorInterfaces.cpp */; };
EBF21BBE1FC498630052F4D5 /* InspectorInterfaces.h in Headers */ = {isa = PBXBuildFile; fileRef = EBF21BBA1FC498270052F4D5 /* InspectorInterfaces.h */; };
EBF21BFB1FC498FC0052F4D5 /* InspectorInterfaces.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = EBF21BBA1FC498270052F4D5 /* InspectorInterfaces.h */; };
EBF21BFC1FC4990B0052F4D5 /* InspectorInterfaces.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EBF21BBB1FC498270052F4D5 /* InspectorInterfaces.cpp */; };
EBF21BFE1FC499840052F4D5 /* InspectorInterfaces.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = EBF21BBA1FC498270052F4D5 /* InspectorInterfaces.h */; };
EBF21BFF1FC4998E0052F4D5 /* InspectorInterfaces.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EBF21BBB1FC498270052F4D5 /* InspectorInterfaces.cpp */; };
- EBF21C001FC499A80052F4D5 /* InspectorInterfaces.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EBF21BBB1FC498270052F4D5 /* InspectorInterfaces.cpp */; };
+ ED296F82214C973700B7C4FE /* libjsinspector-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EBF21BFA1FC4989A0052F4D5 /* libjsinspector-tvOS.a */; };
+ ED296F83214C974A00B7C4FE /* libyoga.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D3C06751DE3340C00C268FA /* libyoga.a */; };
+ ED296FB7214C9A9A00B7C4FE /* JSIDynamic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EDEBC6DA214B3F6800DD5AC8 /* JSIDynamic.cpp */; };
+ ED296FB8214C9A9A00B7C4FE /* jsi.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EDEBC6DB214B3F6800DD5AC8 /* jsi.cpp */; };
+ ED296FB9214C9AC200B7C4FE /* JSCRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EDEBC6DD214B3F6800DD5AC8 /* JSCRuntime.cpp */; };
+ ED296FBC214C9B0400B7C4FE /* jsi-inl.h in Headers */ = {isa = PBXBuildFile; fileRef = EDEBC6D9214B3F6800DD5AC8 /* jsi-inl.h */; };
+ ED296FBF214C9B0400B7C4FE /* JSIDynamic.h in Headers */ = {isa = PBXBuildFile; fileRef = EDEBC6DC214B3F6800DD5AC8 /* JSIDynamic.h */; };
+ ED296FC1214C9B0400B7C4FE /* JSCRuntime.h in Headers */ = {isa = PBXBuildFile; fileRef = EDEBC6DE214B3F6800DD5AC8 /* JSCRuntime.h */; };
+ ED296FC3214C9B0400B7C4FE /* instrumentation.h in Headers */ = {isa = PBXBuildFile; fileRef = EDEBC6E0214B3F6800DD5AC8 /* instrumentation.h */; };
+ ED296FC4214C9B0400B7C4FE /* jsi.h in Headers */ = {isa = PBXBuildFile; fileRef = EDEBC6E1214B3F6800DD5AC8 /* jsi.h */; };
+ ED296FC5214C9B3E00B7C4FE /* jsi-inl.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = EDEBC6D9214B3F6800DD5AC8 /* jsi-inl.h */; };
+ ED296FC6214C9B4400B7C4FE /* JSIDynamic.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = EDEBC6DC214B3F6800DD5AC8 /* JSIDynamic.h */; };
+ ED296FC7214C9B4B00B7C4FE /* instrumentation.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = EDEBC6E0214B3F6800DD5AC8 /* instrumentation.h */; };
+ ED296FC8214C9B5200B7C4FE /* jsi.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = EDEBC6E1214B3F6800DD5AC8 /* jsi.h */; };
+ ED296FCB214C9B6C00B7C4FE /* libjsi-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ED296FB6214C9A0900B7C4FE /* libjsi-tvOS.a */; };
+ ED29703E2150126E00B7C4FE /* AtomicIntrusiveLinkedList.h in Headers */ = {isa = PBXBuildFile; fileRef = 139D849C1E273B5600323FB7 /* AtomicIntrusiveLinkedList.h */; };
+ ED2970422150126E00B7C4FE /* Conv.h in Headers */ = {isa = PBXBuildFile; fileRef = 139D84A01E273B5600323FB7 /* Conv.h */; };
+ ED2970432150126E00B7C4FE /* dynamic-inl.h in Headers */ = {isa = PBXBuildFile; fileRef = 139D84A11E273B5600323FB7 /* dynamic-inl.h */; };
+ ED2970452150126E00B7C4FE /* dynamic.h in Headers */ = {isa = PBXBuildFile; fileRef = 139D84A31E273B5600323FB7 /* dynamic.h */; };
+ ED2970462150126E00B7C4FE /* Exception.h in Headers */ = {isa = PBXBuildFile; fileRef = 139D84A41E273B5600323FB7 /* Exception.h */; };
+ ED2970482150126E00B7C4FE /* json.h in Headers */ = {isa = PBXBuildFile; fileRef = 139D84A81E273B5600323FB7 /* json.h */; };
+ ED2970492150126E00B7C4FE /* Memory.h in Headers */ = {isa = PBXBuildFile; fileRef = 139D84A91E273B5600323FB7 /* Memory.h */; };
+ ED29704A2150126E00B7C4FE /* MoveWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 139D84AA1E273B5600323FB7 /* MoveWrapper.h */; };
+ ED29704B2150126E00B7C4FE /* Optional.h in Headers */ = {isa = PBXBuildFile; fileRef = 139D84AB1E273B5600323FB7 /* Optional.h */; };
+ ED29704C2150126E00B7C4FE /* ScopeGuard.h in Headers */ = {isa = PBXBuildFile; fileRef = 139D84AC1E273B5600323FB7 /* ScopeGuard.h */; };
+ ED29704F2150199F00B7C4FE /* JSCRuntime.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = EDEBC6DE214B3F6800DD5AC8 /* JSCRuntime.h */; };
+ ED297050215019B400B7C4FE /* instrumentation.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = EDEBC6E0214B3F6800DD5AC8 /* instrumentation.h */; };
+ ED297067215023D800B7C4FE /* libjsiexecutor-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ED296FEE214C9CF800B7C4FE /* libjsiexecutor-tvOS.a */; };
+ ED6189692155BBF70000C9A7 /* JSIExecutor.h in Headers */ = {isa = PBXBuildFile; fileRef = ED6189672155BBF70000C9A7 /* JSIExecutor.h */; };
+ ED61896A2155BBF70000C9A7 /* JSIExecutor.h in Headers */ = {isa = PBXBuildFile; fileRef = ED6189672155BBF70000C9A7 /* JSIExecutor.h */; };
+ ED61896B2155BBF70000C9A7 /* JSINativeModules.h in Headers */ = {isa = PBXBuildFile; fileRef = ED6189682155BBF70000C9A7 /* JSINativeModules.h */; };
+ ED61896C2155BBF70000C9A7 /* JSINativeModules.h in Headers */ = {isa = PBXBuildFile; fileRef = ED6189682155BBF70000C9A7 /* JSINativeModules.h */; };
+ ED7286BC2155C62000C26ABF /* JSIExecutor.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = ED6189672155BBF70000C9A7 /* JSIExecutor.h */; };
+ ED7286BD2155C62000C26ABF /* JSINativeModules.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = ED6189682155BBF70000C9A7 /* JSINativeModules.h */; };
+ ED7286BE2155C62B00C26ABF /* JSIExecutor.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = ED6189672155BBF70000C9A7 /* JSIExecutor.h */; };
+ ED7286BF2155C62B00C26ABF /* JSINativeModules.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = ED6189682155BBF70000C9A7 /* JSINativeModules.h */; };
+ EDDA711D2164285A00B2D070 /* JSINativeModules.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EDDA711B2164285A00B2D070 /* JSINativeModules.cpp */; };
+ EDDA711E2164285A00B2D070 /* JSINativeModules.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EDDA711B2164285A00B2D070 /* JSINativeModules.cpp */; };
+ EDDA711F2164285A00B2D070 /* JSIExecutor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EDDA711C2164285A00B2D070 /* JSIExecutor.cpp */; };
+ EDDA71202164285A00B2D070 /* JSIExecutor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EDDA711C2164285A00B2D070 /* JSIExecutor.cpp */; };
+ EDEBC6E2214B3F6800DD5AC8 /* jsi-inl.h in Headers */ = {isa = PBXBuildFile; fileRef = EDEBC6D9214B3F6800DD5AC8 /* jsi-inl.h */; };
+ EDEBC6E3214B3F6800DD5AC8 /* JSIDynamic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EDEBC6DA214B3F6800DD5AC8 /* JSIDynamic.cpp */; };
+ EDEBC6E4214B3F6800DD5AC8 /* jsi.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EDEBC6DB214B3F6800DD5AC8 /* jsi.cpp */; };
+ EDEBC6E5214B3F6800DD5AC8 /* JSIDynamic.h in Headers */ = {isa = PBXBuildFile; fileRef = EDEBC6DC214B3F6800DD5AC8 /* JSIDynamic.h */; };
+ EDEBC6E6214B3F6800DD5AC8 /* JSCRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EDEBC6DD214B3F6800DD5AC8 /* JSCRuntime.cpp */; };
+ EDEBC6E7214B3F6800DD5AC8 /* JSCRuntime.h in Headers */ = {isa = PBXBuildFile; fileRef = EDEBC6DE214B3F6800DD5AC8 /* JSCRuntime.h */; };
+ EDEBC6E8214B3F6800DD5AC8 /* instrumentation.h in Headers */ = {isa = PBXBuildFile; fileRef = EDEBC6E0214B3F6800DD5AC8 /* instrumentation.h */; };
+ EDEBC6E9214B3F6800DD5AC8 /* jsi.h in Headers */ = {isa = PBXBuildFile; fileRef = EDEBC6E1214B3F6800DD5AC8 /* jsi.h */; };
+ EDEBC71A214B40A300DD5AC8 /* libjsi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EDEBC6D6214B3E7000DD5AC8 /* libjsi.a */; };
+ EDEBC71C214B40F900DD5AC8 /* jsi-inl.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = EDEBC6D9214B3F6800DD5AC8 /* jsi-inl.h */; };
+ EDEBC71D214B40F900DD5AC8 /* JSIDynamic.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = EDEBC6DC214B3F6800DD5AC8 /* JSIDynamic.h */; };
+ EDEBC71E214B40F900DD5AC8 /* JSCRuntime.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = EDEBC6DE214B3F6800DD5AC8 /* JSCRuntime.h */; };
+ EDEBC71F214B40F900DD5AC8 /* jsi.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = EDEBC6E1214B3F6800DD5AC8 /* jsi.h */; };
+ EDEBC7DF214C705700DD5AC8 /* libjsiexecutor.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EDEBC73B214B45A300DD5AC8 /* libjsiexecutor.a */; };
+ EDEBC7E0214C709200DD5AC8 /* libjsinspector.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EBF21BDC1FC498900052F4D5 /* libjsinspector.a */; };
F1EFDA50201F661000EE6E4C /* RCTUIUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = F1EFDA4E201F660F00EE6E4C /* RCTUIUtils.m */; };
FEFAAC9E1FDB89B50057BBE0 /* RCTRedBoxExtraDataViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FEFAAC9C1FDB89B40057BBE0 /* RCTRedBoxExtraDataViewController.m */; };
FEFAAC9F1FDB89B50057BBE0 /* RCTRedBoxExtraDataViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = FEFAAC9D1FDB89B40057BBE0 /* RCTRedBoxExtraDataViewController.h */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
- 1320081A1E283DC300F0C457 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 139D7ECD1E25DB7D00323FB7;
- remoteInfo = "third-party";
- };
1320081C1E283DCB00F0C457 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
@@ -1270,13 +1185,6 @@
remoteGlobalIDString = 3D3CD9261DE5FBEE00167DC4;
remoteInfo = "cxxreact-tvOS";
};
- 3D383D631EBD27CE005632C8 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 3D383D211EBD27B6005632C8;
- remoteInfo = "third-party-tvOS";
- };
3D383D651EBD27DB005632C8 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
@@ -1291,68 +1199,124 @@
remoteGlobalIDString = 3D3CD9191DE5FBEC00167DC4;
remoteInfo = cxxreact;
};
- 3D3CD94F1DE5FDB900167DC4 /* PBXContainerItemProxy */ = {
+ 53D123981FBF1E0C001B8A10 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
proxyType = 1;
- remoteGlobalIDString = 3D3CD8FF1DE5FBD600167DC4;
- remoteInfo = jschelpers;
+ remoteGlobalIDString = 3D3C04B91DE3340900C268FA;
+ remoteInfo = yoga;
};
- 3DC159E71E83E2A0007B1282 /* PBXContainerItemProxy */ = {
+ ED296F7D214C957300B7C4FE /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
proxyType = 1;
- remoteGlobalIDString = 3D3CD90C1DE5FBD800167DC4;
- remoteInfo = "jschelpers-tvOS";
+ remoteGlobalIDString = EDEBC6BA214B3E7000DD5AC8;
+ remoteInfo = jsi;
};
- 53D123981FBF1E0C001B8A10 /* PBXContainerItemProxy */ = {
+ ED296F80214C971800B7C4FE /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
proxyType = 1;
- remoteGlobalIDString = 3D3C04B91DE3340900C268FA;
- remoteInfo = yoga;
+ remoteGlobalIDString = EBF21BDD1FC4989A0052F4D5;
+ remoteInfo = "jsinspector-tvOS";
};
- 9936F33F1F5F305D0010BF04 /* PBXContainerItemProxy */ = {
+ ED296F96214C996500B7C4FE /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
proxyType = 1;
- remoteGlobalIDString = 9936F2F81F5F2E4B0010BF04;
- remoteInfo = privatedata;
+ remoteGlobalIDString = 3D383D3D1EBD27B9005632C8;
+ remoteInfo = "double-conversion-tvOS";
};
- 9936F3411F5F30640010BF04 /* PBXContainerItemProxy */ = {
+ ED296FC9214C9B6200B7C4FE /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
proxyType = 1;
- remoteGlobalIDString = 9936F3141F5F2E5B0010BF04;
- remoteInfo = "privatedata-tvOS";
+ remoteGlobalIDString = ED296F98214C9A0900B7C4FE;
+ remoteInfo = "jsi-tvOS";
};
- 9936F3431F5F30780010BF04 /* PBXContainerItemProxy */ = {
+ ED296FF7214C9EAA00B7C4FE /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
proxyType = 1;
- remoteGlobalIDString = 9936F2F81F5F2E4B0010BF04;
- remoteInfo = privatedata;
+ remoteGlobalIDString = 3D383D211EBD27B6005632C8;
+ remoteInfo = "third-party-tvOS";
};
- 9936F3451F5F30830010BF04 /* PBXContainerItemProxy */ = {
+ ED296FFB214C9EC000B7C4FE /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
proxyType = 1;
- remoteGlobalIDString = 9936F3141F5F2E5B0010BF04;
- remoteInfo = "privatedata-tvOS";
+ remoteGlobalIDString = 3D3CD9261DE5FBEE00167DC4;
+ remoteInfo = "cxxreact-tvOS";
};
- EBF21C011FC499D10052F4D5 /* PBXContainerItemProxy */ = {
+ ED296FFD214C9EC600B7C4FE /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
proxyType = 1;
- remoteGlobalIDString = EBF21BBF1FC498900052F4D5;
- remoteInfo = jsinspector;
+ remoteGlobalIDString = ED296F98214C9A0900B7C4FE;
+ remoteInfo = "jsi-tvOS";
};
- EBF21C031FC499D80052F4D5 /* PBXContainerItemProxy */ = {
+ ED29704D215012C700B7C4FE /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
proxyType = 1;
- remoteGlobalIDString = EBF21BDD1FC4989A0052F4D5;
- remoteInfo = "jsinspector-tvOS";
+ remoteGlobalIDString = 3D383D3D1EBD27B9005632C8;
+ remoteInfo = "double-conversion-tvOS";
+ };
+ ED2970652150237300B7C4FE /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = ED296FD0214C9CF800B7C4FE;
+ remoteInfo = "jsiexecutor-tvOS";
+ };
+ EDEBC74A214B46A700DD5AC8 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = EDEBC724214B45A300DD5AC8;
+ remoteInfo = jsiexecutor;
+ };
+ EDEBC74E214B477400DD5AC8 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = EDEBC6BA214B3E7000DD5AC8;
+ remoteInfo = jsi;
+ };
+ EDEBC7CB214C516800DD5AC8 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 139D7E871E25C6D100323FB7;
+ remoteInfo = "double-conversion";
+ };
+ EDEBC7CD214C523F00DD5AC8 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 3D3CD9191DE5FBEC00167DC4;
+ remoteInfo = cxxreact;
+ };
+ EDEBC7D2214C528C00DD5AC8 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 139D7ECD1E25DB7D00323FB7;
+ remoteInfo = "third-party";
+ };
+ EDEBC7D6214C52FD00DD5AC8 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 139D7E871E25C6D100323FB7;
+ remoteInfo = "double-conversion";
+ };
+ EDEBC7D8214C628300DD5AC8 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = EBF21BBF1FC498900052F4D5;
+ remoteInfo = jsinspector;
};
/* End PBXContainerItemProxy section */
@@ -1414,7 +1378,6 @@
3D383D201EBD27AF005632C8 /* RCTBridge+Private.h in Copy Headers */,
3D7BFD351EA8E43F008DFB7A /* RCTDevSettings.h in Copy Headers */,
3D7BFD331EA8E433008DFB7A /* RCTPackagerClient.h in Copy Headers */,
- 3DA981E91E5B0F7F004F2374 /* RCTJSCSamplingProfiler.h in Copy Headers */,
3DA981EA1E5B0F7F004F2374 /* RCTAccessibilityManager.h in Copy Headers */,
3DA981EB1E5B0F7F004F2374 /* RCTAlertManager.h in Copy Headers */,
3DA981EC1E5B0F7F004F2374 /* RCTAppState.h in Copy Headers */,
@@ -1448,10 +1411,6 @@
3DA982111E5B0F7F004F2374 /* RCTModalHostView.h in Copy Headers */,
3DA982121E5B0F7F004F2374 /* RCTModalHostViewController.h in Copy Headers */,
3DA982131E5B0F7F004F2374 /* RCTModalHostViewManager.h in Copy Headers */,
- 3DA982141E5B0F7F004F2374 /* RCTNavigator.h in Copy Headers */,
- 3DA982151E5B0F7F004F2374 /* RCTNavigatorManager.h in Copy Headers */,
- 3DA982161E5B0F7F004F2374 /* RCTNavItem.h in Copy Headers */,
- 3DA982171E5B0F7F004F2374 /* RCTNavItemManager.h in Copy Headers */,
3DA982181E5B0F7F004F2374 /* RCTPicker.h in Copy Headers */,
3DA982191E5B0F7F004F2374 /* RCTPickerManager.h in Copy Headers */,
3DA9821A1E5B0F7F004F2374 /* RCTPointerEvents.h in Copy Headers */,
@@ -1466,10 +1425,6 @@
3DA982281E5B0F7F004F2374 /* RCTSliderManager.h in Copy Headers */,
3DA982291E5B0F7F004F2374 /* RCTSwitch.h in Copy Headers */,
3DA9822A1E5B0F7F004F2374 /* RCTSwitchManager.h in Copy Headers */,
- 3DA9822B1E5B0F7F004F2374 /* RCTTabBar.h in Copy Headers */,
- 3DA9822C1E5B0F7F004F2374 /* RCTTabBarItem.h in Copy Headers */,
- 3DA9822D1E5B0F7F004F2374 /* RCTTabBarItemManager.h in Copy Headers */,
- 3DA9822E1E5B0F7F004F2374 /* RCTTabBarManager.h in Copy Headers */,
3DA9822F1E5B0F7F004F2374 /* RCTTextDecorationLineType.h in Copy Headers */,
3DA982301E5B0F7F004F2374 /* RCTTVView.h in Copy Headers */,
3DA982311E5B0F7F004F2374 /* RCTView.h in Copy Headers */,
@@ -1525,7 +1480,9 @@
dstPath = include/yoga;
dstSubfolderSpec = 16;
files = (
- BA0501B12109DD1C00A6BBC4 /* YGConfig.h in Copy Headers */,
+ AC6B69E921B146DB00B2B68A /* YGValue.h in Copy Headers */,
+ AC71763621B0274A00C06877 /* YGMarker.h in Copy Headers */,
+ AC71763521B0274000C06877 /* YGConfig.h in Copy Headers */,
3DFE0D1A1DF8575800459392 /* YGEnums.h in Copy Headers */,
3DFE0D1B1DF8575800459392 /* YGMacros.h in Copy Headers */,
3DFE0D1C1DF8575800459392 /* Yoga.h in Copy Headers */,
@@ -1549,13 +1506,6 @@
3DA982421E5B1053004F2374 /* JsArgumentHelpers.h in Copy Headers */,
3DA982431E5B1053004F2374 /* JSBigString.h in Copy Headers */,
3DA982441E5B1053004F2374 /* JSBundleType.h in Copy Headers */,
- 3DA982451E5B1053004F2374 /* JSCExecutor.h in Copy Headers */,
- 3DA982471E5B1053004F2374 /* JSCLegacyTracing.h in Copy Headers */,
- 3DA982481E5B1053004F2374 /* JSCMemory.h in Copy Headers */,
- 3DA982491E5B1053004F2374 /* JSCNativeModules.h in Copy Headers */,
- 3DA9824A1E5B1053004F2374 /* JSCPerfStats.h in Copy Headers */,
- 3DA9824B1E5B1053004F2374 /* JSCSamplingProfiler.h in Copy Headers */,
- 3DA9824C1E5B1053004F2374 /* JSCUtils.h in Copy Headers */,
3DA9824E1E5B1053004F2374 /* JSIndexedRAMBundle.h in Copy Headers */,
3DA9824F1E5B1053004F2374 /* JSModulesUnbundle.h in Copy Headers */,
3DA982501E5B1053004F2374 /* MessageQueueThread.h in Copy Headers */,
@@ -1563,7 +1513,6 @@
3DA982521E5B1053004F2374 /* ModuleRegistry.h in Copy Headers */,
3DA982531E5B1053004F2374 /* NativeModule.h in Copy Headers */,
3DA982541E5B1053004F2374 /* NativeToJsBridge.h in Copy Headers */,
- 3DA982561E5B1053004F2374 /* Platform.h in Copy Headers */,
3DA982571E5B1053004F2374 /* RecoverableError.h in Copy Headers */,
3DA982581E5B1053004F2374 /* SampleCxxModule.h in Copy Headers */,
3DA982591E5B1053004F2374 /* SystraceSection.h in Copy Headers */,
@@ -1571,22 +1520,6 @@
name = "Copy Headers";
runOnlyForDeploymentPostprocessing = 0;
};
- 3D302F1D1DF8264A00D6DDAE /* Copy Headers */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 2147483647;
- dstPath = include/jschelpers;
- dstSubfolderSpec = 16;
- files = (
- 3DA982601E5B1089004F2374 /* JSCHelpers.h in Copy Headers */,
- 3DA982611E5B1089004F2374 /* noncopyable.h in Copy Headers */,
- 3DA982621E5B1089004F2374 /* Unicode.h in Copy Headers */,
- 3DA982631E5B1089004F2374 /* Value.h in Copy Headers */,
- 3D302F1E1DF8265A00D6DDAE /* JavaScriptCore.h in Copy Headers */,
- 3D302F1F1DF8265A00D6DDAE /* JSCWrapper.h in Copy Headers */,
- );
- name = "Copy Headers";
- runOnlyForDeploymentPostprocessing = 0;
- };
3D383D491EBD27B9005632C8 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
@@ -1680,7 +1613,6 @@
3D80D9481DF6FA890028D040 /* RCTURLRequestDelegate.h in Copy Headers */,
3D80D9491DF6FA890028D040 /* RCTURLRequestHandler.h in Copy Headers */,
3D80D94A1DF6FA890028D040 /* RCTUtils.h in Copy Headers */,
- 3D80D94F1DF6FA890028D040 /* RCTJSCSamplingProfiler.h in Copy Headers */,
3D80D9501DF6FA890028D040 /* RCTAccessibilityManager.h in Copy Headers */,
3D80D9511DF6FA890028D040 /* RCTAlertManager.h in Copy Headers */,
3D80D9521DF6FA890028D040 /* RCTAppState.h in Copy Headers */,
@@ -1714,10 +1646,6 @@
3D80D9761DF6FA890028D040 /* RCTModalHostView.h in Copy Headers */,
3D80D9771DF6FA890028D040 /* RCTModalHostViewController.h in Copy Headers */,
3D80D9781DF6FA890028D040 /* RCTModalHostViewManager.h in Copy Headers */,
- 3D80D9791DF6FA890028D040 /* RCTNavigator.h in Copy Headers */,
- 3D80D97A1DF6FA890028D040 /* RCTNavigatorManager.h in Copy Headers */,
- 3D80D97B1DF6FA890028D040 /* RCTNavItem.h in Copy Headers */,
- 3D80D97C1DF6FA890028D040 /* RCTNavItemManager.h in Copy Headers */,
3D80D97D1DF6FA890028D040 /* RCTPicker.h in Copy Headers */,
3D80D97E1DF6FA890028D040 /* RCTPickerManager.h in Copy Headers */,
3D80D97F1DF6FA890028D040 /* RCTPointerEvents.h in Copy Headers */,
@@ -1732,10 +1660,6 @@
3D80D98B1DF6FA890028D040 /* RCTSliderManager.h in Copy Headers */,
3D80D98C1DF6FA890028D040 /* RCTSwitch.h in Copy Headers */,
3D80D98D1DF6FA890028D040 /* RCTSwitchManager.h in Copy Headers */,
- 3D80D98E1DF6FA890028D040 /* RCTTabBar.h in Copy Headers */,
- 3D80D98F1DF6FA890028D040 /* RCTTabBarItem.h in Copy Headers */,
- 3D80D9901DF6FA890028D040 /* RCTTabBarItemManager.h in Copy Headers */,
- 3D80D9911DF6FA890028D040 /* RCTTabBarManager.h in Copy Headers */,
3D80D9921DF6FA890028D040 /* RCTTextDecorationLineType.h in Copy Headers */,
3D80D9931DF6FA890028D040 /* RCTView.h in Copy Headers */,
3D80D9951DF6FA890028D040 /* RCTViewManager.h in Copy Headers */,
@@ -1753,6 +1677,9 @@
dstPath = include/yoga;
dstSubfolderSpec = 16;
files = (
+ AC90464121C91DB8005B24B3 /* YGConfig.h in Copy Headers */,
+ AC6B69E621B146A500B2B68A /* YGValue.h in Copy Headers */,
+ AC8360D321B0263000FC46B9 /* YGMarker.h in Copy Headers */,
3DE4F8681DF85D8E00B9E5A0 /* YGEnums.h in Copy Headers */,
3DE4F8691DF85D8E00B9E5A0 /* YGMacros.h in Copy Headers */,
3DE4F86A1DF85D8E00B9E5A0 /* Yoga.h in Copy Headers */,
@@ -1776,13 +1703,6 @@
3DA981A71E5B0E34004F2374 /* JsArgumentHelpers.h in Copy Headers */,
3DA981A81E5B0E34004F2374 /* JSBigString.h in Copy Headers */,
3DA981A91E5B0E34004F2374 /* JSBundleType.h in Copy Headers */,
- 3DA981AA1E5B0E34004F2374 /* JSCExecutor.h in Copy Headers */,
- 3DA981AC1E5B0E34004F2374 /* JSCLegacyTracing.h in Copy Headers */,
- 3DA981AD1E5B0E34004F2374 /* JSCMemory.h in Copy Headers */,
- 3DA981AE1E5B0E34004F2374 /* JSCNativeModules.h in Copy Headers */,
- 3DA981AF1E5B0E34004F2374 /* JSCPerfStats.h in Copy Headers */,
- 3DA981B01E5B0E34004F2374 /* JSCSamplingProfiler.h in Copy Headers */,
- 3DA981B11E5B0E34004F2374 /* JSCUtils.h in Copy Headers */,
3DA981B31E5B0E34004F2374 /* JSIndexedRAMBundle.h in Copy Headers */,
3DA981B41E5B0E34004F2374 /* JSModulesUnbundle.h in Copy Headers */,
3DA981B51E5B0E34004F2374 /* MessageQueueThread.h in Copy Headers */,
@@ -1790,7 +1710,6 @@
3DA981B71E5B0E34004F2374 /* ModuleRegistry.h in Copy Headers */,
3DA981B81E5B0E34004F2374 /* NativeModule.h in Copy Headers */,
3DA981B91E5B0E34004F2374 /* NativeToJsBridge.h in Copy Headers */,
- 3DA981BB1E5B0E34004F2374 /* Platform.h in Copy Headers */,
3DA981BC1E5B0E34004F2374 /* RecoverableError.h in Copy Headers */,
3DA981BD1E5B0E34004F2374 /* SampleCxxModule.h in Copy Headers */,
3DA981BE1E5B0E34004F2374 /* SystraceSection.h in Copy Headers */,
@@ -1798,62 +1717,78 @@
name = "Copy Headers";
runOnlyForDeploymentPostprocessing = 0;
};
- 3D80DABB1DF8218B0028D040 /* Copy Headers */ = {
+ EBF21BCB1FC498900052F4D5 /* Copy Headers */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
- dstPath = include/jschelpers;
+ dstPath = include/jsinspector;
dstSubfolderSpec = 16;
files = (
- 3DA9825A1E5B1079004F2374 /* JavaScriptCore.h in Copy Headers */,
- 3DA9825B1E5B1079004F2374 /* JSCHelpers.h in Copy Headers */,
- 3DA9825C1E5B1079004F2374 /* JSCWrapper.h in Copy Headers */,
- 3DA9825D1E5B1079004F2374 /* noncopyable.h in Copy Headers */,
- 3DA9825E1E5B1079004F2374 /* Unicode.h in Copy Headers */,
- 3DA9825F1E5B1079004F2374 /* Value.h in Copy Headers */,
+ EBF21BFB1FC498FC0052F4D5 /* InspectorInterfaces.h in Copy Headers */,
);
name = "Copy Headers";
runOnlyForDeploymentPostprocessing = 0;
};
- 9936F3021F5F2E4B0010BF04 /* Copy Headers */ = {
+ EBF21BE91FC4989A0052F4D5 /* Copy Headers */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
- dstPath = include/privatedata;
+ dstPath = include/jsinspector;
dstSubfolderSpec = 16;
files = (
- 9936F33D1F5F2FF40010BF04 /* PrivateDataBase.h in Copy Headers */,
+ EBF21BFE1FC499840052F4D5 /* InspectorInterfaces.h in Copy Headers */,
);
name = "Copy Headers";
runOnlyForDeploymentPostprocessing = 0;
};
- 9936F31E1F5F2E5B0010BF04 /* Copy Headers */ = {
+ ED296FA4214C9A0900B7C4FE /* Copy Headers */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
- dstPath = include/privatedata;
+ dstPath = include/jsi;
dstSubfolderSpec = 16;
files = (
- 9936F33A1F5F2F7C0010BF04 /* PrivateDataBase.h in Copy Headers */,
+ ED29704F2150199F00B7C4FE /* JSCRuntime.h in Copy Headers */,
+ ED296FC8214C9B5200B7C4FE /* jsi.h in Copy Headers */,
+ ED296FC7214C9B4B00B7C4FE /* instrumentation.h in Copy Headers */,
+ ED296FC6214C9B4400B7C4FE /* JSIDynamic.h in Copy Headers */,
+ ED296FC5214C9B3E00B7C4FE /* jsi-inl.h in Copy Headers */,
);
name = "Copy Headers";
runOnlyForDeploymentPostprocessing = 0;
};
- EBF21BCB1FC498900052F4D5 /* Copy Headers */ = {
+ ED296FDC214C9CF800B7C4FE /* Copy Headers */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
- dstPath = include/jsinspector;
+ dstPath = include/jsireact;
dstSubfolderSpec = 16;
files = (
- EBF21BFB1FC498FC0052F4D5 /* InspectorInterfaces.h in Copy Headers */,
+ ED7286BE2155C62B00C26ABF /* JSIExecutor.h in Copy Headers */,
+ ED7286BF2155C62B00C26ABF /* JSINativeModules.h in Copy Headers */,
);
name = "Copy Headers";
runOnlyForDeploymentPostprocessing = 0;
};
- EBF21BE91FC4989A0052F4D5 /* Copy Headers */ = {
+ EDEBC6C6214B3E7000DD5AC8 /* Copy Headers */ = {
isa = PBXCopyFilesBuildPhase;
- buildActionMask = 2147483647;
- dstPath = include/jsinspector;
+ buildActionMask = 12;
+ dstPath = include/jsi;
dstSubfolderSpec = 16;
files = (
- EBF21BFE1FC499840052F4D5 /* InspectorInterfaces.h in Copy Headers */,
+ ED297050215019B400B7C4FE /* instrumentation.h in Copy Headers */,
+ EDEBC71C214B40F900DD5AC8 /* jsi-inl.h in Copy Headers */,
+ EDEBC71D214B40F900DD5AC8 /* JSIDynamic.h in Copy Headers */,
+ EDEBC71E214B40F900DD5AC8 /* JSCRuntime.h in Copy Headers */,
+ EDEBC71F214B40F900DD5AC8 /* jsi.h in Copy Headers */,
+ );
+ name = "Copy Headers";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ EDEBC72F214B45A300DD5AC8 /* Copy Headers */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 12;
+ dstPath = include/jsireact;
+ dstSubfolderSpec = 16;
+ files = (
+ ED7286BC2155C62000C26ABF /* JSIExecutor.h in Copy Headers */,
+ ED7286BD2155C62000C26ABF /* JSINativeModules.h in Copy Headers */,
);
name = "Copy Headers";
runOnlyForDeploymentPostprocessing = 0;
@@ -1906,22 +1841,10 @@
134D63C21F1FEC4B008872B5 /* RCTCxxBridgeDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTCxxBridgeDelegate.h; sourceTree = "<group>"; };
13513F3A1B1F43F400FCE529 /* RCTProgressViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTProgressViewManager.h; sourceTree = "<group>"; };
13513F3B1B1F43F400FCE529 /* RCTProgressViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTProgressViewManager.m; sourceTree = "<group>"; };
- 135A9BF91E7B0EAE00587AEB /* RCTJSCErrorHandling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTJSCErrorHandling.h; sourceTree = "<group>"; };
- 135A9BFA1E7B0EAE00587AEB /* RCTJSCErrorHandling.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RCTJSCErrorHandling.mm; sourceTree = "<group>"; };
- 135A9BFD1E7B0EE600587AEB /* RCTJSCHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTJSCHelpers.h; sourceTree = "<group>"; };
- 135A9BFE1E7B0EE600587AEB /* RCTJSCHelpers.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RCTJSCHelpers.mm; sourceTree = "<group>"; };
13723B4E1A82FD3C00F88898 /* RCTStatusBarManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTStatusBarManager.h; sourceTree = "<group>"; };
13723B4F1A82FD3C00F88898 /* RCTStatusBarManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTStatusBarManager.m; sourceTree = "<group>"; };
1372B7081AB030C200659ED6 /* RCTAppState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAppState.h; sourceTree = "<group>"; };
1372B7091AB030C200659ED6 /* RCTAppState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAppState.m; sourceTree = "<group>"; };
- 137327DF1AA5CF210034F82E /* RCTTabBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTabBar.h; sourceTree = "<group>"; };
- 137327E01AA5CF210034F82E /* RCTTabBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTabBar.m; sourceTree = "<group>"; };
- 137327E11AA5CF210034F82E /* RCTTabBarItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTabBarItem.h; sourceTree = "<group>"; };
- 137327E21AA5CF210034F82E /* RCTTabBarItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTabBarItem.m; sourceTree = "<group>"; };
- 137327E31AA5CF210034F82E /* RCTTabBarItemManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTabBarItemManager.h; sourceTree = "<group>"; };
- 137327E41AA5CF210034F82E /* RCTTabBarItemManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTabBarItemManager.m; sourceTree = "<group>"; };
- 137327E51AA5CF210034F82E /* RCTTabBarManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTabBarManager.h; sourceTree = "<group>"; };
- 137327E61AA5CF210034F82E /* RCTTabBarManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTabBarManager.m; sourceTree = "<group>"; };
1384E2061E806D4E00545659 /* RCTNativeModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTNativeModule.h; sourceTree = "<group>"; };
1384E2071E806D4E00545659 /* RCTNativeModule.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RCTNativeModule.mm; sourceTree = "<group>"; };
139D7E391E25C5A300323FB7 /* bignum-dtoa.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "bignum-dtoa.cc"; path = "../third-party/double-conversion-1.1.6/src/bignum-dtoa.cc"; sourceTree = SOURCE_ROOT; };
@@ -1961,21 +1884,19 @@
139D7F141E25DEC900323FB7 /* raw_logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = raw_logging.h; path = "../third-party/glog-0.3.5/src/glog/raw_logging.h"; sourceTree = SOURCE_ROOT; };
139D7F161E25DEC900323FB7 /* stl_logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stl_logging.h; path = "../third-party/glog-0.3.5/src/glog/stl_logging.h"; sourceTree = SOURCE_ROOT; };
139D7F181E25DEC900323FB7 /* vlog_is_on.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = vlog_is_on.h; path = "../third-party/glog-0.3.5/src/glog/vlog_is_on.h"; sourceTree = SOURCE_ROOT; };
- 139D849C1E273B5600323FB7 /* AtomicIntrusiveLinkedList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AtomicIntrusiveLinkedList.h; path = "../third-party/folly-2016.10.31.00/folly/AtomicIntrusiveLinkedList.h"; sourceTree = SOURCE_ROOT; };
- 139D849D1E273B5600323FB7 /* Bits.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Bits.cpp; path = "../third-party/folly-2016.10.31.00/folly/Bits.cpp"; sourceTree = SOURCE_ROOT; };
- 139D849E1E273B5600323FB7 /* Bits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Bits.h; path = "../third-party/folly-2016.10.31.00/folly/Bits.h"; sourceTree = SOURCE_ROOT; };
- 139D849F1E273B5600323FB7 /* Conv.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Conv.cpp; path = "../third-party/folly-2016.10.31.00/folly/Conv.cpp"; sourceTree = SOURCE_ROOT; };
- 139D84A01E273B5600323FB7 /* Conv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Conv.h; path = "../third-party/folly-2016.10.31.00/folly/Conv.h"; sourceTree = SOURCE_ROOT; };
- 139D84A11E273B5600323FB7 /* dynamic-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "dynamic-inl.h"; path = "../third-party/folly-2016.10.31.00/folly/dynamic-inl.h"; sourceTree = SOURCE_ROOT; };
- 139D84A21E273B5600323FB7 /* dynamic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dynamic.cpp; path = "../third-party/folly-2016.10.31.00/folly/dynamic.cpp"; sourceTree = SOURCE_ROOT; };
- 139D84A31E273B5600323FB7 /* dynamic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dynamic.h; path = "../third-party/folly-2016.10.31.00/folly/dynamic.h"; sourceTree = SOURCE_ROOT; };
- 139D84A41E273B5600323FB7 /* Exception.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Exception.h; path = "../third-party/folly-2016.10.31.00/folly/Exception.h"; sourceTree = SOURCE_ROOT; };
- 139D84A71E273B5600323FB7 /* json.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = json.cpp; path = "../third-party/folly-2016.10.31.00/folly/json.cpp"; sourceTree = SOURCE_ROOT; };
- 139D84A81E273B5600323FB7 /* json.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = json.h; path = "../third-party/folly-2016.10.31.00/folly/json.h"; sourceTree = SOURCE_ROOT; };
- 139D84A91E273B5600323FB7 /* Memory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Memory.h; path = "../third-party/folly-2016.10.31.00/folly/Memory.h"; sourceTree = SOURCE_ROOT; };
- 139D84AA1E273B5600323FB7 /* MoveWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MoveWrapper.h; path = "../third-party/folly-2016.10.31.00/folly/MoveWrapper.h"; sourceTree = SOURCE_ROOT; };
- 139D84AB1E273B5600323FB7 /* Optional.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Optional.h; path = "../third-party/folly-2016.10.31.00/folly/Optional.h"; sourceTree = SOURCE_ROOT; };
- 139D84AC1E273B5600323FB7 /* ScopeGuard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScopeGuard.h; path = "../third-party/folly-2016.10.31.00/folly/ScopeGuard.h"; sourceTree = SOURCE_ROOT; };
+ 139D849C1E273B5600323FB7 /* AtomicIntrusiveLinkedList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AtomicIntrusiveLinkedList.h; path = "../third-party/folly-2018.10.22.00/folly/AtomicIntrusiveLinkedList.h"; sourceTree = SOURCE_ROOT; };
+ 139D849F1E273B5600323FB7 /* Conv.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Conv.cpp; path = "../third-party/folly-2018.10.22.00/folly/Conv.cpp"; sourceTree = SOURCE_ROOT; };
+ 139D84A01E273B5600323FB7 /* Conv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Conv.h; path = "../third-party/folly-2018.10.22.00/folly/Conv.h"; sourceTree = SOURCE_ROOT; };
+ 139D84A11E273B5600323FB7 /* dynamic-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "dynamic-inl.h"; path = "../third-party/folly-2018.10.22.00/folly/dynamic-inl.h"; sourceTree = SOURCE_ROOT; };
+ 139D84A21E273B5600323FB7 /* dynamic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dynamic.cpp; path = "../third-party/folly-2018.10.22.00/folly/dynamic.cpp"; sourceTree = SOURCE_ROOT; };
+ 139D84A31E273B5600323FB7 /* dynamic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dynamic.h; path = "../third-party/folly-2018.10.22.00/folly/dynamic.h"; sourceTree = SOURCE_ROOT; };
+ 139D84A41E273B5600323FB7 /* Exception.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Exception.h; path = "../third-party/folly-2018.10.22.00/folly/Exception.h"; sourceTree = SOURCE_ROOT; };
+ 139D84A71E273B5600323FB7 /* json.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = json.cpp; path = "../third-party/folly-2018.10.22.00/folly/json.cpp"; sourceTree = SOURCE_ROOT; };
+ 139D84A81E273B5600323FB7 /* json.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = json.h; path = "../third-party/folly-2018.10.22.00/folly/json.h"; sourceTree = SOURCE_ROOT; };
+ 139D84A91E273B5600323FB7 /* Memory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Memory.h; path = "../third-party/folly-2018.10.22.00/folly/Memory.h"; sourceTree = SOURCE_ROOT; };
+ 139D84AA1E273B5600323FB7 /* MoveWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MoveWrapper.h; path = "../third-party/folly-2018.10.22.00/folly/MoveWrapper.h"; sourceTree = SOURCE_ROOT; };
+ 139D84AB1E273B5600323FB7 /* Optional.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Optional.h; path = "../third-party/folly-2018.10.22.00/folly/Optional.h"; sourceTree = SOURCE_ROOT; };
+ 139D84AC1E273B5600323FB7 /* ScopeGuard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScopeGuard.h; path = "../third-party/folly-2018.10.22.00/folly/ScopeGuard.h"; sourceTree = SOURCE_ROOT; };
13A0C2851B74F71200B29F6F /* RCTDevLoadingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTDevLoadingView.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
13A0C2861B74F71200B29F6F /* RCTDevLoadingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDevLoadingView.m; sourceTree = "<group>"; };
13A0C2871B74F71200B29F6F /* RCTDevMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTDevMenu.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
@@ -1998,14 +1919,6 @@
13B07FEA1A69327A00A75B9A /* RCTExceptionsManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTExceptionsManager.m; sourceTree = "<group>"; };
13B07FED1A69327A00A75B9A /* RCTTiming.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTiming.h; sourceTree = "<group>"; };
13B07FEE1A69327A00A75B9A /* RCTTiming.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTiming.m; sourceTree = "<group>"; };
- 13B0800C1A69489C00A75B9A /* RCTNavigator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTNavigator.h; sourceTree = "<group>"; };
- 13B0800D1A69489C00A75B9A /* RCTNavigator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTNavigator.m; sourceTree = "<group>"; };
- 13B0800E1A69489C00A75B9A /* RCTNavigatorManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTNavigatorManager.h; sourceTree = "<group>"; };
- 13B0800F1A69489C00A75B9A /* RCTNavigatorManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTNavigatorManager.m; sourceTree = "<group>"; };
- 13B080101A69489C00A75B9A /* RCTNavItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTNavItem.h; sourceTree = "<group>"; };
- 13B080111A69489C00A75B9A /* RCTNavItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTNavItem.m; sourceTree = "<group>"; };
- 13B080121A69489C00A75B9A /* RCTNavItemManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTNavItemManager.h; sourceTree = "<group>"; };
- 13B080131A69489C00A75B9A /* RCTNavItemManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTNavItemManager.m; sourceTree = "<group>"; };
13B080181A69489C00A75B9A /* RCTActivityIndicatorViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTActivityIndicatorViewManager.h; sourceTree = "<group>"; };
13B080191A69489C00A75B9A /* RCTActivityIndicatorViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTActivityIndicatorViewManager.m; sourceTree = "<group>"; };
13B080231A694A8400A75B9A /* RCTWrapperViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWrapperViewController.h; sourceTree = "<group>"; };
@@ -2041,11 +1954,8 @@
13E067541A70F44B002CDEE1 /* UIView+React.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+React.m"; sourceTree = "<group>"; };
13F17A831B8493E5007D4C75 /* RCTRedBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRedBox.h; sourceTree = "<group>"; };
13F17A841B8493E5007D4C75 /* RCTRedBox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRedBox.m; sourceTree = "<group>"; };
- 13F887521E2971C500C3C7A1 /* Demangle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Demangle.cpp; path = "../third-party/folly-2016.10.31.00/folly/Demangle.cpp"; sourceTree = SOURCE_ROOT; };
- 13F887531E2971C500C3C7A1 /* StringBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StringBase.cpp; path = "../third-party/folly-2016.10.31.00/folly/StringBase.cpp"; sourceTree = SOURCE_ROOT; };
- 13F887541E2971C500C3C7A1 /* Unicode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Unicode.cpp; path = "../third-party/folly-2016.10.31.00/folly/Unicode.cpp"; sourceTree = SOURCE_ROOT; };
- 13F8879C1E29740700C3C7A1 /* BitsFunctexcept.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BitsFunctexcept.cpp; path = "../third-party/folly-2016.10.31.00/folly/portability/BitsFunctexcept.cpp"; sourceTree = SOURCE_ROOT; };
- 13F887A01E2977D800C3C7A1 /* MallocImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MallocImpl.cpp; path = "../third-party/folly-2016.10.31.00/folly/detail/MallocImpl.cpp"; sourceTree = SOURCE_ROOT; };
+ 13F887521E2971C500C3C7A1 /* Demangle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Demangle.cpp; path = "../third-party/folly-2018.10.22.00/folly/Demangle.cpp"; sourceTree = SOURCE_ROOT; };
+ 13F887541E2971C500C3C7A1 /* Unicode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Unicode.cpp; path = "../third-party/folly-2018.10.22.00/folly/Unicode.cpp"; sourceTree = SOURCE_ROOT; };
14200DA81AC179B3008EE6BA /* RCTJavaScriptLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTJavaScriptLoader.h; sourceTree = "<group>"; };
142014171B32094000CC17BA /* RCTPerformanceLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPerformanceLogger.m; sourceTree = "<group>"; };
142014181B32094000CC17BA /* RCTPerformanceLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPerformanceLogger.h; sourceTree = "<group>"; };
@@ -2077,13 +1987,10 @@
191E3EBF1C29DC3800C180A6 /* RCTRefreshControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRefreshControl.h; sourceTree = "<group>"; };
191E3EC01C29DC3800C180A6 /* RCTRefreshControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRefreshControl.m; sourceTree = "<group>"; };
199B8A6E1F44DB16005DEF67 /* RCTVersion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTVersion.h; sourceTree = "<group>"; };
- 19DED2281E77E29200F089BB /* systemJSCWrapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = systemJSCWrapper.cpp; sourceTree = "<group>"; };
27B958731E57587D0096647A /* JSBigString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSBigString.cpp; sourceTree = "<group>"; };
2D2A28131D9B038B00D4039D /* libReact.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libReact.a; sourceTree = BUILT_PRODUCTS_DIR; };
352DCFEE1D19F4C20056D623 /* RCTI18nUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTI18nUtil.h; sourceTree = "<group>"; };
352DCFEF1D19F4C20056D623 /* RCTI18nUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTI18nUtil.m; sourceTree = "<group>"; };
- 369123DF1DDC75850095B341 /* RCTJSCSamplingProfiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTJSCSamplingProfiler.h; sourceTree = "<group>"; };
- 369123E01DDC75850095B341 /* RCTJSCSamplingProfiler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTJSCSamplingProfiler.m; sourceTree = "<group>"; };
391E86A21C623EC800009732 /* RCTTouchEvent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTouchEvent.m; sourceTree = "<group>"; };
391E86A31C623EC800009732 /* RCTTouchEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTouchEvent.h; sourceTree = "<group>"; };
39C50FFA2046EE3500CEE534 /* RCTVersion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTVersion.m; sourceTree = "<group>"; };
@@ -2092,7 +1999,6 @@
3D0B842D1EC0B51200B2BD8E /* RCTTVNavigationEventEmitter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTVNavigationEventEmitter.h; sourceTree = "<group>"; };
3D0B842E1EC0B51200B2BD8E /* RCTTVNavigationEventEmitter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTVNavigationEventEmitter.m; sourceTree = "<group>"; };
3D0E37891F1CC40000DCAC9F /* RCTWebSocketModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RCTWebSocketModule.h; path = WebSocket/RCTWebSocketModule.h; sourceTree = "<group>"; };
- 3D0E378B1F1CC58C00DCAC9F /* RCTWebSocketObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RCTWebSocketObserver.h; path = WebSocket/RCTWebSocketObserver.h; sourceTree = "<group>"; };
3D1E68D81CABD13900DD7465 /* RCTDisplayLink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDisplayLink.h; sourceTree = "<group>"; };
3D1E68D91CABD13900DD7465 /* RCTDisplayLink.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDisplayLink.m; sourceTree = "<group>"; };
3D1FA07A1DE4F2EA00E03CC6 /* RCTNetworking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTNetworking.h; sourceTree = "<group>"; };
@@ -2109,8 +2015,6 @@
3D3C059A1DE3340900C268FA /* libyoga.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libyoga.a; sourceTree = BUILT_PRODUCTS_DIR; };
3D3C06751DE3340C00C268FA /* libyoga.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libyoga.a; sourceTree = BUILT_PRODUCTS_DIR; };
3D3CD8F51DE5FB2300167DC4 /* JSBundleType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSBundleType.h; sourceTree = "<group>"; };
- 3D3CD90B1DE5FBD600167DC4 /* libjschelpers.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjschelpers.a; sourceTree = BUILT_PRODUCTS_DIR; };
- 3D3CD9181DE5FBD800167DC4 /* libjschelpers.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjschelpers.a; sourceTree = BUILT_PRODUCTS_DIR; };
3D3CD9251DE5FBEC00167DC4 /* libcxxreact.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libcxxreact.a; sourceTree = BUILT_PRODUCTS_DIR; };
3D3CD9321DE5FBEE00167DC4 /* libcxxreact.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libcxxreact.a; sourceTree = BUILT_PRODUCTS_DIR; };
3D7454781E54757500E74ADD /* JSBigString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSBigString.h; sourceTree = "<group>"; };
@@ -2119,9 +2023,6 @@
3D7749421DC1065C007EC8D8 /* RCTPlatform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPlatform.h; sourceTree = "<group>"; };
3D7749431DC1065C007EC8D8 /* RCTPlatform.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPlatform.m; sourceTree = "<group>"; };
3D788F841EBD2D240063D616 /* third-party.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "third-party.xcconfig"; sourceTree = "<group>"; };
- 3D7A27DC1DE32541002E3F95 /* JavaScriptCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JavaScriptCore.h; sourceTree = "<group>"; };
- 3D7A27DD1DE32541002E3F95 /* JSCWrapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCWrapper.cpp; sourceTree = "<group>"; };
- 3D7A27DE1DE32541002E3F95 /* JSCWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCWrapper.h; sourceTree = "<group>"; };
3D7AA9C31E548CD5001955CF /* NSDataBigString.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = NSDataBigString.mm; sourceTree = "<group>"; };
3D7BFD0B1EA8E351008DFB7A /* RCTPackagerClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPackagerClient.h; sourceTree = "<group>"; };
3D7BFD0C1EA8E351008DFB7A /* RCTPackagerClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPackagerClient.m; sourceTree = "<group>"; };
@@ -2137,20 +2038,6 @@
3D92B0AF1E03699D0018521A /* Instance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Instance.h; sourceTree = "<group>"; };
3D92B0B01E03699D0018521A /* JsArgumentHelpers-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "JsArgumentHelpers-inl.h"; sourceTree = "<group>"; };
3D92B0B11E03699D0018521A /* JsArgumentHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JsArgumentHelpers.h; sourceTree = "<group>"; };
- 3D92B0B21E03699D0018521A /* JSCExecutor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCExecutor.cpp; sourceTree = "<group>"; };
- 3D92B0B31E03699D0018521A /* JSCExecutor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCExecutor.h; sourceTree = "<group>"; };
- 3D92B0B61E03699D0018521A /* JSCLegacyTracing.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCLegacyTracing.cpp; sourceTree = "<group>"; };
- 3D92B0B71E03699D0018521A /* JSCLegacyTracing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCLegacyTracing.h; sourceTree = "<group>"; };
- 3D92B0B81E03699D0018521A /* JSCMemory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCMemory.cpp; sourceTree = "<group>"; };
- 3D92B0B91E03699D0018521A /* JSCMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCMemory.h; sourceTree = "<group>"; };
- 3D92B0BA1E03699D0018521A /* JSCNativeModules.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCNativeModules.cpp; sourceTree = "<group>"; };
- 3D92B0BB1E03699D0018521A /* JSCNativeModules.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCNativeModules.h; sourceTree = "<group>"; };
- 3D92B0BC1E03699D0018521A /* JSCPerfStats.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCPerfStats.cpp; sourceTree = "<group>"; };
- 3D92B0BD1E03699D0018521A /* JSCPerfStats.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCPerfStats.h; sourceTree = "<group>"; };
- 3D92B0BE1E03699D0018521A /* JSCSamplingProfiler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCSamplingProfiler.cpp; sourceTree = "<group>"; };
- 3D92B0BF1E03699D0018521A /* JSCSamplingProfiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCSamplingProfiler.h; sourceTree = "<group>"; };
- 3D92B0C21E03699D0018521A /* JSCUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCUtils.cpp; sourceTree = "<group>"; };
- 3D92B0C31E03699D0018521A /* JSCUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCUtils.h; sourceTree = "<group>"; };
3D92B0C61E03699D0018521A /* JSIndexedRAMBundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSIndexedRAMBundle.cpp; sourceTree = "<group>"; };
3D92B0C71E03699D0018521A /* JSIndexedRAMBundle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSIndexedRAMBundle.h; sourceTree = "<group>"; };
3D92B0C81E03699D0018521A /* JSModulesUnbundle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSModulesUnbundle.h; sourceTree = "<group>"; };
@@ -2162,20 +2049,9 @@
3D92B0CE1E03699D0018521A /* NativeModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NativeModule.h; sourceTree = "<group>"; };
3D92B0CF1E03699D0018521A /* NativeToJsBridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NativeToJsBridge.cpp; sourceTree = "<group>"; };
3D92B0D01E03699D0018521A /* NativeToJsBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NativeToJsBridge.h; sourceTree = "<group>"; };
- 3D92B0D11E03699D0018521A /* Platform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Platform.cpp; sourceTree = "<group>"; };
- 3D92B0D21E03699D0018521A /* Platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Platform.h; sourceTree = "<group>"; };
3D92B0D31E03699D0018521A /* SampleCxxModule.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SampleCxxModule.cpp; sourceTree = "<group>"; };
3D92B0D41E03699D0018521A /* SampleCxxModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SampleCxxModule.h; sourceTree = "<group>"; };
3D92B0D51E03699D0018521A /* SystraceSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SystraceSection.h; sourceTree = "<group>"; };
- 3D92B1071E0369AD0018521A /* JSCHelpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCHelpers.cpp; sourceTree = "<group>"; };
- 3D92B1081E0369AD0018521A /* JSCHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCHelpers.h; sourceTree = "<group>"; };
- 3D92B1091E0369AD0018521A /* noncopyable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = noncopyable.h; sourceTree = "<group>"; };
- 3D92B10A1E0369AD0018521A /* Unicode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Unicode.cpp; sourceTree = "<group>"; };
- 3D92B10B1E0369AD0018521A /* Unicode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Unicode.h; sourceTree = "<group>"; };
- 3D92B10C1E0369AD0018521A /* Value.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Value.cpp; sourceTree = "<group>"; };
- 3D92B10D1E0369AD0018521A /* Value.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Value.h; sourceTree = "<group>"; };
- 3DF1BE801F26576400068F1A /* JSCTracing.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCTracing.cpp; sourceTree = "<group>"; };
- 3DF1BE811F26576400068F1A /* JSCTracing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCTracing.h; sourceTree = "<group>"; };
3EDCA8A21D3591E700450C31 /* RCTErrorCustomizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTErrorCustomizer.h; sourceTree = "<group>"; };
3EDCA8A31D3591E700450C31 /* RCTErrorInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTErrorInfo.h; sourceTree = "<group>"; };
3EDCA8A41D3591E700450C31 /* RCTErrorInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTErrorInfo.m; sourceTree = "<group>"; };
@@ -2196,7 +2072,6 @@
53CBF1861FB4FE80002CBB31 /* YGEnums.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGEnums.cpp; sourceTree = "<group>"; };
53CBF1871FB4FE80002CBB31 /* Yoga.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Yoga.cpp; sourceTree = "<group>"; };
53D123831FBF1D49001B8A10 /* libyoga.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libyoga.a; path = "../../../../../../../../../Library/Developer/Xcode/DerivedData/yoga-hdfifpwsinitsibujacpiefkjfdy/Build/Products/Debug/libyoga.a"; sourceTree = "<group>"; };
- 53DEF6E6205AE59B006A3890 /* YGFloatOptional.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGFloatOptional.cpp; sourceTree = "<group>"; };
53DEF6E7205AE59C006A3890 /* YGFloatOptional.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGFloatOptional.h; sourceTree = "<group>"; };
53EC85DE1FDEC75A0051B2B5 /* YGNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGNode.h; sourceTree = "<group>"; };
53EC85DF1FDEC75A0051B2B5 /* YGNode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGNode.cpp; sourceTree = "<group>"; };
@@ -2278,8 +2153,18 @@
830213F31A654E0800B993E6 /* RCTBridgeModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTBridgeModule.h; sourceTree = "<group>"; };
830A229C1A66C68A008503DA /* RCTRootView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRootView.h; sourceTree = "<group>"; };
830A229D1A66C68A008503DA /* RCTRootView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRootView.m; sourceTree = "<group>"; };
+ 83281383217EB70800574D55 /* MallocImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MallocImpl.cpp; path = folly/memory/detail/MallocImpl.cpp; sourceTree = "<group>"; };
+ 83281386217EB73400574D55 /* String.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = String.cpp; path = folly/String.cpp; sourceTree = "<group>"; };
+ 83281389217EB74C00574D55 /* json_pointer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = json_pointer.cpp; path = folly/json_pointer.cpp; sourceTree = "<group>"; };
+ 8328138C217EB75C00574D55 /* ColdClass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ColdClass.cpp; path = folly/lang/ColdClass.cpp; sourceTree = "<group>"; };
+ 8328138F217EB76B00574D55 /* Demangle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Demangle.cpp; path = folly/detail/Demangle.cpp; sourceTree = "<group>"; };
+ 83281392217EB77C00574D55 /* SpookyHashV2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SpookyHashV2.cpp; path = folly/hash/SpookyHashV2.cpp; sourceTree = "<group>"; };
+ 83281395217EB78F00574D55 /* F14Table.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = F14Table.cpp; path = folly/container/detail/F14Table.cpp; sourceTree = "<group>"; };
+ 83281398217EB79D00574D55 /* ScopeGuard.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ScopeGuard.cpp; path = folly/ScopeGuard.cpp; sourceTree = "<group>"; };
83392EB11B6634E10013B15F /* RCTModalHostViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTModalHostViewController.h; sourceTree = "<group>"; };
83392EB21B6634E10013B15F /* RCTModalHostViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTModalHostViewController.m; sourceTree = "<group>"; };
+ 833D02B9217EBCFA00A23750 /* Assume.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Assume.cpp; path = folly/lang/Assume.cpp; sourceTree = "<group>"; };
+ 833D02BC217EBD2600A23750 /* Format.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Format.cpp; path = folly/Format.cpp; sourceTree = "<group>"; };
83A1FE8A1B62640A00BE0E65 /* RCTModalHostView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTModalHostView.h; sourceTree = "<group>"; };
83A1FE8B1B62640A00BE0E65 /* RCTModalHostView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTModalHostView.m; sourceTree = "<group>"; };
83A1FE8D1B62643A00BE0E65 /* RCTModalHostViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTModalHostViewManager.h; sourceTree = "<group>"; };
@@ -2302,16 +2187,20 @@
83CBBACA1A6023D300E9B192 /* RCTConvert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTConvert.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
83CBBACB1A6023D300E9B192 /* RCTConvert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTConvert.m; sourceTree = "<group>"; };
83F15A171B7CC46900F10295 /* UIView+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIView+Private.h"; sourceTree = "<group>"; };
+ 8507BBBC21EDACC200AEAFCA /* JSCExecutorFactory.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = JSCExecutorFactory.mm; sourceTree = "<group>"; };
+ 8507BBBD21EDACC200AEAFCA /* JSCExecutorFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCExecutorFactory.h; sourceTree = "<group>"; };
91076A871F743AB00081B4FA /* RCTModalManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCTModalManager.m; sourceTree = "<group>"; };
91076A881F743AB00081B4FA /* RCTModalManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTModalManager.h; sourceTree = "<group>"; };
- 9936F3131F5F2E4B0010BF04 /* libprivatedata.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libprivatedata.a; sourceTree = BUILT_PRODUCTS_DIR; };
- 9936F32F1F5F2E5B0010BF04 /* libprivatedata-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libprivatedata-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; };
- 9936F3351F5F2F480010BF04 /* PrivateDataBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PrivateDataBase.cpp; path = privatedata/PrivateDataBase.cpp; sourceTree = "<group>"; };
- 9936F3361F5F2F480010BF04 /* PrivateDataBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PrivateDataBase.h; path = privatedata/PrivateDataBase.h; sourceTree = "<group>"; };
A2440AA01DF8D854006E7BFC /* RCTReloadCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTReloadCommand.h; sourceTree = "<group>"; };
A2440AA11DF8D854006E7BFC /* RCTReloadCommand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTReloadCommand.m; sourceTree = "<group>"; };
+ AC4A6AF821FB4EA900FBEC39 /* YGMarker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGMarker.cpp; sourceTree = "<group>"; };
+ AC52CEDD21FB3FF9003C6BEC /* instrumentation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = instrumentation.h; sourceTree = "<group>"; };
+ AC6B69E121B1467C00B2B68A /* YGValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGValue.cpp; sourceTree = "<group>"; };
+ AC6B69E221B1467C00B2B68A /* YGValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGValue.h; sourceTree = "<group>"; };
AC70D2E81DE489E4002E6351 /* RCTJavaScriptLoader.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RCTJavaScriptLoader.mm; sourceTree = "<group>"; };
AC70D2EB1DE48A22002E6351 /* JSBundleType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSBundleType.cpp; sourceTree = "<group>"; };
+ AC8360CC21B0256A00FC46B9 /* YGMarker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGMarker.h; sourceTree = "<group>"; };
+ AC90463D21C91CC2005B24B3 /* CompactValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CompactValue.h; sourceTree = "<group>"; };
ACDD3FDA1BC7430D00E7DE33 /* RCTBorderStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBorderStyle.h; sourceTree = "<group>"; };
B233E6E81D2D843200BC68BA /* RCTI18nManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTI18nManager.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
B233E6E91D2D845D00BC68BA /* RCTI18nManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTI18nManager.m; sourceTree = "<group>"; };
@@ -2334,6 +2223,28 @@
EBF21BBB1FC498270052F4D5 /* InspectorInterfaces.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorInterfaces.cpp; sourceTree = "<group>"; };
EBF21BDC1FC498900052F4D5 /* libjsinspector.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjsinspector.a; sourceTree = BUILT_PRODUCTS_DIR; };
EBF21BFA1FC4989A0052F4D5 /* libjsinspector-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libjsinspector-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ ED296FB6214C9A0900B7C4FE /* libjsi-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libjsi-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ ED296FEE214C9CF800B7C4FE /* libjsiexecutor-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libjsiexecutor-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ ED6189672155BBF70000C9A7 /* JSIExecutor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSIExecutor.h; path = jsireact/JSIExecutor.h; sourceTree = "<group>"; };
+ ED6189682155BBF70000C9A7 /* JSINativeModules.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSINativeModules.h; path = jsireact/JSINativeModules.h; sourceTree = "<group>"; };
+ EDDA711B2164285A00B2D070 /* JSINativeModules.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JSINativeModules.cpp; path = jsireact/JSINativeModules.cpp; sourceTree = "<group>"; };
+ EDDA711C2164285A00B2D070 /* JSIExecutor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JSIExecutor.cpp; path = jsireact/JSIExecutor.cpp; sourceTree = "<group>"; };
+ EDEBC6D6214B3E7000DD5AC8 /* libjsi.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjsi.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ EDEBC6D9214B3F6800DD5AC8 /* jsi-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "jsi-inl.h"; sourceTree = "<group>"; };
+ EDEBC6DA214B3F6800DD5AC8 /* JSIDynamic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSIDynamic.cpp; sourceTree = "<group>"; };
+ EDEBC6DB214B3F6800DD5AC8 /* jsi.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = jsi.cpp; sourceTree = "<group>"; };
+ EDEBC6DC214B3F6800DD5AC8 /* JSIDynamic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSIDynamic.h; sourceTree = "<group>"; };
+ EDEBC6DD214B3F6800DD5AC8 /* JSCRuntime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCRuntime.cpp; sourceTree = "<group>"; };
+ EDEBC6DE214B3F6800DD5AC8 /* JSCRuntime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCRuntime.h; sourceTree = "<group>"; };
+ EDEBC6DF214B3F6800DD5AC8 /* BUCK */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BUCK; sourceTree = "<group>"; };
+ EDEBC6E0214B3F6800DD5AC8 /* instrumentation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = instrumentation.h; sourceTree = "<group>"; };
+ EDEBC6E1214B3F6800DD5AC8 /* jsi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsi.h; sourceTree = "<group>"; };
+ EDEBC73B214B45A300DD5AC8 /* libjsiexecutor.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjsiexecutor.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ EDEBC740214B463000DD5AC8 /* BUCK */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BUCK; sourceTree = "<group>"; };
+ EDEBC750214B47E100DD5AC8 /* JSDeltaBundleClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSDeltaBundleClient.cpp; sourceTree = "<group>"; };
+ EDEBC751214B47E100DD5AC8 /* JSDeltaBundleClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDeltaBundleClient.h; sourceTree = "<group>"; };
+ EDEBC752214B47E100DD5AC8 /* SharedProxyCxxModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SharedProxyCxxModule.h; sourceTree = "<group>"; };
+ EDEBC757214C284000DD5AC8 /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
F1EFDA4E201F660F00EE6E4C /* RCTUIUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTUIUtils.m; sourceTree = "<group>"; };
F1EFDA4F201F660F00EE6E4C /* RCTUIUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTUIUtils.h; sourceTree = "<group>"; };
FEFAAC9C1FDB89B40057BBE0 /* RCTRedBoxExtraDataViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRedBoxExtraDataViewController.m; sourceTree = "<group>"; };
@@ -2345,11 +2256,13 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ EDEBC7E0214C709200DD5AC8 /* libjsinspector.a in Frameworks */,
+ 3D3CD9411DE5FC5300167DC4 /* libcxxreact.a in Frameworks */,
+ EDEBC71A214B40A300DD5AC8 /* libjsi.a in Frameworks */,
+ EDEBC7DF214C705700DD5AC8 /* libjsiexecutor.a in Frameworks */,
53D123971FBF1DF5001B8A10 /* libyoga.a in Frameworks */,
3D383D6D1EBD2940005632C8 /* libdouble-conversion.a in Frameworks */,
- 3D383D6E1EBD2940005632C8 /* libjschelpers.a in Frameworks */,
3D383D6F1EBD2940005632C8 /* libthird-party.a in Frameworks */,
- 3D3CD9411DE5FC5300167DC4 /* libcxxreact.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2357,12 +2270,41 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ ED297067215023D800B7C4FE /* libjsiexecutor-tvOS.a in Frameworks */,
+ ED296FCB214C9B6C00B7C4FE /* libjsi-tvOS.a in Frameworks */,
+ ED296F83214C974A00B7C4FE /* libyoga.a in Frameworks */,
+ ED296F82214C973700B7C4FE /* libjsinspector-tvOS.a in Frameworks */,
2D1D83CE1F74E2DA00615550 /* libdouble-conversion.a in Frameworks */,
- 2D1D83CD1F74E2CE00615550 /* libprivatedata-tvOS.a in Frameworks */,
- 3D383D711EBD2949005632C8 /* libjschelpers.a in Frameworks */,
3D383D721EBD2949005632C8 /* libthird-party.a in Frameworks */,
3D8ED92C1E5B120100D83D20 /* libcxxreact.a in Frameworks */,
- 3D8ED92D1E5B120100D83D20 /* libyoga.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ ED296FCE214C9CB400B7C4FE /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ ED296FF5214C9E7C00B7C4FE /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ EDEBC756214C283300DD5AC8 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ EDEBC79A214C2A7000DD5AC8 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2381,9 +2323,14 @@
130A77021DF767AF001F9587 /* yoga */ = {
isa = PBXGroup;
children = (
+ AC4A6AF821FB4EA900FBEC39 /* YGMarker.cpp */,
+ AC52CEDD21FB3FF9003C6BEC /* instrumentation.h */,
+ AC90463D21C91CC2005B24B3 /* CompactValue.h */,
+ AC6B69E121B1467C00B2B68A /* YGValue.cpp */,
+ AC6B69E221B1467C00B2B68A /* YGValue.h */,
+ AC8360CC21B0256A00FC46B9 /* YGMarker.h */,
5CE2080020772F7C009A43B3 /* YGConfig.cpp */,
5CE2080120772F7C009A43B3 /* YGConfig.h */,
- 53DEF6E6205AE59B006A3890 /* YGFloatOptional.cpp */,
53DEF6E7205AE59C006A3890 /* YGFloatOptional.h */,
5343895E203905B6008E0CB3 /* YGLayout.cpp */,
5343895F203905B6008E0CB3 /* YGLayout.h */,
@@ -2413,12 +2360,12 @@
3D7454B31E54786200E74ADD /* NSDataBigString.h */,
3D7AA9C31E548CD5001955CF /* NSDataBigString.mm */,
13134C741E296B2A00B9F3CB /* RCTCxxBridge.mm */,
- 135A9BFD1E7B0EE600587AEB /* RCTJSCHelpers.h */,
- 135A9BFE1E7B0EE600587AEB /* RCTJSCHelpers.mm */,
13134C771E296B2A00B9F3CB /* RCTMessageThread.h */,
13134C781E296B2A00B9F3CB /* RCTMessageThread.mm */,
13134C7B1E296B2A00B9F3CB /* RCTObjcExecutor.h */,
13134C7C1E296B2A00B9F3CB /* RCTObjcExecutor.mm */,
+ 8507BBBD21EDACC200AEAFCA /* JSCExecutorFactory.h */,
+ 8507BBBC21EDACC200AEAFCA /* JSCExecutorFactory.mm */,
);
path = CxxBridge;
sourceTree = "<group>";
@@ -2500,29 +2447,34 @@
139D849B1E2739EC00323FB7 /* folly */ = {
isa = PBXGroup;
children = (
- 13F887A01E2977D800C3C7A1 /* MallocImpl.cpp */,
- 13F8879C1E29740700C3C7A1 /* BitsFunctexcept.cpp */,
- 13F887521E2971C500C3C7A1 /* Demangle.cpp */,
- 13F887531E2971C500C3C7A1 /* StringBase.cpp */,
- 13F887541E2971C500C3C7A1 /* Unicode.cpp */,
+ 833D02B9217EBCFA00A23750 /* Assume.cpp */,
139D849C1E273B5600323FB7 /* AtomicIntrusiveLinkedList.h */,
- 139D849D1E273B5600323FB7 /* Bits.cpp */,
- 139D849E1E273B5600323FB7 /* Bits.h */,
+ 8328138C217EB75C00574D55 /* ColdClass.cpp */,
139D849F1E273B5600323FB7 /* Conv.cpp */,
139D84A01E273B5600323FB7 /* Conv.h */,
+ 8328138F217EB76B00574D55 /* Demangle.cpp */,
+ 13F887521E2971C500C3C7A1 /* Demangle.cpp */,
139D84A11E273B5600323FB7 /* dynamic-inl.h */,
139D84A21E273B5600323FB7 /* dynamic.cpp */,
139D84A31E273B5600323FB7 /* dynamic.h */,
139D84A41E273B5600323FB7 /* Exception.h */,
+ 83281395217EB78F00574D55 /* F14Table.cpp */,
+ 833D02BC217EBD2600A23750 /* Format.cpp */,
+ 83281389217EB74C00574D55 /* json_pointer.cpp */,
139D84A71E273B5600323FB7 /* json.cpp */,
139D84A81E273B5600323FB7 /* json.h */,
+ 83281383217EB70800574D55 /* MallocImpl.cpp */,
139D84A91E273B5600323FB7 /* Memory.h */,
139D84AA1E273B5600323FB7 /* MoveWrapper.h */,
139D84AB1E273B5600323FB7 /* Optional.h */,
+ 83281398217EB79D00574D55 /* ScopeGuard.cpp */,
139D84AC1E273B5600323FB7 /* ScopeGuard.h */,
+ 83281392217EB77C00574D55 /* SpookyHashV2.cpp */,
+ 83281386217EB73400574D55 /* String.cpp */,
+ 13F887541E2971C500C3C7A1 /* Unicode.cpp */,
);
name = folly;
- path = "../third-party/folly-2016.10.31.00";
+ path = "../third-party/folly-2018.10.22.00";
sourceTree = "<group>";
};
13B07FE01A69315300A75B9A /* Modules */ = {
@@ -2550,8 +2502,6 @@
B233E6E91D2D845D00BC68BA /* RCTI18nManager.m */,
352DCFEE1D19F4C20056D623 /* RCTI18nUtil.h */,
352DCFEF1D19F4C20056D623 /* RCTI18nUtil.m */,
- 369123DF1DDC75850095B341 /* RCTJSCSamplingProfiler.h */,
- 369123E01DDC75850095B341 /* RCTJSCSamplingProfiler.m */,
13D9FEEC1CDCD93000158BD7 /* RCTKeyboardObserver.h */,
13D9FEED1CDCD93000158BD7 /* RCTKeyboardObserver.m */,
5960C1B11F0804A00066FD5B /* RCTLayoutAnimation.h */,
@@ -2623,14 +2573,6 @@
83A1FE8E1B62643A00BE0E65 /* RCTModalHostViewManager.m */,
91076A881F743AB00081B4FA /* RCTModalManager.h */,
91076A871F743AB00081B4FA /* RCTModalManager.m */,
- 13B0800C1A69489C00A75B9A /* RCTNavigator.h */,
- 13B0800D1A69489C00A75B9A /* RCTNavigator.m */,
- 13B0800E1A69489C00A75B9A /* RCTNavigatorManager.h */,
- 13B0800F1A69489C00A75B9A /* RCTNavigatorManager.m */,
- 13B080101A69489C00A75B9A /* RCTNavItem.h */,
- 13B080111A69489C00A75B9A /* RCTNavItem.m */,
- 13B080121A69489C00A75B9A /* RCTNavItemManager.h */,
- 13B080131A69489C00A75B9A /* RCTNavItemManager.m */,
58114A121AAE854800E7D092 /* RCTPicker.h */,
58114A131AAE854800E7D092 /* RCTPicker.m */,
58114A141AAE854800E7D092 /* RCTPickerManager.h */,
@@ -2662,14 +2604,6 @@
14F362081AABD06A001CE568 /* RCTSwitch.m */,
14F362091AABD06A001CE568 /* RCTSwitchManager.h */,
14F3620A1AABD06A001CE568 /* RCTSwitchManager.m */,
- 137327DF1AA5CF210034F82E /* RCTTabBar.h */,
- 137327E01AA5CF210034F82E /* RCTTabBar.m */,
- 137327E11AA5CF210034F82E /* RCTTabBarItem.h */,
- 137327E21AA5CF210034F82E /* RCTTabBarItem.m */,
- 137327E31AA5CF210034F82E /* RCTTabBarItemManager.h */,
- 137327E41AA5CF210034F82E /* RCTTabBarItemManager.m */,
- 137327E51AA5CF210034F82E /* RCTTabBarManager.h */,
- 137327E61AA5CF210034F82E /* RCTTabBarManager.m */,
E3BBC8EB1ADE6F47001BBD81 /* RCTTextDecorationLineType.h */,
130443D61E401AD800D93A67 /* RCTTVView.h */,
130443D71E401AD800D93A67 /* RCTTVView.m */,
@@ -2712,10 +2646,10 @@
3D10A3C71DDF3CED004A0F9D /* ReactCommon */ = {
isa = PBXGroup;
children = (
- 9936F3341F5F2F360010BF04 /* privatedata */,
+ EDEBC73C214B463000DD5AC8 /* jsiexecutor */,
+ EDEBC6D8214B3F6800DD5AC8 /* jsi */,
130A77021DF767AF001F9587 /* yoga */,
AC70D2EA1DE489FC002E6351 /* cxxreact */,
- 3D4A621D1DDD3985001F41B4 /* jschelpers */,
EBF21BB91FC497DA0052F4D5 /* jsinspector */,
);
name = ReactCommon;
@@ -2770,24 +2704,6 @@
name = PushNotificationIOS;
sourceTree = "<group>";
};
- 3D4A621D1DDD3985001F41B4 /* jschelpers */ = {
- isa = PBXGroup;
- children = (
- 19DED2281E77E29200F089BB /* systemJSCWrapper.cpp */,
- 3D7A27DC1DE32541002E3F95 /* JavaScriptCore.h */,
- 3D92B1071E0369AD0018521A /* JSCHelpers.cpp */,
- 3D92B1081E0369AD0018521A /* JSCHelpers.h */,
- 3D7A27DD1DE32541002E3F95 /* JSCWrapper.cpp */,
- 3D7A27DE1DE32541002E3F95 /* JSCWrapper.h */,
- 3D92B1091E0369AD0018521A /* noncopyable.h */,
- 3D92B10A1E0369AD0018521A /* Unicode.cpp */,
- 3D92B10B1E0369AD0018521A /* Unicode.h */,
- 3D92B10C1E0369AD0018521A /* Value.cpp */,
- 3D92B10D1E0369AD0018521A /* Value.h */,
- );
- path = jschelpers;
- sourceTree = "<group>";
- };
3D7BFD0A1EA8E2D1008DFB7A /* DevSupport */ = {
isa = PBXGroup;
children = (
@@ -2808,7 +2724,6 @@
3D7BFD2A1EA8E3D3008DFB7A /* WebSocket */ = {
isa = PBXGroup;
children = (
- 3D0E378B1F1CC58C00DCAC9F /* RCTWebSocketObserver.h */,
3D0E37891F1CC40000DCAC9F /* RCTWebSocketModule.h */,
3D7BFD2B1EA8E3FA008DFB7A /* RCTReconnectingWebSocket.h */,
3D7BFD2C1EA8E3FA008DFB7A /* RCTSRWebSocket.h */,
@@ -2829,6 +2744,7 @@
53D123821FBF1D49001B8A10 /* Frameworks */ = {
isa = PBXGroup;
children = (
+ EDEBC757214C284000DD5AC8 /* JavaScriptCore.framework */,
53D123831FBF1D49001B8A10 /* libyoga.a */,
);
name = Frameworks;
@@ -2933,18 +2849,18 @@
2D2A28131D9B038B00D4039D /* libReact.a */,
3D3C059A1DE3340900C268FA /* libyoga.a */,
3D3C06751DE3340C00C268FA /* libyoga.a */,
- 3D3CD90B1DE5FBD600167DC4 /* libjschelpers.a */,
- 3D3CD9181DE5FBD800167DC4 /* libjschelpers.a */,
3D3CD9251DE5FBEC00167DC4 /* libcxxreact.a */,
3D3CD9321DE5FBEE00167DC4 /* libcxxreact.a */,
139D7E881E25C6D100323FB7 /* libdouble-conversion.a */,
139D7ECE1E25DB7D00323FB7 /* libthird-party.a */,
3D383D3C1EBD27B6005632C8 /* libthird-party.a */,
3D383D621EBD27B9005632C8 /* libdouble-conversion.a */,
- 9936F3131F5F2E4B0010BF04 /* libprivatedata.a */,
- 9936F32F1F5F2E5B0010BF04 /* libprivatedata-tvOS.a */,
EBF21BDC1FC498900052F4D5 /* libjsinspector.a */,
EBF21BFA1FC4989A0052F4D5 /* libjsinspector-tvOS.a */,
+ EDEBC6D6214B3E7000DD5AC8 /* libjsi.a */,
+ EDEBC73B214B45A300DD5AC8 /* libjsiexecutor.a */,
+ ED296FB6214C9A0900B7C4FE /* libjsi-tvOS.a */,
+ ED296FEE214C9CF800B7C4FE /* libjsiexecutor-tvOS.a */,
);
name = Products;
sourceTree = "<group>";
@@ -2999,8 +2915,6 @@
83CBBA631A601ECA00E9B192 /* RCTJavaScriptExecutor.h */,
14200DA81AC179B3008EE6BA /* RCTJavaScriptLoader.h */,
AC70D2E81DE489E4002E6351 /* RCTJavaScriptLoader.mm */,
- 135A9BF91E7B0EAE00587AEB /* RCTJSCErrorHandling.h */,
- 135A9BFA1E7B0EAE00587AEB /* RCTJSCErrorHandling.mm */,
008341F51D1DB34400876D9A /* RCTJSStackFrame.h */,
008341F41D1DB34400876D9A /* RCTJSStackFrame.m */,
13A1F71C1A75392D00D3D453 /* RCTKeyCommands.h */,
@@ -3049,18 +2963,12 @@
path = Base;
sourceTree = "<group>";
};
- 9936F3341F5F2F360010BF04 /* privatedata */ = {
- isa = PBXGroup;
- children = (
- 9936F3351F5F2F480010BF04 /* PrivateDataBase.cpp */,
- 9936F3361F5F2F480010BF04 /* PrivateDataBase.h */,
- );
- name = privatedata;
- sourceTree = "<group>";
- };
AC70D2EA1DE489FC002E6351 /* cxxreact */ = {
isa = PBXGroup;
children = (
+ EDEBC750214B47E100DD5AC8 /* JSDeltaBundleClient.cpp */,
+ EDEBC751214B47E100DD5AC8 /* JSDeltaBundleClient.h */,
+ EDEBC752214B47E100DD5AC8 /* SharedProxyCxxModule.h */,
13DA8A302097A90B00276ED4 /* ReactMarker.cpp */,
13DA8A2F2097A90A00276ED4 /* ReactMarker.h */,
E223624320875A8000108244 /* JSExecutor.cpp */,
@@ -3075,22 +2983,6 @@
3D7454781E54757500E74ADD /* JSBigString.h */,
AC70D2EB1DE48A22002E6351 /* JSBundleType.cpp */,
3D3CD8F51DE5FB2300167DC4 /* JSBundleType.h */,
- 3D92B0B21E03699D0018521A /* JSCExecutor.cpp */,
- 3D92B0B31E03699D0018521A /* JSCExecutor.h */,
- 3D92B0B61E03699D0018521A /* JSCLegacyTracing.cpp */,
- 3D92B0B71E03699D0018521A /* JSCLegacyTracing.h */,
- 3D92B0B81E03699D0018521A /* JSCMemory.cpp */,
- 3D92B0B91E03699D0018521A /* JSCMemory.h */,
- 3D92B0BA1E03699D0018521A /* JSCNativeModules.cpp */,
- 3D92B0BB1E03699D0018521A /* JSCNativeModules.h */,
- 3D92B0BC1E03699D0018521A /* JSCPerfStats.cpp */,
- 3D92B0BD1E03699D0018521A /* JSCPerfStats.h */,
- 3D92B0BE1E03699D0018521A /* JSCSamplingProfiler.cpp */,
- 3D92B0BF1E03699D0018521A /* JSCSamplingProfiler.h */,
- 3DF1BE801F26576400068F1A /* JSCTracing.cpp */,
- 3DF1BE811F26576400068F1A /* JSCTracing.h */,
- 3D92B0C21E03699D0018521A /* JSCUtils.cpp */,
- 3D92B0C31E03699D0018521A /* JSCUtils.h */,
3D92B0AB1E03699D0018521A /* JSExecutor.h */,
3D92B0C61E03699D0018521A /* JSIndexedRAMBundle.cpp */,
3D92B0C71E03699D0018521A /* JSIndexedRAMBundle.h */,
@@ -3103,8 +2995,6 @@
3D92B0CE1E03699D0018521A /* NativeModule.h */,
3D92B0CF1E03699D0018521A /* NativeToJsBridge.cpp */,
3D92B0D01E03699D0018521A /* NativeToJsBridge.h */,
- 3D92B0D11E03699D0018521A /* Platform.cpp */,
- 3D92B0D21E03699D0018521A /* Platform.h */,
C6D380191F71D75B00621378 /* RAMBundleRegistry.cpp */,
C6D380181F71D75B00621378 /* RAMBundleRegistry.h */,
3D7454791E54757500E74ADD /* RecoverableError.h */,
@@ -3124,6 +3014,42 @@
path = jsinspector;
sourceTree = "<group>";
};
+ ED6189662155BBDD0000C9A7 /* jsireact */ = {
+ isa = PBXGroup;
+ children = (
+ EDDA711C2164285A00B2D070 /* JSIExecutor.cpp */,
+ EDDA711B2164285A00B2D070 /* JSINativeModules.cpp */,
+ ED6189672155BBF70000C9A7 /* JSIExecutor.h */,
+ ED6189682155BBF70000C9A7 /* JSINativeModules.h */,
+ );
+ name = jsireact;
+ sourceTree = "<group>";
+ };
+ EDEBC6D8214B3F6800DD5AC8 /* jsi */ = {
+ isa = PBXGroup;
+ children = (
+ EDEBC6D9214B3F6800DD5AC8 /* jsi-inl.h */,
+ EDEBC6DA214B3F6800DD5AC8 /* JSIDynamic.cpp */,
+ EDEBC6DB214B3F6800DD5AC8 /* jsi.cpp */,
+ EDEBC6DC214B3F6800DD5AC8 /* JSIDynamic.h */,
+ EDEBC6DD214B3F6800DD5AC8 /* JSCRuntime.cpp */,
+ EDEBC6DE214B3F6800DD5AC8 /* JSCRuntime.h */,
+ EDEBC6DF214B3F6800DD5AC8 /* BUCK */,
+ EDEBC6E0214B3F6800DD5AC8 /* instrumentation.h */,
+ EDEBC6E1214B3F6800DD5AC8 /* jsi.h */,
+ );
+ path = jsi;
+ sourceTree = "<group>";
+ };
+ EDEBC73C214B463000DD5AC8 /* jsiexecutor */ = {
+ isa = PBXGroup;
+ children = (
+ ED6189662155BBDD0000C9A7 /* jsireact */,
+ EDEBC740214B463000DD5AC8 /* BUCK */,
+ );
+ path = jsiexecutor;
+ sourceTree = "<group>";
+ };
F1EFDA4D201F660F00EE6E4C /* UIUtils */ = {
isa = PBXGroup;
children = (
@@ -3160,11 +3086,9 @@
3DA982391E5B0F8A004F2374 /* UIView+Private.h in Headers */,
13134C8D1E296B2A00B9F3CB /* RCTMessageThread.h in Headers */,
130443DE1E401B0D00D93A67 /* RCTTVView.h in Headers */,
- 598FD1941F8172A9006C54CB /* PrivateDataBase.h in Headers */,
3D7AA9C51E548CDB001955CF /* NSDataBigString.h in Headers */,
5960C1BA1F0804A00066FD5B /* RCTLayoutAnimationGroup.h in Headers */,
13134C991E296B2A00B9F3CB /* RCTCxxMethod.h in Headers */,
- 3D0E378D1F1CC58F00DCAC9F /* RCTWebSocketObserver.h in Headers */,
3D302F471DF828F800D6DDAE /* RCTPlatform.h in Headers */,
13134C951E296B2A00B9F3CB /* RCTObjcExecutor.h in Headers */,
590D7BFE1EBD458B00D8A370 /* RCTShadowView+Layout.h in Headers */,
@@ -3188,6 +3112,7 @@
3D302F2E1DF828F800D6DDAE /* RCTBridgeDelegate.h in Headers */,
3D302F2F1DF828F800D6DDAE /* RCTBridgeMethod.h in Headers */,
130E3D8A1E6A083600ACE484 /* RCTDevSettings.h in Headers */,
+ 8507BBC121EDACC200AEAFCA /* JSCExecutorFactory.h in Headers */,
3D0E378E1F1CC59100DCAC9F /* RCTWebSocketModule.h in Headers */,
3D302F301DF828F800D6DDAE /* RCTBridgeModule.h in Headers */,
3D302F311DF828F800D6DDAE /* RCTBundleURLProvider.h in Headers */,
@@ -3198,7 +3123,6 @@
3D302F351DF828F800D6DDAE /* RCTErrorCustomizer.h in Headers */,
3D302F361DF828F800D6DDAE /* RCTErrorInfo.h in Headers */,
3D302F371DF828F800D6DDAE /* RCTEventDispatcher.h in Headers */,
- 59EDBCAA1FDF4E0C003573DE /* (null) in Headers */,
594F0A371FD23228007FBE96 /* RCTSurfaceSizeMeasureMode.h in Headers */,
3D302F381DF828F800D6DDAE /* RCTFrameUpdate.h in Headers */,
3D302F391DF828F800D6DDAE /* RCTImageSource.h in Headers */,
@@ -3211,7 +3135,6 @@
599FAA491FB274980058CCF6 /* RCTSurfaceView+Internal.h in Headers */,
59EDBCB61FDF4E0C003573DE /* RCTScrollView.h in Headers */,
3D302F3E1DF828F800D6DDAE /* RCTKeyCommands.h in Headers */,
- 135A9C031E7B0F6100587AEB /* RCTJSCErrorHandling.h in Headers */,
599FAA411FB274980058CCF6 /* RCTSurfaceRootShadowViewDelegate.h in Headers */,
3D302F3F1DF828F800D6DDAE /* RCTLog.h in Headers */,
599FAA431FB274980058CCF6 /* RCTSurfaceRootView.h in Headers */,
@@ -3227,7 +3150,6 @@
3D302F481DF828F800D6DDAE /* RCTRootView.h in Headers */,
3D302F491DF828F800D6DDAE /* RCTRootViewDelegate.h in Headers */,
3D302F4A1DF828F800D6DDAE /* RCTRootViewInternal.h in Headers */,
- 59EDBCB21FDF4E0C003573DE /* (null) in Headers */,
3D302F4B1DF828F800D6DDAE /* RCTTouchEvent.h in Headers */,
591F78DD202ADB22004A668C /* RCTLayout.h in Headers */,
59D031F21F8353D3008361F0 /* RCTSafeAreaView.h in Headers */,
@@ -3237,7 +3159,6 @@
59500D441F71C63F00B122B7 /* RCTUIManagerUtils.h in Headers */,
3D302F4F1DF828F800D6DDAE /* RCTUtils.h in Headers */,
59D031FA1F8353D3008361F0 /* RCTSafeAreaViewManager.h in Headers */,
- 3D302F541DF828F800D6DDAE /* RCTJSCSamplingProfiler.h in Headers */,
3D302F551DF828F800D6DDAE /* RCTAccessibilityManager.h in Headers */,
3D302F561DF828F800D6DDAE /* RCTAlertManager.h in Headers */,
3D302F571DF828F800D6DDAE /* RCTAppState.h in Headers */,
@@ -3266,7 +3187,6 @@
3D302F661DF828F800D6DDAE /* RCTFPSGraph.h in Headers */,
3D302F681DF828F800D6DDAE /* RCTMacros.h in Headers */,
3D302F691DF828F800D6DDAE /* RCTProfile.h in Headers */,
- 3DF1BE841F26577000068F1A /* JSCTracing.h in Headers */,
3D302F6A1DF828F800D6DDAE /* RCTActivityIndicatorView.h in Headers */,
3D302F6B1DF828F800D6DDAE /* RCTActivityIndicatorViewManager.h in Headers */,
3D7BFD301EA8E3FA008DFB7A /* RCTSRWebSocket.h in Headers */,
@@ -3286,13 +3206,8 @@
3D302F7C1DF828F800D6DDAE /* RCTModalHostViewController.h in Headers */,
3D302F7D1DF828F800D6DDAE /* RCTModalHostViewManager.h in Headers */,
594F0A331FD23228007FBE96 /* RCTSurfaceHostingView.h in Headers */,
- 3D302F7E1DF828F800D6DDAE /* RCTNavigator.h in Headers */,
- 3D302F7F1DF828F800D6DDAE /* RCTNavigatorManager.h in Headers */,
130443DD1E401AF500D93A67 /* RCTConvert+Transform.h in Headers */,
134D63C41F1FEC65008872B5 /* RCTCxxBridgeDelegate.h in Headers */,
- 3D302F801DF828F800D6DDAE /* RCTNavItem.h in Headers */,
- 3D302F811DF828F800D6DDAE /* RCTNavItemManager.h in Headers */,
- 135A9C061E7B0F7800587AEB /* RCTJSCHelpers.h in Headers */,
3D302F841DF828F800D6DDAE /* RCTPointerEvents.h in Headers */,
59EB6DBC1EBD6FC90072A5E7 /* RCTUIManagerObserverCoordinator.h in Headers */,
657734941EE8356100A0E9EA /* RCTInspectorPackagerConnection.h in Headers */,
@@ -3314,11 +3229,7 @@
3D302F901DF828F800D6DDAE /* RCTSliderManager.h in Headers */,
3D302F911DF828F800D6DDAE /* RCTSwitch.h in Headers */,
3D302F921DF828F800D6DDAE /* RCTSwitchManager.h in Headers */,
- 3D302F931DF828F800D6DDAE /* RCTTabBar.h in Headers */,
- 3D302F941DF828F800D6DDAE /* RCTTabBarItem.h in Headers */,
- 3D302F951DF828F800D6DDAE /* RCTTabBarItemManager.h in Headers */,
59EDBCAE1FDF4E0C003573DE /* RCTScrollContentView.h in Headers */,
- 3D302F961DF828F800D6DDAE /* RCTTabBarManager.h in Headers */,
59E604A71FE9CCE300BD90C5 /* RCTScrollContentViewManager.h in Headers */,
3D302F971DF828F800D6DDAE /* RCTTextDecorationLineType.h in Headers */,
3D302F981DF828F800D6DDAE /* RCTView.h in Headers */,
@@ -3334,6 +3245,11 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
+ AC52CEE021FB403B003C6BEC /* instrumentation.h in Headers */,
+ AC90463F21C91D02005B24B3 /* CompactValue.h in Headers */,
+ AC6B69E821B146C500B2B68A /* YGValue.h in Headers */,
+ AC8360D221B025EF00FC46B9 /* YGConfig.h in Headers */,
+ AC8360CE21B0256A00FC46B9 /* YGMarker.h in Headers */,
5352C5782038FF9B00A3B97E /* YGStyle.h in Headers */,
53EC85E41FDEC7630051B2B5 /* YGNode.h in Headers */,
53D1239F1FBF1EFB001B8A10 /* Yoga-internal.h in Headers */,
@@ -3357,44 +3273,23 @@
27595AD51E575C7800CCE2B1 /* NativeToJsBridge.h in Headers */,
27595AC41E575C7800CCE2B1 /* Instance.h in Headers */,
27595AD11E575C7800CCE2B1 /* MessageQueueThread.h in Headers */,
- 27595ACE1E575C7800CCE2B1 /* JSCUtils.h in Headers */,
3D7454811E5475AF00E74ADD /* RecoverableError.h in Headers */,
27595AC51E575C7800CCE2B1 /* JsArgumentHelpers-inl.h in Headers */,
- 27595AC91E575C7800CCE2B1 /* JSCLegacyTracing.h in Headers */,
- 27595AD61E575C7800CCE2B1 /* Platform.h in Headers */,
27595AD81E575C7800CCE2B1 /* SystraceSection.h in Headers */,
27595AC61E575C7800CCE2B1 /* JsArgumentHelpers.h in Headers */,
27595AD71E575C7800CCE2B1 /* SampleCxxModule.h in Headers */,
27595AD21E575C7800CCE2B1 /* MethodCall.h in Headers */,
3D3030221DF8294C00D6DDAE /* JSBundleType.h in Headers */,
- 27595ACA1E575C7800CCE2B1 /* JSCMemory.h in Headers */,
3D74547D1E54758900E74ADD /* JSBigString.h in Headers */,
- 27595AC71E575C7800CCE2B1 /* JSCExecutor.h in Headers */,
- 27595ACD1E575C7800CCE2B1 /* JSCSamplingProfiler.h in Headers */,
27595ABF1E575C7800CCE2B1 /* CxxModule.h in Headers */,
27595AD41E575C7800CCE2B1 /* NativeModule.h in Headers */,
- 27595ACB1E575C7800CCE2B1 /* JSCNativeModules.h in Headers */,
27595AC01E575C7800CCE2B1 /* CxxNativeModule.h in Headers */,
27595AD01E575C7800CCE2B1 /* JSIndexedRAMBundle.h in Headers */,
27595AD31E575C7800CCE2B1 /* ModuleRegistry.h in Headers */,
- 27595ACC1E575C7800CCE2B1 /* JSCPerfStats.h in Headers */,
27595AC11E575C7800CCE2B1 /* JSExecutor.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
- 3D3030241DF8295800D6DDAE /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 19F61C041E8495FF00571D81 /* JSCHelpers.h in Headers */,
- 19F61C051E8495FF00571D81 /* noncopyable.h in Headers */,
- 19F61C061E8495FF00571D81 /* Unicode.h in Headers */,
- 19F61C071E8495FF00571D81 /* Value.h in Headers */,
- 3D3030251DF8295E00D6DDAE /* JavaScriptCore.h in Headers */,
- 3D3030261DF8295E00D6DDAE /* JSCWrapper.h in Headers */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
3D383D541EBD27B9005632C8 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
@@ -3416,6 +3311,11 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
+ AC52CEDF21FB401D003C6BEC /* instrumentation.h in Headers */,
+ AC90464021C91D14005B24B3 /* CompactValue.h in Headers */,
+ AC6B69E521B1469A00B2B68A /* YGValue.h in Headers */,
+ AC8360CF21B0258B00FC46B9 /* YGConfig.h in Headers */,
+ AC8360CD21B0256A00FC46B9 /* YGMarker.h in Headers */,
5352C5772038FF9A00A3B97E /* YGStyle.h in Headers */,
53EC85E51FDEC7630051B2B5 /* YGNode.h in Headers */,
53D1239E1FBF1EFB001B8A10 /* Yoga-internal.h in Headers */,
@@ -3429,19 +3329,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
- 3D3CD9001DE5FBD600167DC4 /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 13EBC6821E28733C00880AC5 /* Value.h in Headers */,
- 13EBC6811E28733C00880AC5 /* Unicode.h in Headers */,
- 13EBC6801E28733C00880AC5 /* noncopyable.h in Headers */,
- 13EBC67E1E28726000880AC5 /* JSCHelpers.h in Headers */,
- 3D3CD93D1DE5FC1400167DC4 /* JavaScriptCore.h in Headers */,
- 3D3CD93E1DE5FC1400167DC4 /* JSCWrapper.h in Headers */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
3D3CD91A1DE5FBEC00167DC4 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
@@ -3452,27 +3339,19 @@
27595ABA1E575C7800CCE2B1 /* NativeToJsBridge.h in Headers */,
27595AA91E575C7800CCE2B1 /* Instance.h in Headers */,
27595AB61E575C7800CCE2B1 /* MessageQueueThread.h in Headers */,
- 27595AB31E575C7800CCE2B1 /* JSCUtils.h in Headers */,
3D7454801E5475AF00E74ADD /* RecoverableError.h in Headers */,
27595AAA1E575C7800CCE2B1 /* JsArgumentHelpers-inl.h in Headers */,
- 27595AAE1E575C7800CCE2B1 /* JSCLegacyTracing.h in Headers */,
- 27595ABB1E575C7800CCE2B1 /* Platform.h in Headers */,
27595ABD1E575C7800CCE2B1 /* SystraceSection.h in Headers */,
27595AAB1E575C7800CCE2B1 /* JsArgumentHelpers.h in Headers */,
27595ABC1E575C7800CCE2B1 /* SampleCxxModule.h in Headers */,
27595AB71E575C7800CCE2B1 /* MethodCall.h in Headers */,
- 27595AAF1E575C7800CCE2B1 /* JSCMemory.h in Headers */,
3D74547C1E54758900E74ADD /* JSBigString.h in Headers */,
- 27595AAC1E575C7800CCE2B1 /* JSCExecutor.h in Headers */,
- 27595AB21E575C7800CCE2B1 /* JSCSamplingProfiler.h in Headers */,
27595AA41E575C7800CCE2B1 /* CxxModule.h in Headers */,
27595AB91E575C7800CCE2B1 /* NativeModule.h in Headers */,
- 27595AB01E575C7800CCE2B1 /* JSCNativeModules.h in Headers */,
3D3CD9451DE5FC7100167DC4 /* JSBundleType.h in Headers */,
27595AA51E575C7800CCE2B1 /* CxxNativeModule.h in Headers */,
27595AB51E575C7800CCE2B1 /* JSIndexedRAMBundle.h in Headers */,
27595AB81E575C7800CCE2B1 /* ModuleRegistry.h in Headers */,
- 27595AB11E575C7800CCE2B1 /* JSCPerfStats.h in Headers */,
27595AA61E575C7800CCE2B1 /* JSExecutor.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -3495,7 +3374,6 @@
3D80DA1F1DF820620028D040 /* RCTPushNotificationManager.h in Headers */,
3D80DA201DF820620028D040 /* RCTAssert.h in Headers */,
3D80DA211DF820620028D040 /* RCTBridge.h in Headers */,
- 13F880381E296D2800C3C7A1 /* JSCWrapper.h in Headers */,
3D80DA221DF820620028D040 /* RCTBridge+Private.h in Headers */,
599FAA461FB274980058CCF6 /* RCTSurfaceStage.h in Headers */,
599FAA361FB274980058CCF6 /* RCTSurface.h in Headers */,
@@ -3522,11 +3400,9 @@
3D80DA2F1DF820620028D040 /* RCTInvalidating.h in Headers */,
598FD1971F817336006C54CB /* RCTModalManager.h in Headers */,
599FAA3A1FB274980058CCF6 /* RCTSurfaceDelegate.h in Headers */,
- 9936F3381F5F2F480010BF04 /* PrivateDataBase.h in Headers */,
3D80DA301DF820620028D040 /* RCTJavaScriptExecutor.h in Headers */,
3DCE53281FEAB23100613583 /* RCTDatePicker.h in Headers */,
50E98FEB21460B0D00CD9289 /* RCTWKWebView.h in Headers */,
- 135A9BFF1E7B0EE600587AEB /* RCTJSCHelpers.h in Headers */,
3D80DA311DF820620028D040 /* RCTJavaScriptLoader.h in Headers */,
130E3D881E6A082100ACE484 /* RCTDevSettings.h in Headers */,
3D80DA321DF820620028D040 /* RCTJSStackFrame.h in Headers */,
@@ -3549,10 +3425,10 @@
3D80DA3D1DF820620028D040 /* RCTRootView.h in Headers */,
59EDBCB91FDF4E0C003573DE /* RCTScrollViewManager.h in Headers */,
59EDBCB51FDF4E0C003573DE /* RCTScrollView.h in Headers */,
- 135A9BFB1E7B0EAE00587AEB /* RCTJSCErrorHandling.h in Headers */,
3D80DA3E1DF820620028D040 /* RCTRootViewDelegate.h in Headers */,
3D80DA3F1DF820620028D040 /* RCTRootViewInternal.h in Headers */,
3D80DA401DF820620028D040 /* RCTTouchEvent.h in Headers */,
+ AC90463E21C91CC2005B24B3 /* CompactValue.h in Headers */,
3D80DA411DF820620028D040 /* RCTTouchHandler.h in Headers */,
59E604A61FE9CCE300BD90C5 /* RCTScrollContentViewManager.h in Headers */,
13134C8C1E296B2A00B9F3CB /* RCTMessageThread.h in Headers */,
@@ -3561,11 +3437,9 @@
3D80DA431DF820620028D040 /* RCTURLRequestHandler.h in Headers */,
3D80DA441DF820620028D040 /* RCTUtils.h in Headers */,
13134C981E296B2A00B9F3CB /* RCTCxxMethod.h in Headers */,
- 3D80DA491DF820620028D040 /* RCTJSCSamplingProfiler.h in Headers */,
3D80DA4A1DF820620028D040 /* RCTAccessibilityManager.h in Headers */,
3D80DA4B1DF820620028D040 /* RCTAlertManager.h in Headers */,
3D80DA4C1DF820620028D040 /* RCTAppState.h in Headers */,
- 3D0E378C1F1CC58C00DCAC9F /* RCTWebSocketObserver.h in Headers */,
3D80DA4D1DF820620028D040 /* RCTAsyncLocalStorage.h in Headers */,
3D80DA4E1DF820620028D040 /* RCTClipboard.h in Headers */,
3D80DA4F1DF820620028D040 /* RCTDevLoadingView.h in Headers */,
@@ -3579,8 +3453,10 @@
3D80DA541DF820620028D040 /* RCTI18nUtil.h in Headers */,
3D80DA551DF820620028D040 /* RCTKeyboardObserver.h in Headers */,
3D80DA561DF820620028D040 /* RCTRedBox.h in Headers */,
+ AC6B69E421B1467C00B2B68A /* YGValue.h in Headers */,
3D80DA571DF820620028D040 /* RCTSourceCode.h in Headers */,
EBF21BBC1FC498270052F4D5 /* InspectorInterfaces.h in Headers */,
+ AC52CEDE21FB3FF9003C6BEC /* instrumentation.h in Headers */,
3D80DA581DF820620028D040 /* RCTStatusBarManager.h in Headers */,
3D80DA591DF820620028D040 /* RCTTiming.h in Headers */,
3D80DA5A1DF820620028D040 /* RCTUIManager.h in Headers */,
@@ -3613,14 +3489,9 @@
3D80DA6B1DF820620028D040 /* RCTFont.h in Headers */,
3D80DA701DF820620028D040 /* RCTModalHostView.h in Headers */,
3D80DA711DF820620028D040 /* RCTModalHostViewController.h in Headers */,
- 3DF1BE831F26576400068F1A /* JSCTracing.h in Headers */,
3D80DA721DF820620028D040 /* RCTModalHostViewManager.h in Headers */,
13134C9C1E296B2A00B9F3CB /* RCTCxxModule.h in Headers */,
- 3D80DA731DF820620028D040 /* RCTNavigator.h in Headers */,
- 3D80DA741DF820620028D040 /* RCTNavigatorManager.h in Headers */,
594F0A321FD23228007FBE96 /* RCTSurfaceHostingView.h in Headers */,
- 3D80DA751DF820620028D040 /* RCTNavItem.h in Headers */,
- 3D80DA761DF820620028D040 /* RCTNavItemManager.h in Headers */,
3D80DA771DF820620028D040 /* RCTPicker.h in Headers */,
3D80DA781DF820620028D040 /* RCTPickerManager.h in Headers */,
3D80DA791DF820620028D040 /* RCTPointerEvents.h in Headers */,
@@ -3641,14 +3512,11 @@
3D80DA851DF820620028D040 /* RCTSliderManager.h in Headers */,
3D80DA861DF820620028D040 /* RCTSwitch.h in Headers */,
3D80DA871DF820620028D040 /* RCTSwitchManager.h in Headers */,
- 3D80DA881DF820620028D040 /* RCTTabBar.h in Headers */,
- 3D80DA891DF820620028D040 /* RCTTabBarItem.h in Headers */,
- 3D80DA8A1DF820620028D040 /* RCTTabBarItemManager.h in Headers */,
66CD94B51F1045E700CB3C7C /* RCTMaskedViewManager.h in Headers */,
- 3D80DA8B1DF820620028D040 /* RCTTabBarManager.h in Headers */,
3D80DA8C1DF820620028D040 /* RCTTextDecorationLineType.h in Headers */,
6577348E1EE8354A00A0E9EA /* RCTInspector.h in Headers */,
3D80DA8D1DF820620028D040 /* RCTView.h in Headers */,
+ 8507BBC021EDACC200AEAFCA /* JSCExecutorFactory.h in Headers */,
590D7BFD1EBD458B00D8A370 /* RCTShadowView+Layout.h in Headers */,
3D80DA8F1DF820620028D040 /* RCTViewManager.h in Headers */,
13134CA01E296B2A00B9F3CB /* RCTCxxUtils.h in Headers */,
@@ -3662,33 +3530,76 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
- 9936F2FB1F5F2E4B0010BF04 /* Headers */ = {
+ EBF21BC41FC498900052F4D5 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
- 9936F33C1F5F2FE70010BF04 /* PrivateDataBase.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
- 9936F3171F5F2E5B0010BF04 /* Headers */ = {
+ EBF21BE21FC4989A0052F4D5 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
- 9936F3391F5F2F5C0010BF04 /* PrivateDataBase.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
- EBF21BC41FC498900052F4D5 /* Headers */ = {
+ ED296F99214C9A0900B7C4FE /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
+ ED296FBC214C9B0400B7C4FE /* jsi-inl.h in Headers */,
+ ED296FBF214C9B0400B7C4FE /* JSIDynamic.h in Headers */,
+ ED296FC1214C9B0400B7C4FE /* JSCRuntime.h in Headers */,
+ ED296FC3214C9B0400B7C4FE /* instrumentation.h in Headers */,
+ ED296FC4214C9B0400B7C4FE /* jsi.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
- EBF21BE21FC4989A0052F4D5 /* Headers */ = {
+ ED296FD1214C9CF800B7C4FE /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
+ ED61896C2155BBF70000C9A7 /* JSINativeModules.h in Headers */,
+ ED61896A2155BBF70000C9A7 /* JSIExecutor.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ ED2970382150123E00B7C4FE /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ ED29703E2150126E00B7C4FE /* AtomicIntrusiveLinkedList.h in Headers */,
+ ED2970422150126E00B7C4FE /* Conv.h in Headers */,
+ ED2970432150126E00B7C4FE /* dynamic-inl.h in Headers */,
+ ED2970452150126E00B7C4FE /* dynamic.h in Headers */,
+ ED2970462150126E00B7C4FE /* Exception.h in Headers */,
+ ED2970482150126E00B7C4FE /* json.h in Headers */,
+ ED2970492150126E00B7C4FE /* Memory.h in Headers */,
+ ED29704A2150126E00B7C4FE /* MoveWrapper.h in Headers */,
+ ED29704B2150126E00B7C4FE /* Optional.h in Headers */,
+ ED29704C2150126E00B7C4FE /* ScopeGuard.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ EDEBC6BB214B3E7000DD5AC8 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ EDEBC6E9214B3F6800DD5AC8 /* jsi.h in Headers */,
+ EDEBC6E7214B3F6800DD5AC8 /* JSCRuntime.h in Headers */,
+ EDEBC6E5214B3F6800DD5AC8 /* JSIDynamic.h in Headers */,
+ EDEBC6E2214B3F6800DD5AC8 /* jsi-inl.h in Headers */,
+ EDEBC6E8214B3F6800DD5AC8 /* instrumentation.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ EDEBC729214B45A300DD5AC8 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ ED61896B2155BBF70000C9A7 /* JSINativeModules.h in Headers */,
+ ED6189692155BBF70000C9A7 /* JSIExecutor.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -3743,6 +3654,9 @@
buildRules = (
);
dependencies = (
+ ED2970662150237300B7C4FE /* PBXTargetDependency */,
+ ED296FCA214C9B6200B7C4FE /* PBXTargetDependency */,
+ ED296F81214C971800B7C4FE /* PBXTargetDependency */,
3D0574551DE5FF9600184BB4 /* PBXTargetDependency */,
3D0574571DE5FF9600184BB4 /* PBXTargetDependency */,
);
@@ -3756,6 +3670,7 @@
buildConfigurationList = 3D383D391EBD27B6005632C8 /* Build configuration list for PBXNativeTarget "third-party-tvOS" */;
buildPhases = (
3D383D241EBD27B6005632C8 /* Sources */,
+ ED2970382150123E00B7C4FE /* Headers */,
);
buildRules = (
);
@@ -3819,44 +3734,6 @@
productReference = 3D3C06751DE3340C00C268FA /* libyoga.a */;
productType = "com.apple.product-type.library.static";
};
- 3D3CD8FF1DE5FBD600167DC4 /* jschelpers */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 3D3CD9081DE5FBD600167DC4 /* Build configuration list for PBXNativeTarget "jschelpers" */;
- buildPhases = (
- 3D3CD9001DE5FBD600167DC4 /* Headers */,
- 3D80DABB1DF8218B0028D040 /* Copy Headers */,
- 3D3CD9051DE5FBD600167DC4 /* Sources */,
- );
- buildRules = (
- );
- dependencies = (
- 9936F3441F5F30780010BF04 /* PBXTargetDependency */,
- 1320081B1E283DC300F0C457 /* PBXTargetDependency */,
- );
- name = jschelpers;
- productName = React;
- productReference = 3D3CD90B1DE5FBD600167DC4 /* libjschelpers.a */;
- productType = "com.apple.product-type.library.static";
- };
- 3D3CD90C1DE5FBD800167DC4 /* jschelpers-tvOS */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 3D3CD9151DE5FBD800167DC4 /* Build configuration list for PBXNativeTarget "jschelpers-tvOS" */;
- buildPhases = (
- 3D3030241DF8295800D6DDAE /* Headers */,
- 3D302F1D1DF8264A00D6DDAE /* Copy Headers */,
- 3D3CD9121DE5FBD800167DC4 /* Sources */,
- );
- buildRules = (
- );
- dependencies = (
- 9936F3461F5F30830010BF04 /* PBXTargetDependency */,
- 3D383D641EBD27CE005632C8 /* PBXTargetDependency */,
- );
- name = "jschelpers-tvOS";
- productName = "React-tvOS";
- productReference = 3D3CD9181DE5FBD800167DC4 /* libjschelpers.a */;
- productType = "com.apple.product-type.library.static";
- };
3D3CD9191DE5FBEC00167DC4 /* cxxreact */ = {
isa = PBXNativeTarget;
buildConfigurationList = 3D3CD9221DE5FBEC00167DC4 /* Build configuration list for PBXNativeTarget "cxxreact" */;
@@ -3868,9 +3745,7 @@
buildRules = (
);
dependencies = (
- EBF21C021FC499D10052F4D5 /* PBXTargetDependency */,
- 9936F3401F5F305D0010BF04 /* PBXTargetDependency */,
- 3D3CD9501DE5FDB900167DC4 /* PBXTargetDependency */,
+ EDEBC7D7214C52FD00DD5AC8 /* PBXTargetDependency */,
);
name = cxxreact;
productName = React;
@@ -3888,9 +3763,7 @@
buildRules = (
);
dependencies = (
- EBF21C041FC499D80052F4D5 /* PBXTargetDependency */,
- 9936F3421F5F30640010BF04 /* PBXTargetDependency */,
- 3DC159E81E83E2A0007B1282 /* PBXTargetDependency */,
+ ED296F97214C996500B7C4FE /* PBXTargetDependency */,
);
name = "cxxreact-tvOS";
productName = "React-tvOS";
@@ -3911,6 +3784,9 @@
buildRules = (
);
dependencies = (
+ EDEBC74F214B477400DD5AC8 /* PBXTargetDependency */,
+ EDEBC7D9214C628300DD5AC8 /* PBXTargetDependency */,
+ EDEBC74B214B46A700DD5AC8 /* PBXTargetDependency */,
53D123991FBF1E0C001B8A10 /* PBXTargetDependency */,
3D3CD94C1DE5FCE700167DC4 /* PBXTargetDependency */,
);
@@ -3919,72 +3795,118 @@
productReference = 83CBBA2E1A601D0E00E9B192 /* libReact.a */;
productType = "com.apple.product-type.library.static";
};
- 9936F2F81F5F2E4B0010BF04 /* privatedata */ = {
+ EBF21BBF1FC498900052F4D5 /* jsinspector */ = {
isa = PBXNativeTarget;
- buildConfigurationList = 9936F3101F5F2E4B0010BF04 /* Build configuration list for PBXNativeTarget "privatedata" */;
+ buildConfigurationList = EBF21BD91FC498900052F4D5 /* Build configuration list for PBXNativeTarget "jsinspector" */;
buildPhases = (
- 9936F2FB1F5F2E4B0010BF04 /* Headers */,
- 9936F3021F5F2E4B0010BF04 /* Copy Headers */,
- 9936F30A1F5F2E4B0010BF04 /* Sources */,
+ EBF21BC41FC498900052F4D5 /* Headers */,
+ EBF21BCB1FC498900052F4D5 /* Copy Headers */,
+ EBF21BD31FC498900052F4D5 /* Sources */,
);
buildRules = (
);
dependencies = (
);
- name = privatedata;
+ name = jsinspector;
productName = React;
- productReference = 9936F3131F5F2E4B0010BF04 /* libprivatedata.a */;
+ productReference = EBF21BDC1FC498900052F4D5 /* libjsinspector.a */;
productType = "com.apple.product-type.library.static";
};
- 9936F3141F5F2E5B0010BF04 /* privatedata-tvOS */ = {
+ EBF21BDD1FC4989A0052F4D5 /* jsinspector-tvOS */ = {
isa = PBXNativeTarget;
- buildConfigurationList = 9936F32C1F5F2E5B0010BF04 /* Build configuration list for PBXNativeTarget "privatedata-tvOS" */;
+ buildConfigurationList = EBF21BF71FC4989A0052F4D5 /* Build configuration list for PBXNativeTarget "jsinspector-tvOS" */;
buildPhases = (
- 9936F3171F5F2E5B0010BF04 /* Headers */,
- 9936F31E1F5F2E5B0010BF04 /* Copy Headers */,
- 9936F3261F5F2E5B0010BF04 /* Sources */,
+ EBF21BE21FC4989A0052F4D5 /* Headers */,
+ EBF21BE91FC4989A0052F4D5 /* Copy Headers */,
+ EBF21BF11FC4989A0052F4D5 /* Sources */,
);
buildRules = (
);
dependencies = (
);
- name = "privatedata-tvOS";
+ name = "jsinspector-tvOS";
productName = "React-tvOS";
- productReference = 9936F32F1F5F2E5B0010BF04 /* libprivatedata-tvOS.a */;
+ productReference = EBF21BFA1FC4989A0052F4D5 /* libjsinspector-tvOS.a */;
productType = "com.apple.product-type.library.static";
};
- EBF21BBF1FC498900052F4D5 /* jsinspector */ = {
+ ED296F98214C9A0900B7C4FE /* jsi-tvOS */ = {
isa = PBXNativeTarget;
- buildConfigurationList = EBF21BD91FC498900052F4D5 /* Build configuration list for PBXNativeTarget "jsinspector" */;
+ buildConfigurationList = ED296FB3214C9A0900B7C4FE /* Build configuration list for PBXNativeTarget "jsi-tvOS" */;
buildPhases = (
- EBF21BC41FC498900052F4D5 /* Headers */,
- EBF21BCB1FC498900052F4D5 /* Copy Headers */,
- EBF21BD31FC498900052F4D5 /* Sources */,
+ ED296F99214C9A0900B7C4FE /* Headers */,
+ ED296FA4214C9A0900B7C4FE /* Copy Headers */,
+ ED296FA9214C9A0900B7C4FE /* Sources */,
+ ED296FCE214C9CB400B7C4FE /* Frameworks */,
);
buildRules = (
);
dependencies = (
+ ED29704E215012C700B7C4FE /* PBXTargetDependency */,
);
- name = jsinspector;
- productName = React;
- productReference = EBF21BDC1FC498900052F4D5 /* libjsinspector.a */;
+ name = "jsi-tvOS";
+ productName = "React-tvOS";
+ productReference = ED296FB6214C9A0900B7C4FE /* libjsi-tvOS.a */;
productType = "com.apple.product-type.library.static";
};
- EBF21BDD1FC4989A0052F4D5 /* jsinspector-tvOS */ = {
+ ED296FD0214C9CF800B7C4FE /* jsiexecutor-tvOS */ = {
isa = PBXNativeTarget;
- buildConfigurationList = EBF21BF71FC4989A0052F4D5 /* Build configuration list for PBXNativeTarget "jsinspector-tvOS" */;
+ buildConfigurationList = ED296FEB214C9CF800B7C4FE /* Build configuration list for PBXNativeTarget "jsiexecutor-tvOS" */;
buildPhases = (
- EBF21BE21FC4989A0052F4D5 /* Headers */,
- EBF21BE91FC4989A0052F4D5 /* Copy Headers */,
- EBF21BF11FC4989A0052F4D5 /* Sources */,
+ ED296FD1214C9CF800B7C4FE /* Headers */,
+ ED296FDC214C9CF800B7C4FE /* Copy Headers */,
+ ED296FE1214C9CF800B7C4FE /* Sources */,
+ ED296FF5214C9E7C00B7C4FE /* Frameworks */,
);
buildRules = (
);
dependencies = (
+ ED296FFE214C9EC600B7C4FE /* PBXTargetDependency */,
+ ED296FFC214C9EC000B7C4FE /* PBXTargetDependency */,
+ ED296FF8214C9EAA00B7C4FE /* PBXTargetDependency */,
);
- name = "jsinspector-tvOS";
+ name = "jsiexecutor-tvOS";
productName = "React-tvOS";
- productReference = EBF21BFA1FC4989A0052F4D5 /* libjsinspector-tvOS.a */;
+ productReference = ED296FEE214C9CF800B7C4FE /* libjsiexecutor-tvOS.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+ EDEBC6BA214B3E7000DD5AC8 /* jsi */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = EDEBC6D3214B3E7000DD5AC8 /* Build configuration list for PBXNativeTarget "jsi" */;
+ buildPhases = (
+ EDEBC6BB214B3E7000DD5AC8 /* Headers */,
+ EDEBC6C6214B3E7000DD5AC8 /* Copy Headers */,
+ EDEBC6CA214B3E7000DD5AC8 /* Sources */,
+ EDEBC756214C283300DD5AC8 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ EDEBC7CC214C516800DD5AC8 /* PBXTargetDependency */,
+ );
+ name = jsi;
+ productName = React;
+ productReference = EDEBC6D6214B3E7000DD5AC8 /* libjsi.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+ EDEBC724214B45A300DD5AC8 /* jsiexecutor */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = EDEBC738214B45A300DD5AC8 /* Build configuration list for PBXNativeTarget "jsiexecutor" */;
+ buildPhases = (
+ EDEBC729214B45A300DD5AC8 /* Headers */,
+ EDEBC72F214B45A300DD5AC8 /* Copy Headers */,
+ EDEBC734214B45A300DD5AC8 /* Sources */,
+ EDEBC79A214C2A7000DD5AC8 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ ED296F7E214C957300B7C4FE /* PBXTargetDependency */,
+ EDEBC7D3214C528C00DD5AC8 /* PBXTargetDependency */,
+ EDEBC7CE214C523F00DD5AC8 /* PBXTargetDependency */,
+ );
+ name = jsiexecutor;
+ productName = React;
+ productReference = EDEBC73B214B45A300DD5AC8 /* libjsiexecutor.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
@@ -4029,16 +3951,16 @@
3D3C059B1DE3340C00C268FA /* yoga-tvOS */,
3D3CD9191DE5FBEC00167DC4 /* cxxreact */,
3D3CD9261DE5FBEE00167DC4 /* cxxreact-tvOS */,
- 3D3CD8FF1DE5FBD600167DC4 /* jschelpers */,
- 3D3CD90C1DE5FBD800167DC4 /* jschelpers-tvOS */,
EBF21BBF1FC498900052F4D5 /* jsinspector */,
EBF21BDD1FC4989A0052F4D5 /* jsinspector-tvOS */,
139D7ECD1E25DB7D00323FB7 /* third-party */,
3D383D211EBD27B6005632C8 /* third-party-tvOS */,
139D7E871E25C6D100323FB7 /* double-conversion */,
3D383D3D1EBD27B9005632C8 /* double-conversion-tvOS */,
- 9936F2F81F5F2E4B0010BF04 /* privatedata */,
- 9936F3141F5F2E5B0010BF04 /* privatedata-tvOS */,
+ EDEBC6BA214B3E7000DD5AC8 /* jsi */,
+ EDEBC724214B45A300DD5AC8 /* jsiexecutor */,
+ ED296F98214C9A0900B7C4FE /* jsi-tvOS */,
+ ED296FD0214C9CF800B7C4FE /* jsiexecutor-tvOS */,
);
};
/* End PBXProject section */
@@ -4071,7 +3993,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "if [[ \"$CONFIGURATION\" == \"Debug\" ]] && [[ -d \"/tmp/RCTJSCProfiler\" ]]; then\n find \"${CONFIGURATION_BUILD_DIR}\" -name '*.app' | xargs -I{} sh -c 'cp -r /tmp/RCTJSCProfiler \"$1\"' -- {}\nfi";
+ shellScript = "if [[ \"$CONFIGURATION\" == \"Debug\" ]] && [[ -d \"/tmp/RCTJSCProfiler\" ]]; then\n find \"${CONFIGURATION_BUILD_DIR}\" -name '*.app' | xargs -I{} sh -c 'cp -r /tmp/RCTJSCProfiler \"$1\"' -- {}\nfi\n";
showEnvVarsInLog = 0;
};
190EE32F1E6A43DE00A8543A /* Install Third Party */ = {
@@ -4101,26 +4023,31 @@
"../third-party/glog-0.3.5/src/glog/raw_logging.h",
"../third-party/glog-0.3.5/src/glog/stl_logging.h",
"../third-party/glog-0.3.5/src/glog/vlog_is_on.h",
- "../third-party/folly-2016.10.31.00/folly/detail/MallocImpl.cpp",
- "../third-party/folly-2016.10.31.00/folly/portability/BitsFunctexcept.cpp",
- "../third-party/folly-2016.10.31.00/folly/Demangle.cpp",
- "../third-party/folly-2016.10.31.00/folly/StringBase.cpp",
- "../third-party/folly-2016.10.31.00/folly/Unicode.cpp",
- "../third-party/folly-2016.10.31.00/folly/AtomicIntrusiveLinkedList.h",
- "../third-party/folly-2016.10.31.00/folly/Bits.cpp",
- "../third-party/folly-2016.10.31.00/folly/Bits.h",
- "../third-party/folly-2016.10.31.00/folly/Conv.cpp",
- "../third-party/folly-2016.10.31.00/folly/Conv.h",
- "../third-party/folly-2016.10.31.00/folly/dynamic-inl.h",
- "../third-party/folly-2016.10.31.00/folly/dynamic.cpp",
- "../third-party/folly-2016.10.31.00/folly/dynamic.h",
- "../third-party/folly-2016.10.31.00/folly/Exception.h",
- "../third-party/folly-2016.10.31.00/folly/json.cpp",
- "../third-party/folly-2016.10.31.00/folly/json.h",
- "../third-party/folly-2016.10.31.00/folly/Memory.h",
- "../third-party/folly-2016.10.31.00/folly/MoveWrapper.h",
- "../third-party/folly-2016.10.31.00/folly/Optional.h",
- "../third-party/folly-2016.10.31.00/folly/ScopeGuard.h",
+ "../third-party/folly-2018.10.22.00/folly/memory/detail/MallocImpl.cpp",
+ "../third-party/folly-2018.10.22.00/folly/Demangle.cpp",
+ "../third-party/folly-2018.10.22.00/folly/Unicode.cpp",
+ "../third-party/folly-2018.10.22.00/folly/AtomicIntrusiveLinkedList.h",
+ "../third-party/folly-2018.10.22.00/folly/Conv.cpp",
+ "../third-party/folly-2018.10.22.00/folly/Conv.h",
+ "../third-party/folly-2018.10.22.00/folly/dynamic-inl.h",
+ "../third-party/folly-2018.10.22.00/folly/dynamic.cpp",
+ "../third-party/folly-2018.10.22.00/folly/dynamic.h",
+ "../third-party/folly-2018.10.22.00/folly/Exception.h",
+ "../third-party/folly-2018.10.22.00/folly/json.cpp",
+ "../third-party/folly-2018.10.22.00/folly/json.h",
+ "../third-party/folly-2018.10.22.00/folly/Memory.h",
+ "../third-party/folly-2018.10.22.00/folly/MoveWrapper.h",
+ "../third-party/folly-2018.10.22.00/folly/Optional.h",
+ "../third-party/folly-2018.10.22.00/folly/ScopeGuard.h",
+ "../third-party/folly-2018.10.22.00/folly/json_pointer.cpp",
+ "../third-party/folly-2018.10.22.00/folly/String.cpp",
+ "../third-party/folly-2018.10.22.00/folly/detail/Demangle.cpp",
+ "../third-party/folly-2018.10.22.00/folly/hash/SpookyHashV2.cpp",
+ "../third-party/folly-2018.10.22.00/folly/lang/ColdClass.cpp",
+ "../third-party/folly-2018.10.22.00/folly/container/detail/F14Table.cpp",
+ "../third-party/folly-2018.10.22.00/folly/ScopeGuard.cpp",
+ "../third-party/folly-2018.10.22.00/folly/lang/Assume.cpp",
+ "../third-party/folly-2018.10.22.00/folly/Format.cpp",
"../third-party/double-conversion-1.1.6/src/bignum-dtoa.cc",
"../third-party/double-conversion-1.1.6/src/bignum-dtoa.h",
"../third-party/double-conversion-1.1.6/src/bignum.cc",
@@ -4171,7 +4098,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "if [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\nif nc -w 5 -z localhost 8081 ; then\nif ! curl -s \"http://localhost:8081/status\" | grep -q \"packager-status:running\" ; then\necho \"Port 8081 already in use, packager is either not running or not running correctly\"\nexit 2\nfi\nelse\nopen \"$SRCROOT/../scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\nfi\nfi";
+ shellScript = "if [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\nif nc -w 5 -z localhost 8081 ; then\nif ! curl -s \"http://localhost:8081/status\" | grep -q \"packager-status:running\" ; then\necho \"Port 8081 already in use, packager is either not running or not running correctly\"\nexit 2\nfi\nelse\nopen \"$SRCROOT/../scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\nfi\nfi\n";
showEnvVarsInLog = 0;
};
3D383D3E1EBD27B9005632C8 /* Install Third Party */ = {
@@ -4211,21 +4138,27 @@
buildActionMask = 2147483647;
files = (
139D84B01E273B5600323FB7 /* Conv.cpp in Sources */,
- 13F887591E2971D400C3C7A1 /* StringBase.cpp in Sources */,
139D7F031E25DE1100323FB7 /* raw_logging.cc in Sources */,
+ 83281387217EB73400574D55 /* String.cpp in Sources */,
139D7F041E25DE1100323FB7 /* signalhandler.cc in Sources */,
+ 833D02BD217EBD2600A23750 /* Format.cpp in Sources */,
+ 83281390217EB76C00574D55 /* Demangle.cpp in Sources */,
+ 833D02BA217EBCFA00A23750 /* Assume.cpp in Sources */,
139D84B11E273B5600323FB7 /* dynamic.cpp in Sources */,
139D7F061E25DE1100323FB7 /* utilities.cc in Sources */,
- 13F887A21E2977FF00C3C7A1 /* MallocImpl.cpp in Sources */,
- 139D84AF1E273B5600323FB7 /* Bits.cpp in Sources */,
+ 8328138D217EB75C00574D55 /* ColdClass.cpp in Sources */,
139D7F051E25DE1100323FB7 /* symbolize.cc in Sources */,
139D7F071E25DE1100323FB7 /* vlog_is_on.cc in Sources */,
13F8875A1E2971D400C3C7A1 /* Unicode.cpp in Sources */,
139D7F091E25DE3700323FB7 /* demangle.cc in Sources */,
+ 83281399217EB79D00574D55 /* ScopeGuard.cpp in Sources */,
+ 83281393217EB77D00574D55 /* SpookyHashV2.cpp in Sources */,
13F887581E2971D400C3C7A1 /* Demangle.cpp in Sources */,
139D7F021E25DE1100323FB7 /* logging.cc in Sources */,
+ 83281396217EB79000574D55 /* F14Table.cpp in Sources */,
+ 83281384217EB70900574D55 /* MallocImpl.cpp in Sources */,
+ 8328138A217EB74C00574D55 /* json_pointer.cpp in Sources */,
139D84B31E273B5600323FB7 /* json.cpp in Sources */,
- 13F8879F1E29741900C3C7A1 /* BitsFunctexcept.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -4233,7 +4166,6 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 598FD1931F817284006C54CB /* PrivateDataBase.cpp in Sources */,
3DC159E41E83E1AE007B1282 /* RCTRootContentView.m in Sources */,
3D80D91B1DF6F8200028D040 /* RCTPlatform.m in Sources */,
2D0EB9F32021067800CAF88A /* RCTUIUtils.m in Sources */,
@@ -4242,7 +4174,6 @@
66CD94B81F1045E700CB3C7C /* RCTMaskedViewManager.m in Sources */,
2D3B5E991D9B089A00451313 /* RCTDisplayLink.m in Sources */,
2D3B5EA11D9B08B600451313 /* RCTModuleData.mm in Sources */,
- 2D3B5EEA1D9B09CD00451313 /* RCTTabBar.m in Sources */,
3DCE52F41FEAB10D00613583 /* RCTRedBoxExtraDataViewController.m in Sources */,
590D7C001EBD458B00D8A370 /* RCTShadowView+Layout.m in Sources */,
2D3B5EAE1D9B08F800451313 /* RCTEventEmitter.m in Sources */,
@@ -4280,17 +4211,13 @@
2D3B5EBA1D9B092100451313 /* RCTI18nUtil.m in Sources */,
2D3B5EB41D9B090A00451313 /* RCTDevLoadingView.m in Sources */,
3D0B842C1EC0B4EA00B2BD8E /* RCTTVView.m in Sources */,
- 2D3B5EED1D9B09D700451313 /* RCTTabBarManager.m in Sources */,
2D3B5EEF1D9B09DC00451313 /* RCTViewManager.m in Sources */,
13134C971E296B2A00B9F3CB /* RCTObjcExecutor.mm in Sources */,
594F0A351FD23228007FBE96 /* RCTSurfaceHostingView.mm in Sources */,
130E3D8B1E6A083900ACE484 /* RCTDevSettings.mm in Sources */,
- 2D3B5ED81D9B098A00451313 /* RCTNavigatorManager.m in Sources */,
2D3B5E951D9B087C00451313 /* RCTAssert.m in Sources */,
59D031F81F8353D3008361F0 /* RCTSafeAreaViewLocalData.m in Sources */,
- 3DF1BE851F26577300068F1A /* JSCTracing.cpp in Sources */,
2D3B5EB61D9B091400451313 /* RCTExceptionsManager.m in Sources */,
- 2D3B5EEB1D9B09D000451313 /* RCTTabBarItem.m in Sources */,
2D3B5ED41D9B097D00451313 /* RCTModalHostView.m in Sources */,
599FAA391FB274980058CCF6 /* RCTSurface.mm in Sources */,
C606692F1F3CC60500E67165 /* RCTModuleMethod.mm in Sources */,
@@ -4299,7 +4226,6 @@
13134C871E296B2A00B9F3CB /* RCTCxxBridge.mm in Sources */,
CF2731C31E7B8DF30044CA4F /* RCTDeviceInfo.m in Sources */,
599FAA3F1FB274980058CCF6 /* RCTSurfaceRootShadowView.m in Sources */,
- EBF21C001FC499A80052F4D5 /* InspectorInterfaces.cpp in Sources */,
597633371F4E021D005BE8A4 /* RCTShadowView+Internal.m in Sources */,
2D3B5EB11D9B090100451313 /* RCTAppState.m in Sources */,
59E604A31FE9CCE300BD90C5 /* RCTScrollContentViewManager.m in Sources */,
@@ -4310,6 +4236,7 @@
2D3B5E981D9B089500451313 /* RCTConvert.m in Sources */,
3D7BFD181EA8E351008DFB7A /* RCTPackagerClient.m in Sources */,
2D3B5EA71D9B08CE00451313 /* RCTTouchHandler.m in Sources */,
+ 8507BBBF21EDACC200AEAFCA /* JSCExecutorFactory.mm in Sources */,
59D031F01F8353D3008361F0 /* RCTSafeAreaShadowView.m in Sources */,
5925356B20084D0600DD584B /* RCTSurfaceSizeMeasureMode.mm in Sources */,
3D05745A1DE5FFF500184BB4 /* RCTJavaScriptLoader.mm in Sources */,
@@ -4324,7 +4251,6 @@
2D3B5EB51D9B091100451313 /* RCTDevMenu.m in Sources */,
59EDBCAC1FDF4E0C003573DE /* (null) in Sources */,
2D3B5EBD1D9B092A00451313 /* RCTTiming.m in Sources */,
- 135A9C041E7B0F6400587AEB /* RCTJSCErrorHandling.mm in Sources */,
2D3B5EA81D9B08D300451313 /* RCTUtils.m in Sources */,
599FAA451FB274980058CCF6 /* RCTSurfaceRootView.mm in Sources */,
2D3B5EC81D9B095800451313 /* RCTActivityIndicatorViewManager.m in Sources */,
@@ -4338,15 +4264,12 @@
59EDBCBC1FDF4E0C003573DE /* RCTScrollViewManager.m in Sources */,
59EDBCB01FDF4E0C003573DE /* RCTScrollContentView.m in Sources */,
2D3B5EF01D9B09E300451313 /* RCTWrapperViewController.m in Sources */,
- 2D3B5EEC1D9B09D400451313 /* RCTTabBarItemManager.m in Sources */,
2D3B5EB01D9B08FE00451313 /* RCTAlertManager.m in Sources */,
13134C9B1E296B2A00B9F3CB /* RCTCxxMethod.mm in Sources */,
2D3B5E9C1D9B08A300451313 /* RCTImageSource.m in Sources */,
- 3DDEC1521DDCE0CA0020BBDF /* RCTJSCSamplingProfiler.m in Sources */,
2D3B5EC31D9B094800451313 /* RCTProfileTrampoline-arm.S in Sources */,
3D0B842B1EC0B49400B2BD8E /* RCTTVRemoteHandler.m in Sources */,
657734861EE834D900A0E9EA /* RCTInspectorDevServerHelper.mm in Sources */,
- 2D3B5ED91D9B098E00451313 /* RCTNavItem.m in Sources */,
66CD94B41F1045E700CB3C7C /* RCTMaskedView.m in Sources */,
2D74EAFA1DAE9590003B751B /* RCTMultipartDataTask.m in Sources */,
2D3B5EC51D9B094D00451313 /* RCTProfileTrampoline-i386.S in Sources */,
@@ -4357,12 +4280,9 @@
2D3B5EBE1D9B092D00451313 /* RCTUIManager.m in Sources */,
C60128AE1F3D1258009DF9FF /* RCTCxxConvert.m in Sources */,
2D3B5EDD1D9B09A300451313 /* RCTProgressViewManager.m in Sources */,
- 2D3B5ED71D9B098700451313 /* RCTNavigator.m in Sources */,
- 2D3B5EDA1D9B099100451313 /* RCTNavItemManager.m in Sources */,
2D3B5EC11D9B093900451313 /* RCTFPSGraph.m in Sources */,
2D3B5E9A1D9B089D00451313 /* RCTEventDispatcher.m in Sources */,
2D3B5ED61D9B098400451313 /* RCTModalHostViewManager.m in Sources */,
- 135A9C051E7B0F7500587AEB /* RCTJSCHelpers.mm in Sources */,
2D3B5EC71D9B095600451313 /* RCTActivityIndicatorView.m in Sources */,
2D3B5EB21D9B090300451313 /* RCTAsyncLocalStorage.m in Sources */,
59D031FC1F8353D3008361F0 /* RCTSafeAreaViewManager.m in Sources */,
@@ -4375,21 +4295,27 @@
buildActionMask = 2147483647;
files = (
3D383D251EBD27B6005632C8 /* Conv.cpp in Sources */,
- 3D383D261EBD27B6005632C8 /* StringBase.cpp in Sources */,
3D383D271EBD27B6005632C8 /* raw_logging.cc in Sources */,
+ 83281388217EB73400574D55 /* String.cpp in Sources */,
3D383D281EBD27B6005632C8 /* signalhandler.cc in Sources */,
+ 833D02BE217EBD2600A23750 /* Format.cpp in Sources */,
+ 83281391217EB76C00574D55 /* Demangle.cpp in Sources */,
+ 833D02BB217EBCFA00A23750 /* Assume.cpp in Sources */,
3D383D291EBD27B6005632C8 /* dynamic.cpp in Sources */,
3D383D2A1EBD27B6005632C8 /* utilities.cc in Sources */,
- 3D383D2B1EBD27B6005632C8 /* MallocImpl.cpp in Sources */,
- 3D383D2C1EBD27B6005632C8 /* Bits.cpp in Sources */,
+ 8328138E217EB75C00574D55 /* ColdClass.cpp in Sources */,
3D383D2D1EBD27B6005632C8 /* symbolize.cc in Sources */,
3D383D2E1EBD27B6005632C8 /* vlog_is_on.cc in Sources */,
3D383D2F1EBD27B6005632C8 /* Unicode.cpp in Sources */,
3D383D301EBD27B6005632C8 /* demangle.cc in Sources */,
+ 8328139A217EB79D00574D55 /* ScopeGuard.cpp in Sources */,
+ 83281394217EB77D00574D55 /* SpookyHashV2.cpp in Sources */,
3D383D311EBD27B6005632C8 /* Demangle.cpp in Sources */,
3D383D331EBD27B6005632C8 /* logging.cc in Sources */,
+ 83281397217EB79000574D55 /* F14Table.cpp in Sources */,
+ 83281385217EB71200574D55 /* MallocImpl.cpp in Sources */,
+ 8328138B217EB74C00574D55 /* json_pointer.cpp in Sources */,
3D383D341EBD27B6005632C8 /* json.cpp in Sources */,
- 3D383D351EBD27B6005632C8 /* BitsFunctexcept.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -4412,7 +4338,9 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 53DEF6EA205AE5A0006A3890 /* YGFloatOptional.cpp in Sources */,
+ AC4A6AFA21FB4EBF00FBEC39 /* YGMarker.cpp in Sources */,
+ AC6B69E721B146B400B2B68A /* YGValue.cpp in Sources */,
+ AC8360D121B025BC00FC46B9 /* YGConfig.cpp in Sources */,
53D123A01FBF1EFF001B8A10 /* Yoga.cpp in Sources */,
5352C5752038FF9500A3B97E /* YGStyle.cpp in Sources */,
53EC85E21FDEC75F0051B2B5 /* YGNode.cpp in Sources */,
@@ -4427,8 +4355,9 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ AC4A6AFB21FB4ECA00FBEC39 /* YGMarker.cpp in Sources */,
+ AC6B69EA21B146E700B2B68A /* YGValue.cpp in Sources */,
BA0501B02109DD1800A6BBC4 /* YGConfig.cpp in Sources */,
- 53DEF6EB205AE5A1006A3890 /* YGFloatOptional.cpp in Sources */,
53D123A11FBF1EFF001B8A10 /* Yoga.cpp in Sources */,
5352C5762038FF9700A3B97E /* YGStyle.cpp in Sources */,
53EC85E31FDEC75F0051B2B5 /* YGNode.cpp in Sources */,
@@ -4439,30 +4368,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
- 3D3CD9051DE5FBD600167DC4 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 13EBC6711E2870DE00880AC5 /* JSCWrapper.cpp in Sources */,
- 13EBC6731E2870DE00880AC5 /* Value.cpp in Sources */,
- 13EBC67D1E28725900880AC5 /* JSCHelpers.cpp in Sources */,
- 135A9C021E7B0F4800587AEB /* systemJSCWrapper.cpp in Sources */,
- 13EBC67B1E28723000880AC5 /* Unicode.cpp in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 3D3CD9121DE5FBD800167DC4 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 13EBC6791E2870E400880AC5 /* Unicode.cpp in Sources */,
- 13EBC6781E2870E400880AC5 /* JSCWrapper.cpp in Sources */,
- 13EBC6771E2870E400880AC5 /* JSCHelpers.cpp in Sources */,
- 135A9C011E7B0F4700587AEB /* systemJSCWrapper.cpp in Sources */,
- 13EBC67A1E2870E400880AC5 /* Value.cpp in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
3D3CD91F1DE5FBEC00167DC4 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -4472,19 +4377,11 @@
13F8877D1E29726200C3C7A1 /* ModuleRegistry.cpp in Sources */,
C6D3801C1F71D76700621378 /* RAMBundleRegistry.cpp in Sources */,
13F8876E1E29726200C3C7A1 /* CxxNativeModule.cpp in Sources */,
- 13F887721E29726200C3C7A1 /* JSCExecutor.cpp in Sources */,
- 13F887741E29726200C3C7A1 /* JSCLegacyTracing.cpp in Sources */,
13DA8A332097A90B00276ED4 /* ReactMarker.cpp in Sources */,
- 13F887771E29726200C3C7A1 /* JSCPerfStats.cpp in Sources */,
13F887711E29726200C3C7A1 /* JSBundleType.cpp in Sources */,
- 13F887791E29726200C3C7A1 /* JSCUtils.cpp in Sources */,
- 13F887781E29726200C3C7A1 /* JSCSamplingProfiler.cpp in Sources */,
- 13F887751E29726200C3C7A1 /* JSCMemory.cpp in Sources */,
13F8877C1E29726200C3C7A1 /* MethodCall.cpp in Sources */,
- 13F8877F1E29726200C3C7A1 /* Platform.cpp in Sources */,
13F887701E29726200C3C7A1 /* Instance.cpp in Sources */,
13F8877E1E29726200C3C7A1 /* NativeToJsBridge.cpp in Sources */,
- 13F887761E29726200C3C7A1 /* JSCNativeModules.cpp in Sources */,
13F887801E29726200C3C7A1 /* SampleCxxModule.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -4498,20 +4395,12 @@
13F8878E1E29726300C3C7A1 /* JSIndexedRAMBundle.cpp in Sources */,
13F887901E29726300C3C7A1 /* ModuleRegistry.cpp in Sources */,
C6D3801D1F71D76800621378 /* RAMBundleRegistry.cpp in Sources */,
- 13F887851E29726300C3C7A1 /* JSCExecutor.cpp in Sources */,
- 13F887871E29726300C3C7A1 /* JSCLegacyTracing.cpp in Sources */,
- 13F8878A1E29726300C3C7A1 /* JSCPerfStats.cpp in Sources */,
13DA8A342097A90B00276ED4 /* ReactMarker.cpp in Sources */,
13F887841E29726300C3C7A1 /* Instance.cpp in Sources */,
- 13F8878C1E29726300C3C7A1 /* JSCUtils.cpp in Sources */,
- 13F8878B1E29726300C3C7A1 /* JSCSamplingProfiler.cpp in Sources */,
- 13F887881E29726300C3C7A1 /* JSCMemory.cpp in Sources */,
3D80D9181DF6F7A80028D040 /* JSBundleType.cpp in Sources */,
13F8878F1E29726300C3C7A1 /* MethodCall.cpp in Sources */,
- 13F887921E29726300C3C7A1 /* Platform.cpp in Sources */,
13F887911E29726300C3C7A1 /* NativeToJsBridge.cpp in Sources */,
13F887821E29726300C3C7A1 /* CxxNativeModule.cpp in Sources */,
- 13F887891E29726300C3C7A1 /* JSCNativeModules.cpp in Sources */,
13F887931E29726300C3C7A1 /* SampleCxxModule.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -4540,6 +4429,7 @@
83CBBACC1A6023D300E9B192 /* RCTConvert.m in Sources */,
131B6AF41AF1093D00FFC3E0 /* RCTSegmentedControl.m in Sources */,
830A229E1A66C68A008503DA /* RCTRootView.m in Sources */,
+ 8507BBBE21EDACC200AEAFCA /* JSCExecutorFactory.mm in Sources */,
13B07FF01A69327A00A75B9A /* RCTExceptionsManager.m in Sources */,
13A0C28A1B74F71200B29F6F /* RCTDevMenu.m in Sources */,
13BCE8091C99CB9D00DD7AAD /* RCTRootShadowView.m in Sources */,
@@ -4584,16 +4474,13 @@
1450FF881BCFF28A00208362 /* RCTProfileTrampoline-arm64.S in Sources */,
13E41EEB1C05CA0B00CD8DAC /* RCTProfileTrampoline-i386.S in Sources */,
3D37B5821D522B190042D5B5 /* RCTFont.mm in Sources */,
- 137327EA1AA5CF210034F82E /* RCTTabBarManager.m in Sources */,
59EDBCB71FDF4E0C003573DE /* RCTScrollView.m in Sources */,
59EDBCAB1FDF4E0C003573DE /* (null) in Sources */,
59EDBCBB1FDF4E0C003573DE /* RCTScrollViewManager.m in Sources */,
- 369123E11DDC75850095B341 /* RCTJSCSamplingProfiler.m in Sources */,
599FAA441FB274980058CCF6 /* RCTSurfaceRootView.mm in Sources */,
C60669361F3CCF1B00E67165 /* RCTManagedPointer.mm in Sources */,
13B080261A694A8400A75B9A /* RCTWrapperViewController.m in Sources */,
A2440AA31DF8D854006E7BFC /* RCTReloadCommand.m in Sources */,
- 3DF1BE821F26576400068F1A /* JSCTracing.cpp in Sources */,
6577348F1EE8354A00A0E9EA /* RCTInspector.mm in Sources */,
E9B20B7B1B500126007A2DA7 /* RCTAccessibilityManager.m in Sources */,
13A0C2891B74F71200B29F6F /* RCTDevLoadingView.m in Sources */,
@@ -4612,23 +4499,18 @@
83CBBA981A6020BB00E9B192 /* RCTTouchHandler.m in Sources */,
3EDCA8A51D3591E700450C31 /* RCTErrorInfo.m in Sources */,
83CBBA521A601E3B00E9B192 /* RCTLog.mm in Sources */,
- 13B0801D1A69489C00A75B9A /* RCTNavItemManager.m in Sources */,
13A6E20E1C19AA0C00845B82 /* RCTParserUtils.m in Sources */,
59D031F71F8353D3008361F0 /* RCTSafeAreaViewLocalData.m in Sources */,
13E067571A70F44B002CDEE1 /* RCTView.m in Sources */,
3D7749441DC1065C007EC8D8 /* RCTPlatform.m in Sources */,
- EBF21BBD1FC498270052F4D5 /* InspectorInterfaces.cpp in Sources */,
59EDBCAF1FDF4E0C003573DE /* RCTScrollContentView.m in Sources */,
13D9FEEE1CDCD93000158BD7 /* RCTKeyboardObserver.m in Sources */,
- 135A9C001E7B0EE600587AEB /* RCTJSCHelpers.mm in Sources */,
B233E6EA1D2D845D00BC68BA /* RCTI18nManager.m in Sources */,
3D7BFD1F1EA8E351008DFB7A /* RCTPackagerConnection.mm in Sources */,
13456E931ADAD2DE009F94A7 /* RCTConvert+CoreLocation.m in Sources */,
- 137327E91AA5CF210034F82E /* RCTTabBarItemManager.m in Sources */,
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 */,
@@ -4639,10 +4521,8 @@
66CD94B31F1045E700CB3C7C /* RCTMaskedView.m in Sources */,
13C156061AB1A2840079392D /* RCTWebViewManager.m in Sources */,
58114A161AAE854800E7D092 /* RCTPicker.m in Sources */,
- 137327E81AA5CF210034F82E /* RCTTabBarItem.m in Sources */,
83A1FE8C1B62640A00BE0E65 /* RCTModalHostView.m in Sources */,
5925356A20084D0600DD584B /* RCTSurfaceSizeMeasureMode.mm in Sources */,
- 9936F3371F5F2F480010BF04 /* PrivateDataBase.cpp in Sources */,
1450FF871BCFF28A00208362 /* RCTProfileTrampoline-arm.S in Sources */,
131B6AF51AF1093D00FFC3E0 /* RCTSegmentedControlManager.m in Sources */,
58114A171AAE854800E7D092 /* RCTPickerManager.m in Sources */,
@@ -4651,13 +4531,9 @@
68EFE4EE1CF6EB3900A1DE13 /* RCTBundleURLProvider.m in Sources */,
B95154321D1B34B200FE7B80 /* RCTActivityIndicatorView.m in Sources */,
5960C1BB1F0804A00066FD5B /* RCTLayoutAnimationGroup.m in Sources */,
- 13B0801A1A69489C00A75B9A /* RCTNavigator.m in Sources */,
- 137327E71AA5CF210034F82E /* RCTTabBar.m in Sources */,
13F17A851B8493E5007D4C75 /* RCTRedBox.m in Sources */,
- 135A9BFC1E7B0EAE00587AEB /* RCTJSCErrorHandling.mm in Sources */,
59D031F31F8353D3008361F0 /* RCTSafeAreaView.m in Sources */,
83392EB31B6634E10013B15F /* RCTModalHostViewController.m in Sources */,
- 13B0801C1A69489C00A75B9A /* RCTNavItem.m in Sources */,
83CBBA691A601EF300E9B192 /* RCTEventDispatcher.m in Sources */,
83A1FE8F1B62643A00BE0E65 /* RCTModalHostViewManager.m in Sources */,
13E0674A1A70F434002CDEE1 /* RCTUIManager.m in Sources */,
@@ -4665,52 +4541,68 @@
391E86A41C623EC800009732 /* RCTTouchEvent.m in Sources */,
1450FF861BCFF28A00208362 /* RCTProfile.m in Sources */,
13AB90C11B6FA36700713B4F /* RCTComponentData.m in Sources */,
- 13B0801B1A69489C00A75B9A /* RCTNavigatorManager.m in Sources */,
916F9C2D1F743F57002E5920 /* RCTModalManager.m in Sources */,
F1EFDA50201F661000EE6E4C /* RCTUIUtils.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
- 9936F30A1F5F2E4B0010BF04 /* Sources */ = {
+ EBF21BD31FC498900052F4D5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 9936F33E1F5F2FFC0010BF04 /* PrivateDataBase.cpp in Sources */,
+ EBF21BFC1FC4990B0052F4D5 /* InspectorInterfaces.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
- 9936F3261F5F2E5B0010BF04 /* Sources */ = {
+ EBF21BF11FC4989A0052F4D5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 9936F33B1F5F2F9D0010BF04 /* PrivateDataBase.cpp in Sources */,
+ EBF21BFF1FC4998E0052F4D5 /* InspectorInterfaces.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
- EBF21BD31FC498900052F4D5 /* Sources */ = {
+ ED296FA9214C9A0900B7C4FE /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- EBF21BFC1FC4990B0052F4D5 /* InspectorInterfaces.cpp in Sources */,
+ ED296FB9214C9AC200B7C4FE /* JSCRuntime.cpp in Sources */,
+ ED296FB7214C9A9A00B7C4FE /* JSIDynamic.cpp in Sources */,
+ ED296FB8214C9A9A00B7C4FE /* jsi.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
- EBF21BF11FC4989A0052F4D5 /* Sources */ = {
+ ED296FE1214C9CF800B7C4FE /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- EBF21BFF1FC4998E0052F4D5 /* InspectorInterfaces.cpp in Sources */,
+ EDDA711E2164285A00B2D070 /* JSINativeModules.cpp in Sources */,
+ EDDA71202164285A00B2D070 /* JSIExecutor.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ EDEBC6CA214B3E7000DD5AC8 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ EDEBC6E6214B3F6800DD5AC8 /* JSCRuntime.cpp in Sources */,
+ EDEBC6E4214B3F6800DD5AC8 /* jsi.cpp in Sources */,
+ EDEBC6E3214B3F6800DD5AC8 /* JSIDynamic.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ EDEBC734214B45A300DD5AC8 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ EDDA711D2164285A00B2D070 /* JSINativeModules.cpp in Sources */,
+ EDDA711F2164285A00B2D070 /* JSIExecutor.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
- 1320081B1E283DC300F0C457 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 139D7ECD1E25DB7D00323FB7 /* third-party */;
- targetProxy = 1320081A1E283DC300F0C457 /* PBXContainerItemProxy */;
- };
1320081D1E283DCB00F0C457 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 139D7E871E25C6D100323FB7 /* double-conversion */;
@@ -4726,11 +4618,6 @@
target = 3D3CD9261DE5FBEE00167DC4 /* cxxreact-tvOS */;
targetProxy = 3D0574561DE5FF9600184BB4 /* PBXContainerItemProxy */;
};
- 3D383D641EBD27CE005632C8 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 3D383D211EBD27B6005632C8 /* third-party-tvOS */;
- targetProxy = 3D383D631EBD27CE005632C8 /* PBXContainerItemProxy */;
- };
3D383D661EBD27DB005632C8 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 3D383D3D1EBD27B9005632C8 /* double-conversion-tvOS */;
@@ -4741,50 +4628,90 @@
target = 3D3CD9191DE5FBEC00167DC4 /* cxxreact */;
targetProxy = 3D3CD94B1DE5FCE700167DC4 /* PBXContainerItemProxy */;
};
- 3D3CD9501DE5FDB900167DC4 /* PBXTargetDependency */ = {
+ 53D123991FBF1E0C001B8A10 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
- target = 3D3CD8FF1DE5FBD600167DC4 /* jschelpers */;
- targetProxy = 3D3CD94F1DE5FDB900167DC4 /* PBXContainerItemProxy */;
+ target = 3D3C04B91DE3340900C268FA /* yoga */;
+ targetProxy = 53D123981FBF1E0C001B8A10 /* PBXContainerItemProxy */;
};
- 3DC159E81E83E2A0007B1282 /* PBXTargetDependency */ = {
+ ED296F7E214C957300B7C4FE /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
- target = 3D3CD90C1DE5FBD800167DC4 /* jschelpers-tvOS */;
- targetProxy = 3DC159E71E83E2A0007B1282 /* PBXContainerItemProxy */;
+ target = EDEBC6BA214B3E7000DD5AC8 /* jsi */;
+ targetProxy = ED296F7D214C957300B7C4FE /* PBXContainerItemProxy */;
};
- 53D123991FBF1E0C001B8A10 /* PBXTargetDependency */ = {
+ ED296F81214C971800B7C4FE /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
- target = 3D3C04B91DE3340900C268FA /* yoga */;
- targetProxy = 53D123981FBF1E0C001B8A10 /* PBXContainerItemProxy */;
+ target = EBF21BDD1FC4989A0052F4D5 /* jsinspector-tvOS */;
+ targetProxy = ED296F80214C971800B7C4FE /* PBXContainerItemProxy */;
};
- 9936F3401F5F305D0010BF04 /* PBXTargetDependency */ = {
+ ED296F97214C996500B7C4FE /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
- target = 9936F2F81F5F2E4B0010BF04 /* privatedata */;
- targetProxy = 9936F33F1F5F305D0010BF04 /* PBXContainerItemProxy */;
+ target = 3D383D3D1EBD27B9005632C8 /* double-conversion-tvOS */;
+ targetProxy = ED296F96214C996500B7C4FE /* PBXContainerItemProxy */;
};
- 9936F3421F5F30640010BF04 /* PBXTargetDependency */ = {
+ ED296FCA214C9B6200B7C4FE /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
- target = 9936F3141F5F2E5B0010BF04 /* privatedata-tvOS */;
- targetProxy = 9936F3411F5F30640010BF04 /* PBXContainerItemProxy */;
+ target = ED296F98214C9A0900B7C4FE /* jsi-tvOS */;
+ targetProxy = ED296FC9214C9B6200B7C4FE /* PBXContainerItemProxy */;
};
- 9936F3441F5F30780010BF04 /* PBXTargetDependency */ = {
+ ED296FF8214C9EAA00B7C4FE /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
- target = 9936F2F81F5F2E4B0010BF04 /* privatedata */;
- targetProxy = 9936F3431F5F30780010BF04 /* PBXContainerItemProxy */;
+ target = 3D383D211EBD27B6005632C8 /* third-party-tvOS */;
+ targetProxy = ED296FF7214C9EAA00B7C4FE /* PBXContainerItemProxy */;
};
- 9936F3461F5F30830010BF04 /* PBXTargetDependency */ = {
+ ED296FFC214C9EC000B7C4FE /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
- target = 9936F3141F5F2E5B0010BF04 /* privatedata-tvOS */;
- targetProxy = 9936F3451F5F30830010BF04 /* PBXContainerItemProxy */;
+ target = 3D3CD9261DE5FBEE00167DC4 /* cxxreact-tvOS */;
+ targetProxy = ED296FFB214C9EC000B7C4FE /* PBXContainerItemProxy */;
};
- EBF21C021FC499D10052F4D5 /* PBXTargetDependency */ = {
+ ED296FFE214C9EC600B7C4FE /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
- target = EBF21BBF1FC498900052F4D5 /* jsinspector */;
- targetProxy = EBF21C011FC499D10052F4D5 /* PBXContainerItemProxy */;
+ target = ED296F98214C9A0900B7C4FE /* jsi-tvOS */;
+ targetProxy = ED296FFD214C9EC600B7C4FE /* PBXContainerItemProxy */;
};
- EBF21C041FC499D80052F4D5 /* PBXTargetDependency */ = {
+ ED29704E215012C700B7C4FE /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
- target = EBF21BDD1FC4989A0052F4D5 /* jsinspector-tvOS */;
- targetProxy = EBF21C031FC499D80052F4D5 /* PBXContainerItemProxy */;
+ target = 3D383D3D1EBD27B9005632C8 /* double-conversion-tvOS */;
+ targetProxy = ED29704D215012C700B7C4FE /* PBXContainerItemProxy */;
+ };
+ ED2970662150237300B7C4FE /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = ED296FD0214C9CF800B7C4FE /* jsiexecutor-tvOS */;
+ targetProxy = ED2970652150237300B7C4FE /* PBXContainerItemProxy */;
+ };
+ EDEBC74B214B46A700DD5AC8 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = EDEBC724214B45A300DD5AC8 /* jsiexecutor */;
+ targetProxy = EDEBC74A214B46A700DD5AC8 /* PBXContainerItemProxy */;
+ };
+ EDEBC74F214B477400DD5AC8 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = EDEBC6BA214B3E7000DD5AC8 /* jsi */;
+ targetProxy = EDEBC74E214B477400DD5AC8 /* PBXContainerItemProxy */;
+ };
+ EDEBC7CC214C516800DD5AC8 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 139D7E871E25C6D100323FB7 /* double-conversion */;
+ targetProxy = EDEBC7CB214C516800DD5AC8 /* PBXContainerItemProxy */;
+ };
+ EDEBC7CE214C523F00DD5AC8 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 3D3CD9191DE5FBEC00167DC4 /* cxxreact */;
+ targetProxy = EDEBC7CD214C523F00DD5AC8 /* PBXContainerItemProxy */;
+ };
+ EDEBC7D3214C528C00DD5AC8 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 139D7ECD1E25DB7D00323FB7 /* third-party */;
+ targetProxy = EDEBC7D2214C528C00DD5AC8 /* PBXContainerItemProxy */;
+ };
+ EDEBC7D7214C52FD00DD5AC8 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 139D7E871E25C6D100323FB7 /* double-conversion */;
+ targetProxy = EDEBC7D6214C52FD00DD5AC8 /* PBXContainerItemProxy */;
+ };
+ EDEBC7D9214C628300DD5AC8 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = EBF21BBF1FC498900052F4D5 /* jsinspector */;
+ targetProxy = EDEBC7D8214C628300DD5AC8 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
@@ -4826,9 +4753,15 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "c++14";
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_SUSPICIOUS_MOVES = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
+ HEADER_SEARCH_PATHS = (
+ "$(SRCROOT)/../third-party/boost_1_63_0",
+ "$(SRCROOT)/../third-party/folly-2018.10.22.00",
+ "$(SRCROOT)/../third-party/glog-0.3.5/exported",
+ );
OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -4843,10 +4776,16 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "c++14";
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_SUSPICIOUS_MOVES = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ HEADER_SEARCH_PATHS = (
+ "$(SRCROOT)/../third-party/boost_1_63_0",
+ "$(SRCROOT)/../third-party/folly-2018.10.22.00",
+ "$(SRCROOT)/../third-party/glog-0.3.5/exported",
+ );
OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -4899,9 +4838,15 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "c++14";
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_SUSPICIOUS_MOVES = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
+ HEADER_SEARCH_PATHS = (
+ "$(SRCROOT)/../third-party/boost_1_63_0",
+ "$(SRCROOT)/../third-party/folly-2018.10.22.00",
+ "$(SRCROOT)/../third-party/glog-0.3.5/exported",
+ );
OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "third-party";
@@ -4917,10 +4862,16 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "c++14";
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_SUSPICIOUS_MOVES = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ HEADER_SEARCH_PATHS = (
+ "$(SRCROOT)/../third-party/boost_1_63_0",
+ "$(SRCROOT)/../third-party/folly-2018.10.22.00",
+ "$(SRCROOT)/../third-party/glog-0.3.5/exported",
+ );
OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "third-party";
@@ -5026,73 +4977,6 @@
};
name = Release;
};
- 3D3CD9091DE5FBD600167DC4 /* Debug */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = 3D788F841EBD2D240063D616 /* third-party.xcconfig */;
- buildSettings = {
- CLANG_CXX_LANGUAGE_STANDARD = "c++14";
- CLANG_STATIC_ANALYZER_MODE = deep;
- GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
- OTHER_LDFLAGS = "-ObjC";
- PRODUCT_NAME = "$(TARGET_NAME)";
- PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/jschelpers;
- RUN_CLANG_STATIC_ANALYZER = YES;
- };
- name = Debug;
- };
- 3D3CD90A1DE5FBD600167DC4 /* Release */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = 3D788F841EBD2D240063D616 /* third-party.xcconfig */;
- buildSettings = {
- CLANG_CXX_LANGUAGE_STANDARD = "c++14";
- CLANG_STATIC_ANALYZER_MODE = deep;
- GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
- GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
- OTHER_LDFLAGS = "-ObjC";
- PRODUCT_NAME = "$(TARGET_NAME)";
- PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/jschelpers;
- RUN_CLANG_STATIC_ANALYZER = NO;
- };
- name = Release;
- };
- 3D3CD9161DE5FBD800167DC4 /* Debug */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = 3D788F841EBD2D240063D616 /* third-party.xcconfig */;
- buildSettings = {
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_CXX_LANGUAGE_STANDARD = "c++14";
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_SUSPICIOUS_MOVES = YES;
- DEBUG_INFORMATION_FORMAT = dwarf;
- ENABLE_TESTABILITY = YES;
- GCC_NO_COMMON_BLOCKS = YES;
- OTHER_LDFLAGS = "-ObjC";
- PRODUCT_NAME = jschelpers;
- PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/jschelpers;
- SDKROOT = appletvos;
- };
- name = Debug;
- };
- 3D3CD9171DE5FBD800167DC4 /* Release */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = 3D788F841EBD2D240063D616 /* third-party.xcconfig */;
- buildSettings = {
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_CXX_LANGUAGE_STANDARD = "c++14";
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_SUSPICIOUS_MOVES = YES;
- COPY_PHASE_STRIP = NO;
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- GCC_NO_COMMON_BLOCKS = YES;
- OTHER_LDFLAGS = "-ObjC";
- PRODUCT_NAME = jschelpers;
- PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/jschelpers;
- SDKROOT = appletvos;
- };
- name = Release;
- };
3D3CD9231DE5FBEC00167DC4 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 3D788F841EBD2D240063D616 /* third-party.xcconfig */;
@@ -5327,7 +5211,7 @@
};
name = Release;
};
- 9936F3111F5F2E4B0010BF04 /* Debug */ = {
+ EBF21BDA1FC498900052F4D5 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 3D788F841EBD2D240063D616 /* third-party.xcconfig */;
buildSettings = {
@@ -5336,12 +5220,12 @@
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
- PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/privatedata;
+ PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/jsinspector;
RUN_CLANG_STATIC_ANALYZER = YES;
};
name = Debug;
};
- 9936F3121F5F2E4B0010BF04 /* Release */ = {
+ EBF21BDB1FC498900052F4D5 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 3D788F841EBD2D240063D616 /* third-party.xcconfig */;
buildSettings = {
@@ -5351,12 +5235,12 @@
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
- PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/privatedata;
+ PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/jsinspector;
RUN_CLANG_STATIC_ANALYZER = NO;
};
name = Release;
};
- 9936F32D1F5F2E5B0010BF04 /* Debug */ = {
+ EBF21BF81FC4989A0052F4D5 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 3D788F841EBD2D240063D616 /* third-party.xcconfig */;
buildSettings = {
@@ -5370,12 +5254,12 @@
GCC_NO_COMMON_BLOCKS = YES;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
- PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/privatedata;
+ PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/jsinspector;
SDKROOT = appletvos;
};
name = Debug;
};
- 9936F32E1F5F2E5B0010BF04 /* Release */ = {
+ EBF21BF91FC4989A0052F4D5 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 3D788F841EBD2D240063D616 /* third-party.xcconfig */;
buildSettings = {
@@ -5389,43 +5273,69 @@
GCC_NO_COMMON_BLOCKS = YES;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
- PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/privatedata;
+ PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/jsinspector;
SDKROOT = appletvos;
};
name = Release;
};
- EBF21BDA1FC498900052F4D5 /* Debug */ = {
+ ED296FB4214C9A0900B7C4FE /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 3D788F841EBD2D240063D616 /* third-party.xcconfig */;
buildSettings = {
+ CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++14";
- CLANG_STATIC_ANALYZER_MODE = deep;
- GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_SUSPICIOUS_MOVES = YES;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_TESTABILITY = YES;
+ GCC_NO_COMMON_BLOCKS = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(SRCROOT)/../third-party/boost_1_63_0",
+ "$(SRCROOT)/../third-party/folly-2018.10.22.00",
+ "$(SRCROOT)/../third-party/glog-0.3.5/src",
+ );
+ OTHER_CFLAGS = (
+ "-DFOLLY_NO_CONFIG",
+ "-DFOLLY_MOBILE=1",
+ "-DFOLLY_USE_LIBCPP=1",
+ );
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
- PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/jsinspector;
- RUN_CLANG_STATIC_ANALYZER = YES;
+ PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/jsi;
+ SDKROOT = appletvos;
};
name = Debug;
};
- EBF21BDB1FC498900052F4D5 /* Release */ = {
+ ED296FB5214C9A0900B7C4FE /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 3D788F841EBD2D240063D616 /* third-party.xcconfig */;
buildSettings = {
+ CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++14";
- CLANG_STATIC_ANALYZER_MODE = deep;
- GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
- GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_SUSPICIOUS_MOVES = YES;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_NO_COMMON_BLOCKS = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(SRCROOT)/../third-party/boost_1_63_0",
+ "$(SRCROOT)/../third-party/folly-2018.10.22.00",
+ "$(SRCROOT)/../third-party/glog-0.3.5/src",
+ );
+ OTHER_CFLAGS = (
+ "-DFOLLY_NO_CONFIG",
+ "-DFOLLY_MOBILE=1",
+ "-DFOLLY_USE_LIBCPP=1",
+ );
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
- PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/jsinspector;
- RUN_CLANG_STATIC_ANALYZER = NO;
+ PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/jsi;
+ SDKROOT = appletvos;
};
name = Release;
};
- EBF21BF81FC4989A0052F4D5 /* Debug */ = {
+ ED296FEC214C9CF800B7C4FE /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 3D788F841EBD2D240063D616 /* third-party.xcconfig */;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++14";
@@ -5435,16 +5345,25 @@
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_TESTABILITY = YES;
GCC_NO_COMMON_BLOCKS = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(SRCROOT)/../third-party/boost_1_63_0",
+ "$(SRCROOT)/../third-party/folly-2018.10.22.00",
+ "$(SRCROOT)/../third-party/glog-0.3.5/src",
+ );
+ OTHER_CFLAGS = (
+ "-DFOLLY_NO_CONFIG",
+ "-DFOLLY_MOBILE=1",
+ "-DFOLLY_USE_LIBCPP=1",
+ );
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
- PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/jsinspector;
+ PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/jsireact;
SDKROOT = appletvos;
};
name = Debug;
};
- EBF21BF91FC4989A0052F4D5 /* Release */ = {
+ ED296FED214C9CF800B7C4FE /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 3D788F841EBD2D240063D616 /* third-party.xcconfig */;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++14";
@@ -5454,13 +5373,81 @@
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_NO_COMMON_BLOCKS = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(SRCROOT)/../third-party/boost_1_63_0",
+ "$(SRCROOT)/../third-party/folly-2018.10.22.00",
+ "$(SRCROOT)/../third-party/glog-0.3.5/src",
+ );
+ OTHER_CFLAGS = (
+ "-DFOLLY_NO_CONFIG",
+ "-DFOLLY_MOBILE=1",
+ "-DFOLLY_USE_LIBCPP=1",
+ );
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
- PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/jsinspector;
+ PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/jsireact;
SDKROOT = appletvos;
};
name = Release;
};
+ EDEBC6D4214B3E7000DD5AC8 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 3D788F841EBD2D240063D616 /* third-party.xcconfig */;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "c++14";
+ CLANG_STATIC_ANALYZER_MODE = deep;
+ GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+ OTHER_LDFLAGS = "-ObjC";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/jsi;
+ RUN_CLANG_STATIC_ANALYZER = YES;
+ };
+ name = Debug;
+ };
+ EDEBC6D5214B3E7000DD5AC8 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 3D788F841EBD2D240063D616 /* third-party.xcconfig */;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "c++14";
+ CLANG_STATIC_ANALYZER_MODE = deep;
+ GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
+ GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+ OTHER_LDFLAGS = "-ObjC";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/jsi;
+ RUN_CLANG_STATIC_ANALYZER = NO;
+ };
+ name = Release;
+ };
+ EDEBC739214B45A300DD5AC8 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 3D788F841EBD2D240063D616 /* third-party.xcconfig */;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "c++14";
+ CLANG_STATIC_ANALYZER_MODE = deep;
+ GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+ OTHER_LDFLAGS = "-ObjC";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/jsireact;
+ RUN_CLANG_STATIC_ANALYZER = YES;
+ };
+ name = Debug;
+ };
+ EDEBC73A214B45A300DD5AC8 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 3D788F841EBD2D240063D616 /* third-party.xcconfig */;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "c++14";
+ CLANG_STATIC_ANALYZER_MODE = deep;
+ GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
+ GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+ OTHER_LDFLAGS = "-ObjC";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/jsireact;
+ RUN_CLANG_STATIC_ANALYZER = NO;
+ };
+ name = Release;
+ };
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@@ -5527,24 +5514,6 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- 3D3CD9081DE5FBD600167DC4 /* Build configuration list for PBXNativeTarget "jschelpers" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 3D3CD9091DE5FBD600167DC4 /* Debug */,
- 3D3CD90A1DE5FBD600167DC4 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 3D3CD9151DE5FBD800167DC4 /* Build configuration list for PBXNativeTarget "jschelpers-tvOS" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 3D3CD9161DE5FBD800167DC4 /* Debug */,
- 3D3CD9171DE5FBD800167DC4 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
3D3CD9221DE5FBEC00167DC4 /* Build configuration list for PBXNativeTarget "cxxreact" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@@ -5581,38 +5550,56 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- 9936F3101F5F2E4B0010BF04 /* Build configuration list for PBXNativeTarget "privatedata" */ = {
+ EBF21BD91FC498900052F4D5 /* Build configuration list for PBXNativeTarget "jsinspector" */ = {
isa = XCConfigurationList;
buildConfigurations = (
- 9936F3111F5F2E4B0010BF04 /* Debug */,
- 9936F3121F5F2E4B0010BF04 /* Release */,
+ EBF21BDA1FC498900052F4D5 /* Debug */,
+ EBF21BDB1FC498900052F4D5 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- 9936F32C1F5F2E5B0010BF04 /* Build configuration list for PBXNativeTarget "privatedata-tvOS" */ = {
+ EBF21BF71FC4989A0052F4D5 /* Build configuration list for PBXNativeTarget "jsinspector-tvOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
- 9936F32D1F5F2E5B0010BF04 /* Debug */,
- 9936F32E1F5F2E5B0010BF04 /* Release */,
+ EBF21BF81FC4989A0052F4D5 /* Debug */,
+ EBF21BF91FC4989A0052F4D5 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- EBF21BD91FC498900052F4D5 /* Build configuration list for PBXNativeTarget "jsinspector" */ = {
+ ED296FB3214C9A0900B7C4FE /* Build configuration list for PBXNativeTarget "jsi-tvOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
- EBF21BDA1FC498900052F4D5 /* Debug */,
- EBF21BDB1FC498900052F4D5 /* Release */,
+ ED296FB4214C9A0900B7C4FE /* Debug */,
+ ED296FB5214C9A0900B7C4FE /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- EBF21BF71FC4989A0052F4D5 /* Build configuration list for PBXNativeTarget "jsinspector-tvOS" */ = {
+ ED296FEB214C9CF800B7C4FE /* Build configuration list for PBXNativeTarget "jsiexecutor-tvOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
- EBF21BF81FC4989A0052F4D5 /* Debug */,
- EBF21BF91FC4989A0052F4D5 /* Release */,
+ ED296FEC214C9CF800B7C4FE /* Debug */,
+ ED296FED214C9CF800B7C4FE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ EDEBC6D3214B3E7000DD5AC8 /* Build configuration list for PBXNativeTarget "jsi" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ EDEBC6D4214B3E7000DD5AC8 /* Debug */,
+ EDEBC6D5214B3E7000DD5AC8 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ EDEBC738214B45A300DD5AC8 /* Build configuration list for PBXNativeTarget "jsiexecutor" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ EDEBC739214B45A300DD5AC8 /* Debug */,
+ EDEBC73A214B45A300DD5AC8 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;

React/third-party.xcconfig

@@ -2,9 +2,11 @@
// folly.xcconfig
// CxxReact
//
-// Created by Marc Horowitz on 1/12/17.
-// Copyright © 2017 Facebook. All rights reserved.
+// 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.
//
-HEADER_SEARCH_PATHS = $(SRCROOT)/../third-party/boost_1_63_0 $(SRCROOT)/../third-party/folly-2016.10.31.00 $(SRCROOT)/../third-party/glog-0.3.5/src
+HEADER_SEARCH_PATHS = $(SRCROOT)/../third-party/boost_1_63_0 $(SRCROOT)/../third-party/folly-2018.10.22.00 $(SRCROOT)/../third-party/glog-0.3.5/src
OTHER_CFLAGS = -DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1

React/UIUtils/RCTUIUtils.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/UIUtils/RCTUIUtils.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTActivityIndicatorView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTActivityIndicatorView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTActivityIndicatorViewManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTActivityIndicatorViewManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTAnimationType.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTAutoInsetsProtocol.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTBorderDrawing.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -8,6 +8,7 @@
#import <UIKit/UIKit.h>
#import <React/RCTBorderStyle.h>
+#import <React/RCTDefines.h>
typedef struct {
CGFloat topLeft;
@@ -33,22 +34,22 @@
/**
* Determine if the border widths, colors and radii are all equal.
*/
-BOOL RCTBorderInsetsAreEqual(UIEdgeInsets borderInsets);
-BOOL RCTCornerRadiiAreEqual(RCTCornerRadii cornerRadii);
-BOOL RCTBorderColorsAreEqual(RCTBorderColors borderColors);
+RCT_EXTERN BOOL RCTBorderInsetsAreEqual(UIEdgeInsets borderInsets);
+RCT_EXTERN BOOL RCTCornerRadiiAreEqual(RCTCornerRadii cornerRadii);
+RCT_EXTERN BOOL RCTBorderColorsAreEqual(RCTBorderColors borderColors);
/**
* Convert RCTCornerRadii to RCTCornerInsets by applying border insets.
* Effectively, returns radius - inset, with a lower bound of 0.0.
*/
-RCTCornerInsets RCTGetCornerInsets(RCTCornerRadii cornerRadii,
+RCT_EXTERN RCTCornerInsets RCTGetCornerInsets(RCTCornerRadii cornerRadii,
UIEdgeInsets borderInsets);
/**
* Create a CGPath representing a rounded rectangle with the specified bounds
* and corner insets. Note that the CGPathRef must be released by the caller.
*/
-CGPathRef RCTPathCreateWithRoundedRect(CGRect bounds,
+RCT_EXTERN CGPathRef RCTPathCreateWithRoundedRect(CGRect bounds,
RCTCornerInsets cornerInsets,
const CGAffineTransform *transform);
@@ -58,7 +59,7 @@
*
* `borderInsets` defines the border widths for each edge.
*/
-UIImage *RCTGetBorderImage(RCTBorderStyle borderStyle,
+RCT_EXTERN UIImage *RCTGetBorderImage(RCTBorderStyle borderStyle,
CGSize viewSize,
RCTCornerRadii cornerRadii,
UIEdgeInsets borderInsets,

React/Views/RCTBorderDrawing.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -224,6 +224,7 @@
borderInsets.right + MAX(cornerInsets.bottomRight.width, cornerInsets.topRight.width)
};
+ if (hasCornerRadii) {
// Asymmetrical edgeInsets cause strange artifacting on iOS 10 and earlier.
edgeInsets = (UIEdgeInsets){
MAX(edgeInsets.top, edgeInsets.bottom),
@@ -231,6 +232,7 @@
MAX(edgeInsets.top, edgeInsets.bottom),
MAX(edgeInsets.left, edgeInsets.right),
};
+ }
const CGSize size = makeStretchable ? (CGSize){
// 1pt for the middle stretchable area along each axis

React/Views/RCTBorderStyle.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTComponentData.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTComponentData.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTComponent.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTConvert+CoreLocation.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTConvert+CoreLocation.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTConvert+Transform.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTConvert+Transform.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTDatePicker.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTDatePicker.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTDatePickerManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTDatePickerManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTFont.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTFont.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTLayout.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTLayout.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTMaskedView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTMaskedView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTMaskedViewManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTMaskedViewManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTModalHostViewController.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTModalHostViewController.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTModalHostView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTModalHostView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTModalHostViewManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTModalHostViewManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTModalManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTModalManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTNavigator.h

@@ -1,34 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#import <UIKit/UIKit.h>
-
-#import <React/RCTFrameUpdate.h>
-
-@class RCTBridge;
-
-@interface RCTNavigator : UIView <RCTFrameUpdateObserver>
-
-@property (nonatomic, strong) UIView *reactNavSuperviewLink;
-@property (nonatomic, assign) NSInteger requestedTopOfStack;
-@property (nonatomic, assign) BOOL interactivePopGestureEnabled;
-
-- (instancetype)initWithBridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
-
-/**
- * Schedules a JavaScript navigation and prevents `UIKit` from navigating until
- * JavaScript has sent its scheduled navigation.
- *
- * @returns Whether or not a JavaScript driven navigation could be
- * scheduled/reserved. If returning `NO`, JavaScript should usually just do
- * nothing at all.
- */
-- (BOOL)requestSchedulingJavaScriptNavigation;
-
-- (void)uiManagerDidPerformMounting;
-
-@end

React/Views/RCTNavigator.m

@@ -1,630 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#import "RCTNavigator.h"
-
-#import "RCTAssert.h"
-#import "RCTBridge.h"
-#import "RCTConvert.h"
-#import "RCTEventDispatcher.h"
-#import "RCTLog.h"
-#import "RCTNavItem.h"
-#import "RCTScrollView.h"
-#import "RCTUtils.h"
-#import "RCTView.h"
-#import "RCTWrapperViewController.h"
-#import "UIView+React.h"
-
-typedef NS_ENUM(NSUInteger, RCTNavigationLock) {
- RCTNavigationLockNone,
- RCTNavigationLockNative,
- RCTNavigationLockJavaScript
-};
-
-// By default the interactive pop gesture will be enabled when the navigation bar is displayed
-// and disabled when hidden
-// RCTPopGestureStateDefault maps to the default behavior (mentioned above). Once popGestureState
-// leaves this value, it can never be returned back to it. This is because, due to a limitation in
-// the iOS APIs, once we override the default behavior of the gesture recognizer, we cannot return
-// back to it.
-// RCTPopGestureStateEnabled will enable the gesture independent of nav bar visibility
-// RCTPopGestureStateDisabled will disable the gesture independent of nav bar visibility
-typedef NS_ENUM(NSUInteger, RCTPopGestureState) {
- RCTPopGestureStateDefault = 0,
- RCTPopGestureStateEnabled,
- RCTPopGestureStateDisabled
-};
-
-NSInteger kNeverRequested = -1;
-NSInteger kNeverProgressed = -10000;
-
-
-@interface UINavigationController ()
-
-// need to declare this since `UINavigationController` doesn't publicly declare the fact that it implements
-// UINavigationBarDelegate :(
-- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item;
-
-@end
-
-// http://stackoverflow.com/questions/5115135/uinavigationcontroller-how-to-cancel-the-back-button-event
-// There's no other way to do this unfortunately :(
-@interface RCTNavigationController : UINavigationController <UINavigationBarDelegate>
-{
- dispatch_block_t _scrollCallback;
-}
-
-@property (nonatomic, assign) RCTNavigationLock navigationLock;
-
-@end
-
-/**
- * In general, `RCTNavigator` examines `_currentViews` (which are React child
- * views), and compares them to `_navigationController.viewControllers` (which
- * are controlled by UIKit).
- *
- * It is possible for JavaScript (`_currentViews`) to "get ahead" of native
- * (`navigationController.viewControllers`) and vice versa. JavaScript gets
- * ahead by adding/removing React subviews. Native gets ahead by swiping back,
- * or tapping the back button. In both cases, the other system is initially
- * unaware. And in both cases, `RCTNavigator` helps the other side "catch up".
- *
- * If `RCTNavigator` sees the number of React children have changed, it
- * pushes/pops accordingly. If `RCTNavigator` sees a `UIKit` driven push/pop, it
- * notifies JavaScript that this has happened, and expects that JavaScript will
- * eventually render more children to match `UIKit`. There's no rush for
- * JavaScript to catch up. But if it does render anything, it must catch up to
- * UIKit. It cannot deviate.
- *
- * To implement this, we need a lock, which we store on the native thread. This
- * lock allows one of the systems to push/pop views. Whoever wishes to
- * "get ahead" must obtain the lock. Whoever wishes to "catch up" must obtain
- * the lock. One thread may not "get ahead" or "catch up" when the other has
- * the lock. Once a thread has the lock, it can only do the following:
- *
- * 1. If it is behind, it may only catch up.
- * 2. If it is caught up or ahead, it may push or pop.
- *
- *
- * ========= Acquiring The Lock ==========
- *
- * JavaScript asynchronously acquires the lock using a native hook. It might be
- * rejected and receive the return value `false`.
- *
- * We acquire the native lock in `shouldPopItem`, which is called right before
- * native tries to push/pop, but only if JavaScript doesn't already have the
- * lock.
- *
- * ======== While JavaScript Has Lock ====
- *
- * When JavaScript has the lock, we have to block all `UIKit` driven pops:
- *
- * 1. Block back button navigation:
- * - Back button will invoke `shouldPopItem`, from which we return `NO` if
- * JavaScript has the lock.
- * - Back button will respect the return value `NO` and not permit
- * navigation.
- *
- * 2. Block swipe-to-go-back navigation:
- * - Swipe will trigger `shouldPopItem`, but swipe won't respect our `NO`
- * return value so we must disable the gesture recognizer while JavaScript
- * has the lock.
- *
- * ======== While Native Has Lock =======
- *
- * We simply deny JavaScript the right to acquire the lock.
- *
- *
- * ======== Releasing The Lock ===========
- *
- * Recall that the lock represents who has the right to either push/pop (or
- * catch up). As soon as we recognize that the side that has locked has carried
- * out what it scheduled to do, we can release the lock, but only after any
- * possible animations are completed.
- *
- * *IF* a scheduled operation results in a push/pop (not all do), then we can
- * only release the lock after the push/pop animation is complete because
- * UIKit. `didMoveToNavigationController` is invoked when the view is done
- * pushing/popping/animating. Native swipe-to-go-back interactions can be
- * aborted, however, and you'll never see that method invoked. So just to cover
- * that case, we also put an animation complete hook in
- * `animateAlongsideTransition` to make sure we free the lock, in case the
- * scheduled native push/pop never actually happened.
- *
- * For JavaScript:
- * - When we see that JavaScript has "caught up" to `UIKit`, and no pushes/pops
- * were needed, we can release the lock.
- * - When we see that JavaScript requires *some* push/pop, it's not yet done
- * carrying out what it scheduled to do. Just like with `UIKit` push/pops, we
- * still have to wait for it to be done animating
- * (`didMoveToNavigationController` is a suitable hook).
- *
- */
-@implementation RCTNavigationController
-
-/**
- * @param callback Callback that is invoked when a "scroll" interaction begins
- * so that `RCTNavigator` can notify `JavaScript`.
- */
-- (instancetype)initWithScrollCallback:(dispatch_block_t)callback
-{
- if ((self = [super initWithNibName:nil bundle:nil])) {
- _scrollCallback = callback;
- }
- return self;
-}
-
-/**
- * Invoked when either a navigation item has been popped off, or when a
- * swipe-back gesture has began. The swipe-back gesture doesn't respect the
- * return value of this method. The back button does. That's why we have to
- * completely disable the gesture recognizer for swipe-back while JS has the
- * lock.
- */
-- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item
-{
-#if !TARGET_OS_TV
- if (self.interactivePopGestureRecognizer.state == UIGestureRecognizerStateBegan) {
- if (self.navigationLock == RCTNavigationLockNone) {
- self.navigationLock = RCTNavigationLockNative;
- if (_scrollCallback) {
- _scrollCallback();
- }
- } else if (self.navigationLock == RCTNavigationLockJavaScript) {
- // This should never happen because we disable/enable the gesture
- // recognizer when we lock the navigation.
- RCTAssert(NO, @"Should never receive gesture start while JS locks navigator");
- }
- } else
-#endif //TARGET_OS_TV
- {
- if (self.navigationLock == RCTNavigationLockNone) {
- // Must be coming from native interaction, lock it - it will be unlocked
- // in `didMoveToNavigationController`
- self.navigationLock = RCTNavigationLockNative;
- if (_scrollCallback) {
- _scrollCallback();
- }
- } else if (self.navigationLock == RCTNavigationLockJavaScript) {
- // This should only occur when JS has the lock, and
- // - JS is driving the pop
- // - Or the back button was pressed
- // TODO: We actually want to disable the backbutton while JS has the
- // lock, but it's not so easy. Even returning `NO` wont' work because it
- // will also block JS driven pops. We simply need to disallow a standard
- // back button, and instead use a custom one that tells JS to pop to
- // length (`currentReactCount` - 1).
- return [super navigationBar:navigationBar shouldPopItem:item];
- }
- }
- return [super navigationBar:navigationBar shouldPopItem:item];
-}
-
-@end
-
-@interface RCTNavigator() <RCTWrapperViewControllerNavigationListener, UINavigationControllerDelegate, UIGestureRecognizerDelegate>
-
-@property (nonatomic, copy) RCTDirectEventBlock onNavigationProgress;
-@property (nonatomic, copy) RCTBubblingEventBlock onNavigationComplete;
-
-@property (nonatomic, assign) NSInteger previousRequestedTopOfStack;
-
-@property (nonatomic, assign) RCTPopGestureState popGestureState;
-
-// Previous views are only mainted in order to detect incorrect
-// addition/removal of views below the `requestedTopOfStack`
-@property (nonatomic, copy, readwrite) NSArray<RCTNavItem *> *previousViews;
-@property (nonatomic, readwrite, strong) RCTNavigationController *navigationController;
-/**
- * Display link is used to get high frequency sample rate during
- * interaction/animation of view controller push/pop.
- *
- * - The run loop retains the displayLink.
- * - `displayLink` retains its target.
- * - We use `invalidate` to remove the `RCTNavigator`'s reference to the
- * `displayLink` and remove the `displayLink` from the run loop.
- *
- *
- * `displayLink`:
- * --------------
- *
- * - Even though we could implement the `displayLink` cleanup without the
- * `invalidate` hook by adding and removing it from the run loop at the
- * right times (begin/end animation), we need to account for the possibility
- * that the view itself is destroyed mid-interaction. So we always keep it
- * added to the run loop, but start/stop it with interactions/animations. We
- * remove it from the run loop when the view will be destroyed by React.
- *
- * +----------+ +--------------+
- * | run loop o----strong--->| displayLink |
- * +----------+ +--o-----------+
- * | ^
- * | |
- * strong strong
- * | |
- * v |
- * +---------o---+
- * | RCTNavigator |
- * +-------------+
- *
- * `dummyView`:
- * ------------
- * There's no easy way to get a callback that fires when the position of a
- * navigation item changes. The actual layers that are moved around during the
- * navigation transition are private. Our only hope is to use
- * `animateAlongsideTransition`, to set a dummy view's position to transition
- * anywhere from -1.0 to 1.0. We later set up a `CADisplayLink` to poll the
- * `presentationLayer` of that dummy view and report the value as a "progress"
- * percentage.
- *
- * It was critical that we added the dummy view as a subview of the
- * transitionCoordinator's `containerView`, otherwise the animations would not
- * work correctly when reversing the gesture direction etc. This seems to be
- * undocumented behavior/requirement.
- *
- */
-@property (nonatomic, readonly, assign) CGFloat mostRecentProgress;
-@property (nonatomic, readonly, strong) NSTimer *runTimer;
-@property (nonatomic, readonly, assign) NSInteger currentlyTransitioningFrom;
-@property (nonatomic, readonly, assign) NSInteger currentlyTransitioningTo;
-
-// Dummy view that we make animate with the same curve/interaction as the
-// navigation animation/interaction.
-@property (nonatomic, readonly, strong) UIView *dummyView;
-
-@end
-
-@implementation RCTNavigator
-{
- __weak RCTBridge *_bridge;
- NSInteger _numberOfViewControllerMovesToIgnore;
-}
-
-@synthesize paused = _paused;
-@synthesize pauseCallback = _pauseCallback;
-
-- (instancetype)initWithBridge:(RCTBridge *)bridge
-{
- RCTAssertParam(bridge);
-
- if ((self = [super initWithFrame:CGRectZero])) {
- _paused = YES;
-
- _bridge = bridge;
- _mostRecentProgress = kNeverProgressed;
- _dummyView = [[UIView alloc] initWithFrame:CGRectZero];
- _previousRequestedTopOfStack = kNeverRequested; // So that we initialize with a push.
- _previousViews = @[];
- __weak RCTNavigator *weakSelf = self;
- _navigationController = [[RCTNavigationController alloc] initWithScrollCallback:^{
- [weakSelf dispatchFakeScrollEvent];
- }];
- _navigationController.delegate = self;
- RCTAssert([self requestSchedulingJavaScriptNavigation], @"Could not acquire JS navigation lock on init");
-
- [self addSubview:_navigationController.view];
- [_navigationController.view addSubview:_dummyView];
- }
- return self;
-}
-
-RCT_NOT_IMPLEMENTED(- (instancetype)initWithFrame:(CGRect)frame)
-RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
-
-- (void)didUpdateFrame:(__unused RCTFrameUpdate *)update
-{
- if (_currentlyTransitioningFrom != _currentlyTransitioningTo) {
- UIView *topView = _dummyView;
- id presentationLayer = [topView.layer presentationLayer];
- CGRect frame = [presentationLayer frame];
- CGFloat nextProgress = ABS(frame.origin.x);
- // Don't want to spam the bridge, when the user holds their finger still mid-navigation.
- if (nextProgress == _mostRecentProgress) {
- return;
- }
- _mostRecentProgress = nextProgress;
- if (_onNavigationProgress) {
- _onNavigationProgress(@{
- @"fromIndex": @(_currentlyTransitioningFrom),
- @"toIndex": @(_currentlyTransitioningTo),
- @"progress": @(nextProgress),
- });
- }
- }
-}
-
-- (void)setPaused:(BOOL)paused
-{
- if (_paused != paused) {
- _paused = paused;
- if (_pauseCallback) {
- _pauseCallback();
- }
- }
-}
-
-- (void)setInteractivePopGestureEnabled:(BOOL)interactivePopGestureEnabled
-{
-#if !TARGET_OS_TV
- _interactivePopGestureEnabled = interactivePopGestureEnabled;
-
- _navigationController.interactivePopGestureRecognizer.delegate = self;
- _navigationController.interactivePopGestureRecognizer.enabled = interactivePopGestureEnabled;
-
- _popGestureState = interactivePopGestureEnabled ? RCTPopGestureStateEnabled : RCTPopGestureStateDisabled;
-#endif
-}
-
-- (void)dealloc
-{
-#if !TARGET_OS_TV
- if (_navigationController.interactivePopGestureRecognizer.delegate == self) {
- _navigationController.interactivePopGestureRecognizer.delegate = nil;
- }
-#endif
- _navigationController.delegate = nil;
- [_navigationController removeFromParentViewController];
-}
-
-- (UIViewController *)reactViewController
-{
- return _navigationController;
-}
-
-- (BOOL)gestureRecognizerShouldBegin:(__unused UIGestureRecognizer *)gestureRecognizer
-{
- return _navigationController.viewControllers.count > 1;
-}
-
-/**
- * See documentation about lock lifecycle. This is only here to clean up
- * swipe-back abort interaction, which leaves us *no* other way to clean up
- * locks aside from the animation complete hook.
- */
-- (void)navigationController:(UINavigationController *)navigationController
- willShowViewController:(__unused UIViewController *)viewController
- animated:(__unused BOOL)animated
-{
- id<UIViewControllerTransitionCoordinator> tc =
- navigationController.topViewController.transitionCoordinator;
- __weak RCTNavigator *weakSelf = self;
- [tc.containerView addSubview: _dummyView];
- [tc animateAlongsideTransition: ^(id<UIViewControllerTransitionCoordinatorContext> context) {
- RCTWrapperViewController *fromController =
- (RCTWrapperViewController *)[context viewControllerForKey:UITransitionContextFromViewControllerKey];
- RCTWrapperViewController *toController =
- (RCTWrapperViewController *)[context viewControllerForKey:UITransitionContextToViewControllerKey];
-
- // This may be triggered by a navigation controller unrelated to me: if so, ignore.
- if (fromController.navigationController != self->_navigationController ||
- toController.navigationController != self->_navigationController) {
- return;
- }
-
- NSUInteger indexOfFrom = [self.reactSubviews indexOfObject:fromController.navItem];
- NSUInteger indexOfTo = [self.reactSubviews indexOfObject:toController.navItem];
- CGFloat destination = indexOfFrom < indexOfTo ? 1.0 : -1.0;
- self->_dummyView.frame = (CGRect){{destination, 0}, CGSizeZero};
- self->_currentlyTransitioningFrom = indexOfFrom;
- self->_currentlyTransitioningTo = indexOfTo;
- self.paused = NO;
- }
- completion:^(__unused id<UIViewControllerTransitionCoordinatorContext> context) {
- [weakSelf freeLock];
- self->_currentlyTransitioningFrom = 0;
- self->_currentlyTransitioningTo = 0;
- self->_dummyView.frame = CGRectZero;
- self.paused = YES;
- // Reset the parallel position tracker
- }];
-}
-
-- (BOOL)requestSchedulingJavaScriptNavigation
-{
- if (_navigationController.navigationLock == RCTNavigationLockNone) {
- _navigationController.navigationLock = RCTNavigationLockJavaScript;
-#if !TARGET_OS_TV
- _navigationController.interactivePopGestureRecognizer.enabled = NO;
-#endif
- return YES;
- }
- return NO;
-}
-
-- (void)freeLock
-{
- _navigationController.navigationLock = RCTNavigationLockNone;
-
- // Unless the pop gesture has been explicitly disabled (RCTPopGestureStateDisabled),
- // Set interactivePopGestureRecognizer.enabled to YES
- // If the popGestureState is RCTPopGestureStateDefault the default behavior will be maintained
-#if !TARGET_OS_TV
- _navigationController.interactivePopGestureRecognizer.enabled = self.popGestureState != RCTPopGestureStateDisabled;
-#endif
-}
-
-/**
- * A React subview can be inserted/removed at any time, however if the
- * `requestedTopOfStack` changes, there had better be enough subviews present
- * to satisfy the push/pop.
- */
-- (void)insertReactSubview:(RCTNavItem *)view atIndex:(NSInteger)atIndex
-{
- RCTAssert([view isKindOfClass:[RCTNavItem class]], @"RCTNavigator only accepts RCTNavItem subviews");
- RCTAssert(
- _navigationController.navigationLock == RCTNavigationLockJavaScript,
- @"Cannot change subviews from JS without first locking."
- );
- [super insertReactSubview:view atIndex:atIndex];
-}
-
-- (void)didUpdateReactSubviews
-{
- // Do nothing, as subviews are managed by `uiManagerDidPerformMounting`
-}
-
-- (void)layoutSubviews
-{
- [super layoutSubviews];
- [self reactAddControllerToClosestParent:_navigationController];
- _navigationController.view.frame = self.bounds;
-}
-
-- (void)removeReactSubview:(RCTNavItem *)subview
-{
- if (self.reactSubviews.count <= 0 || subview == self.reactSubviews[0]) {
- RCTLogError(@"Attempting to remove invalid RCT subview of RCTNavigator");
- return;
- }
- [super removeReactSubview:subview];
-}
-
-- (void)handleTopOfStackChanged
-{
- if (_onNavigationComplete) {
- _onNavigationComplete(@{
- @"stackLength":@(_navigationController.viewControllers.count)
- });
- }
-}
-
-- (void)dispatchFakeScrollEvent
-{
- [_bridge.eventDispatcher sendFakeScrollEvent:self.reactTag];
-}
-
-/**
- * Must be overridden because UIKit removes the view's superview when used
- * as a navigator - it's considered outside the view hierarchy.
- */
-- (UIView *)reactSuperview
-{
- RCTAssert(!_bridge.isValid || self.superview != nil, @"put reactNavSuperviewLink back");
- UIView *superview = [super reactSuperview];
- return superview ?: self.reactNavSuperviewLink;
-}
-
-- (void)uiManagerDidPerformMounting
-{
- // we can't hook up the VC hierarchy in 'init' because the subviews aren't
- // hooked up yet, so we do it on demand here
- [self reactAddControllerToClosestParent:_navigationController];
-
- NSUInteger viewControllerCount = _navigationController.viewControllers.count;
- // The "react count" is the count of views that are visible on the navigation
- // stack. There may be more beyond this - that aren't visible, and may be
- // deleted/purged soon.
- NSUInteger previousReactCount =
- _previousRequestedTopOfStack == kNeverRequested ? 0 : _previousRequestedTopOfStack + 1;
- NSUInteger currentReactCount = _requestedTopOfStack + 1;
-
- BOOL jsGettingAhead =
- // ----- previously caught up ------ ------ no longer caught up -------
- viewControllerCount == previousReactCount && currentReactCount != viewControllerCount;
- BOOL jsCatchingUp =
- // --- previously not caught up ---- --------- now caught up ----------
- viewControllerCount != previousReactCount && currentReactCount == viewControllerCount;
- BOOL jsMakingNoProgressButNeedsToCatchUp =
- // --- previously not caught up ---- ------- still the same -----------
- viewControllerCount != previousReactCount && currentReactCount == previousReactCount;
- BOOL jsMakingNoProgressAndDoesntNeedTo =
- // --- previously caught up -------- ------- still caught up ----------
- viewControllerCount == previousReactCount && currentReactCount == previousReactCount;
-
-BOOL jsGettingtooSlow =
- // --- previously not caught up -------- ------- no longer caught up ----------
- viewControllerCount < previousReactCount && currentReactCount < previousReactCount;
-
- BOOL reactPushOne = jsGettingAhead && currentReactCount == previousReactCount + 1;
- BOOL reactPopN = jsGettingAhead && currentReactCount < previousReactCount;
-
- // We can actually recover from this situation, but it would be nice to know
- // when this error happens. This simply means that JS hasn't caught up to a
- // back navigation before progressing. It's likely a bug in the JS code that
- // catches up/schedules navigations.
- if (!(jsGettingAhead ||
- jsCatchingUp ||
- jsMakingNoProgressButNeedsToCatchUp ||
- jsMakingNoProgressAndDoesntNeedTo ||
- jsGettingtooSlow)) {
- RCTLogError(@"JS has only made partial progress to catch up to UIKit");
- }
- if (currentReactCount > self.reactSubviews.count) {
- RCTLogError(@"Cannot adjust current top of stack beyond available views");
- }
-
- // Views before the previous React count must not have changed. Views greater than previousReactCount
- // up to currentReactCount may have changed.
- for (NSUInteger i = 0; i < MIN(self.reactSubviews.count, MIN(_previousViews.count, previousReactCount)); i++) {
- if (self.reactSubviews[i] != _previousViews[i]) {
- RCTLogError(@"current view should equal previous view");
- }
- }
- if (currentReactCount < 1) {
- RCTLogError(@"should be at least one current view");
- }
- if (jsGettingAhead) {
- if (reactPushOne) {
- UIView *lastView = self.reactSubviews.lastObject;
- RCTWrapperViewController *vc = [[RCTWrapperViewController alloc] initWithNavItem:(RCTNavItem *)lastView];
- vc.navigationListener = self;
- _numberOfViewControllerMovesToIgnore = 1;
- [_navigationController pushViewController:vc animated:(currentReactCount > 1)];
- } else if (reactPopN) {
- UIViewController *viewControllerToPopTo = _navigationController.viewControllers[(currentReactCount - 1)];
- _numberOfViewControllerMovesToIgnore = viewControllerCount - currentReactCount;
- [_navigationController popToViewController:viewControllerToPopTo animated:YES];
- } else {
- RCTLogError(@"Pushing or popping more than one view at a time from JS");
- }
- } else if (jsCatchingUp) {
- [self freeLock]; // Nothing to push/pop
- } else {
- // Else, JS making no progress, could have been unrelated to anything nav.
- return;
- }
-
- // Only make a copy of the subviews whose validity we expect to be able to check (in the loop, above),
- // otherwise we would unnecessarily retain a reference to view(s) no longer on the React navigation stack:
- NSUInteger expectedCount = MIN(currentReactCount, self.reactSubviews.count);
- _previousViews = [[self.reactSubviews subarrayWithRange: NSMakeRange(0, expectedCount)] copy];
- _previousRequestedTopOfStack = _requestedTopOfStack;
-}
-
-// TODO: This will likely fail when performing multiple pushes/pops. We must
-// free the lock only after the *last* push/pop.
-- (void)wrapperViewController:(RCTWrapperViewController *)wrapperViewController
-didMoveToNavigationController:(UINavigationController *)navigationController
-{
- if (self.superview == nil) {
- // If superview is nil, then a JS reload (Cmd+R) happened
- // while a push/pop is in progress.
- return;
- }
-
- RCTAssert(
- (navigationController == nil || [_navigationController.viewControllers containsObject:wrapperViewController]),
- @"if navigation controller is not nil, it should contain the wrapper view controller"
- );
- RCTAssert(_navigationController.navigationLock == RCTNavigationLockJavaScript ||
- _numberOfViewControllerMovesToIgnore == 0,
- @"If JS doesn't have the lock there should never be any pending transitions");
- /**
- * When JS has the lock we want to keep track of when the request completes
- * the pending transition count hitting 0 signifies this, and should always
- * remain at 0 when JS does not have the lock
- */
- if (_numberOfViewControllerMovesToIgnore > 0) {
- _numberOfViewControllerMovesToIgnore -= 1;
- }
- if (_numberOfViewControllerMovesToIgnore == 0) {
- [self handleTopOfStackChanged];
- [self freeLock];
- }
-}
-
-@end

React/Views/RCTNavigatorManager.h

@@ -1,12 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#import <React/RCTViewManager.h>
-
-@interface RCTNavigatorManager : RCTViewManager
-
-@end

React/Views/RCTNavigatorManager.m

@@ -1,83 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#import "RCTNavigatorManager.h"
-
-#import "RCTBridge.h"
-#import "RCTConvert.h"
-#import "RCTNavigator.h"
-#import "RCTUIManager.h"
-#import "RCTUIManagerObserverCoordinator.h"
-#import "UIView+React.h"
-
-@interface RCTNavigatorManager () <RCTUIManagerObserver>
-
-@end
-
-@implementation RCTNavigatorManager
-{
- // The main thread only.
- NSHashTable<RCTNavigator *> *_viewRegistry;
-}
-
-- (void)setBridge:(RCTBridge *)bridge
-{
- [super setBridge:bridge];
-
- [self.bridge.uiManager.observerCoordinator addObserver:self];
-}
-
-- (void)invalidate
-{
- [self.bridge.uiManager.observerCoordinator removeObserver:self];
-}
-
-RCT_EXPORT_MODULE()
-
-- (UIView *)view
-{
- if (!_viewRegistry) {
- _viewRegistry = [NSHashTable hashTableWithOptions:NSPointerFunctionsWeakMemory];
- }
-
- RCTNavigator *view = [[RCTNavigator alloc] initWithBridge:self.bridge];
- [_viewRegistry addObject:view];
- return view;
-}
-
-RCT_EXPORT_VIEW_PROPERTY(requestedTopOfStack, NSInteger)
-RCT_EXPORT_VIEW_PROPERTY(onNavigationProgress, RCTDirectEventBlock)
-RCT_EXPORT_VIEW_PROPERTY(onNavigationComplete, RCTBubblingEventBlock)
-RCT_EXPORT_VIEW_PROPERTY(interactivePopGestureEnabled, BOOL)
-
-RCT_EXPORT_METHOD(requestSchedulingJavaScriptNavigation:(nonnull NSNumber *)reactTag
- callback:(RCTResponseSenderBlock)callback)
-{
- [self.bridge.uiManager addUIBlock:
- ^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTNavigator *> *viewRegistry){
- RCTNavigator *navigator = viewRegistry[reactTag];
- if ([navigator isKindOfClass:[RCTNavigator class]]) {
- BOOL wasAcquired = [navigator requestSchedulingJavaScriptNavigation];
- callback(@[@(wasAcquired)]);
- } else {
- RCTLogError(@"Cannot set lock: %@ (tag #%@) is not an RCTNavigator", navigator, reactTag);
- }
- }];
-}
-
-#pragma mark - RCTUIManagerObserver
-
-- (void)uiManagerDidPerformMounting:(__unused RCTUIManager *)manager
-{
- RCTExecuteOnMainQueue(^{
- for (RCTNavigator *view in self->_viewRegistry) {
- [view uiManagerDidPerformMounting];
- }
- });
-}
-
-@end

React/Views/RCTNavItem.h

@@ -1,42 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#import <UIKit/UIKit.h>
-
-#import <React/RCTComponent.h>
-
-@interface RCTNavItem : UIView
-
-@property (nonatomic, copy) NSString *title;
-@property (nonatomic, strong) UIImage *titleImage;
-@property (nonatomic, strong) UIImage *leftButtonIcon;
-@property (nonatomic, copy) NSString *leftButtonTitle;
-@property (nonatomic, assign) UIBarButtonSystemItem leftButtonSystemIcon;
-@property (nonatomic, strong) UIImage *rightButtonIcon;
-@property (nonatomic, copy) NSString *rightButtonTitle;
-@property (nonatomic, assign) UIBarButtonSystemItem rightButtonSystemIcon;
-@property (nonatomic, strong) UIImage *backButtonIcon;
-@property (nonatomic, copy) NSString *backButtonTitle;
-@property (nonatomic, assign) BOOL navigationBarHidden;
-@property (nonatomic, assign) BOOL shadowHidden;
-@property (nonatomic, strong) UIColor *tintColor;
-@property (nonatomic, strong) UIColor *barTintColor;
-@property (nonatomic, strong) UIColor *titleTextColor;
-@property (nonatomic, assign) BOOL translucent;
-#if !TARGET_OS_TV
-@property (nonatomic, assign) UIBarStyle barStyle;
-#endif
-
-@property (nonatomic, readonly) UIImageView *titleImageView;
-@property (nonatomic, readonly) UIBarButtonItem *backButtonItem;
-@property (nonatomic, readonly) UIBarButtonItem *leftButtonItem;
-@property (nonatomic, readonly) UIBarButtonItem *rightButtonItem;
-
-@property (nonatomic, copy) RCTBubblingEventBlock onLeftButtonPress;
-@property (nonatomic, copy) RCTBubblingEventBlock onRightButtonPress;
-
-@end

React/Views/RCTNavItem.m

@@ -1,174 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#import "RCTNavItem.h"
-
-@implementation RCTNavItem
-
-@synthesize backButtonItem = _backButtonItem;
-@synthesize leftButtonItem = _leftButtonItem;
-@synthesize rightButtonItem = _rightButtonItem;
-
-- (UIImageView *)titleImageView
-{
- if (_titleImage) {
- return [[UIImageView alloc] initWithImage:_titleImage];
- } else {
- return nil;
- }
-}
-
--(instancetype)init
-{
- if (self = [super init]) {
- _leftButtonSystemIcon = NSNotFound;
- _rightButtonSystemIcon = NSNotFound;
- }
- return self;
-}
-
-- (void)setBackButtonTitle:(NSString *)backButtonTitle
-{
- _backButtonTitle = backButtonTitle;
- _backButtonItem = nil;
-}
-
-- (void)setBackButtonIcon:(UIImage *)backButtonIcon
-{
- _backButtonIcon = backButtonIcon;
- _backButtonItem = nil;
-}
-
-- (UIBarButtonItem *)backButtonItem
-{
- if (!_backButtonItem) {
- if (_backButtonIcon) {
- _backButtonItem = [[UIBarButtonItem alloc] initWithImage:_backButtonIcon
- style:UIBarButtonItemStylePlain
- target:nil
- action:nil];
- } else if (_backButtonTitle.length) {
- _backButtonItem = [[UIBarButtonItem alloc] initWithTitle:_backButtonTitle
- style:UIBarButtonItemStylePlain
- target:nil
- action:nil];
- } else {
- _backButtonItem = nil;
- }
- }
- return _backButtonItem;
-}
-
-- (void)setLeftButtonTitle:(NSString *)leftButtonTitle
-{
- _leftButtonTitle = leftButtonTitle;
- _leftButtonItem = nil;
-}
-
-- (void)setLeftButtonIcon:(UIImage *)leftButtonIcon
-{
- _leftButtonIcon = leftButtonIcon;
- _leftButtonItem = nil;
-}
-
-- (void)setLeftButtonSystemIcon:(UIBarButtonSystemItem)leftButtonSystemIcon
-{
- _leftButtonSystemIcon = leftButtonSystemIcon;
- _leftButtonItem = nil;
-}
-
-- (UIBarButtonItem *)leftButtonItem
-{
- if (!_leftButtonItem) {
- if (_leftButtonIcon) {
- _leftButtonItem =
- [[UIBarButtonItem alloc] initWithImage:_leftButtonIcon
- style:UIBarButtonItemStylePlain
- target:self
- action:@selector(handleLeftButtonPress)];
-
- } else if (_leftButtonTitle.length) {
- _leftButtonItem =
- [[UIBarButtonItem alloc] initWithTitle:_leftButtonTitle
- style:UIBarButtonItemStylePlain
- target:self
- action:@selector(handleLeftButtonPress)];
-
- } else if (_leftButtonSystemIcon != NSNotFound) {
- _leftButtonItem =
- [[UIBarButtonItem alloc] initWithBarButtonSystemItem:_leftButtonSystemIcon
- target:self
- action:@selector(handleLeftButtonPress)];
- } else {
- _leftButtonItem = nil;
- }
- }
- return _leftButtonItem;
-}
-
-- (void)handleLeftButtonPress
-{
- if (_onLeftButtonPress) {
- _onLeftButtonPress(nil);
- }
-}
-
-- (void)setRightButtonTitle:(NSString *)rightButtonTitle
-{
- _rightButtonTitle = rightButtonTitle;
- _rightButtonItem = nil;
-}
-
-- (void)setRightButtonIcon:(UIImage *)rightButtonIcon
-{
- _rightButtonIcon = rightButtonIcon;
- _rightButtonItem = nil;
-}
-
-- (void)setRightButtonSystemIcon:(UIBarButtonSystemItem)rightButtonSystemIcon
-{
- _rightButtonSystemIcon = rightButtonSystemIcon;
- _rightButtonItem = nil;
-}
-
-- (UIBarButtonItem *)rightButtonItem
-{
- if (!_rightButtonItem) {
- if (_rightButtonIcon) {
- _rightButtonItem =
- [[UIBarButtonItem alloc] initWithImage:_rightButtonIcon
- style:UIBarButtonItemStylePlain
- target:self
- action:@selector(handleRightButtonPress)];
-
- } else if (_rightButtonTitle.length) {
- _rightButtonItem =
- [[UIBarButtonItem alloc] initWithTitle:_rightButtonTitle
- style:UIBarButtonItemStylePlain
- target:self
- action:@selector(handleRightButtonPress)];
-
- } else if (_rightButtonSystemIcon != NSNotFound) {
- _rightButtonItem =
- [[UIBarButtonItem alloc] initWithBarButtonSystemItem:_rightButtonSystemIcon
- target:self
- action:@selector(handleRightButtonPress)];
- } else {
- _rightButtonItem = nil;
- }
- }
- return _rightButtonItem;
-}
-
-- (void)handleRightButtonPress
-{
- if (_onRightButtonPress) {
- _onRightButtonPress(nil);
- }
-}
-
-@end

React/Views/RCTNavItemManager.h

@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#import <React/RCTConvert.h>
-#import <React/RCTViewManager.h>
-
-@interface RCTConvert (BarButtonSystemItem)
-
-+ (UIBarButtonSystemItem)UIBarButtonSystemItem:(id)json;
-
-@end
-
-@interface RCTNavItemManager : RCTViewManager
-
-@end

React/Views/RCTNavItemManager.m

@@ -1,80 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#import "RCTNavItemManager.h"
-
-#import "RCTConvert.h"
-#import "RCTNavItem.h"
-
-@implementation RCTConvert (BarButtonSystemItem)
-
-RCT_ENUM_CONVERTER(UIBarButtonSystemItem, (@{
- @"done": @(UIBarButtonSystemItemDone),
- @"cancel": @(UIBarButtonSystemItemCancel),
- @"edit": @(UIBarButtonSystemItemEdit),
- @"save": @(UIBarButtonSystemItemSave),
- @"add": @(UIBarButtonSystemItemAdd),
- @"flexible-space": @(UIBarButtonSystemItemFlexibleSpace),
- @"fixed-space": @(UIBarButtonSystemItemFixedSpace),
- @"compose": @(UIBarButtonSystemItemCompose),
- @"reply": @(UIBarButtonSystemItemReply),
- @"action": @(UIBarButtonSystemItemAction),
- @"organize": @(UIBarButtonSystemItemOrganize),
- @"bookmarks": @(UIBarButtonSystemItemBookmarks),
- @"search": @(UIBarButtonSystemItemSearch),
- @"refresh": @(UIBarButtonSystemItemRefresh),
- @"stop": @(UIBarButtonSystemItemStop),
- @"camera": @(UIBarButtonSystemItemCamera),
- @"trash": @(UIBarButtonSystemItemTrash),
- @"play": @(UIBarButtonSystemItemPlay),
- @"pause": @(UIBarButtonSystemItemPause),
- @"rewind": @(UIBarButtonSystemItemRewind),
- @"fast-forward": @(UIBarButtonSystemItemFastForward),
- @"undo": @(UIBarButtonSystemItemUndo),
- @"redo": @(UIBarButtonSystemItemRedo),
- @"page-curl": @(UIBarButtonSystemItemPageCurl)
-}), NSNotFound, integerValue);
-
-@end
-
-@implementation RCTNavItemManager
-
-RCT_EXPORT_MODULE()
-
-- (UIView *)view
-{
- return [RCTNavItem new];
-}
-
-RCT_EXPORT_VIEW_PROPERTY(navigationBarHidden, BOOL)
-RCT_EXPORT_VIEW_PROPERTY(shadowHidden, BOOL)
-RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
-RCT_EXPORT_VIEW_PROPERTY(barTintColor, UIColor)
-#if !TARGET_OS_TV
-RCT_EXPORT_VIEW_PROPERTY(barStyle, UIBarStyle)
-#endif
-RCT_EXPORT_VIEW_PROPERTY(translucent, BOOL)
-
-RCT_EXPORT_VIEW_PROPERTY(title, NSString)
-RCT_EXPORT_VIEW_PROPERTY(titleTextColor, UIColor)
-RCT_EXPORT_VIEW_PROPERTY(titleImage, UIImage)
-
-RCT_EXPORT_VIEW_PROPERTY(backButtonIcon, UIImage)
-RCT_EXPORT_VIEW_PROPERTY(backButtonTitle, NSString)
-
-RCT_EXPORT_VIEW_PROPERTY(leftButtonTitle, NSString)
-RCT_EXPORT_VIEW_PROPERTY(leftButtonIcon, UIImage)
-RCT_EXPORT_VIEW_PROPERTY(leftButtonSystemIcon, UIBarButtonSystemItem)
-
-RCT_EXPORT_VIEW_PROPERTY(rightButtonIcon, UIImage)
-RCT_EXPORT_VIEW_PROPERTY(rightButtonTitle, NSString)
-RCT_EXPORT_VIEW_PROPERTY(rightButtonSystemIcon, UIBarButtonSystemItem)
-
-RCT_EXPORT_VIEW_PROPERTY(onLeftButtonPress, RCTBubblingEventBlock)
-RCT_EXPORT_VIEW_PROPERTY(onRightButtonPress, RCTBubblingEventBlock)
-
-@end

React/Views/RCTPicker.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTPicker.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTPickerManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTPickerManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTPointerEvents.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTProgressViewManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTProgressViewManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTRefreshControl.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTRefreshControl.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -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 @@
- (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 @@
animations:^(void) {
[scrollView setContentOffset:offset];
} completion:^(__unused BOOL finished) {
+ if(beginRefreshingTimestamp == self->_currentRefreshingStateTimestamp) {
[super beginRefreshing];
+ [self setCurrentRefreshingState:super.refreshing];
+ }
}];
}
@@ -72,6 +80,7 @@
// 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 @@
animations:^(void) {
[scrollView setContentOffset:offset];
} completion:^(__unused BOOL finished) {
+ if(endRefreshingTimestamp == self->_currentRefreshingStateTimestamp) {
[super endRefreshing];
+ [self setCurrentRefreshingState:super.refreshing];
+ }
}];
} else {
[super endRefreshing];
@@ -120,7 +132,7 @@
- (void)setRefreshing:(BOOL)refreshing
{
if (_currentRefreshingState != refreshing) {
- _currentRefreshingState = refreshing;
+ [self setCurrentRefreshingState:refreshing];
if (refreshing) {
if (!_isInitialRender) {
@@ -132,9 +144,15 @@
}
}
+- (void)setCurrentRefreshingState:(BOOL)refreshing
+{
+ _currentRefreshingState = refreshing;
+ _currentRefreshingStateTimestamp = _currentRefreshingStateClock++;
+}
+
- (void)refreshControlValueChanged
{
- _currentRefreshingState = super.refreshing;
+ [self setCurrentRefreshingState:super.refreshing];
_refreshingProgrammatically = NO;
if (_onRefresh) {

React/Views/RCTRefreshControlManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTRefreshControlManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTRootShadowView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTRootShadowView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTSegmentedControl.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTSegmentedControl.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTSegmentedControlManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTSegmentedControlManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTShadowView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTShadowView+Internal.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTShadowView+Internal.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTShadowView+Layout.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTShadowView+Layout.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTShadowView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTSlider.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTSlider.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTSliderManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTSliderManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -83,6 +83,7 @@
RCT_EXPORT_VIEW_PROPERTY(maximumTrackTintColor, UIColor);
RCT_EXPORT_VIEW_PROPERTY(onValueChange, RCTBubblingEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onSlidingComplete, RCTBubblingEventBlock);
+RCT_EXPORT_VIEW_PROPERTY(thumbTintColor, UIColor);
RCT_EXPORT_VIEW_PROPERTY(thumbImage, UIImage);
RCT_CUSTOM_VIEW_PROPERTY(disabled, BOOL, RCTSlider)
{

React/Views/RCTSwitch.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTSwitch.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTSwitchManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTSwitchManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -48,5 +48,8 @@
view.enabled = defaultView.enabled;
}
}
+RCT_REMAP_VIEW_PROPERTY(thumbColor, thumbTintColor, UIColor);
+RCT_REMAP_VIEW_PROPERTY(trackColorForFalse, tintColor, UIColor);
+RCT_REMAP_VIEW_PROPERTY(trackColorForTrue, onTintColor, UIColor);
@end

React/Views/RCTTabBar.h

@@ -1,22 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#import <UIKit/UIKit.h>
-
-@interface RCTTabBar : UIView
-
-@property (nonatomic, strong) UIColor *unselectedTintColor;
-@property (nonatomic, strong) UIColor *tintColor;
-@property (nonatomic, strong) UIColor *barTintColor;
-@property (nonatomic, assign) BOOL translucent;
-#if !TARGET_OS_TV
-@property (nonatomic, assign) UIBarStyle barStyle;
-#endif
-
-- (void)uiManagerDidPerformMounting;
-
-@end

React/Views/RCTTabBarItem.h

@@ -1,35 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#import <UIKit/UIKit.h>
-
-#import <React/RCTComponent.h>
-#import <React/RCTConvert.h>
-
-@interface RCTConvert (UITabBarSystemItem)
-
-+ (UITabBarSystemItem)UITabBarSystemItem:(id)json;
-
-@end
-
-@interface RCTTabBarItem : UIView
-
-@property (nonatomic, copy) id /* NSString or NSNumber */ badge;
-@property (nonatomic, strong) UIImage *icon;
-@property (nonatomic, strong) UIImage *selectedIcon;
-@property (nonatomic, assign) UITabBarSystemItem systemIcon;
-@property (nonatomic, assign) BOOL renderAsOriginal;
-@property (nonatomic, assign, getter=isSelected) BOOL selected;
-@property (nonatomic, readonly) UITabBarItem *barItem;
-@property (nonatomic, copy) RCTBubblingEventBlock onPress;
-@property (nonatomic, strong) NSString *testID;
-
-#if TARGET_OS_TV
-@property (nonatomic, assign) BOOL wasSelectedInJS;
-#endif
-
-@end

React/Views/RCTTabBarItem.m

@@ -1,139 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#import "RCTTabBarItem.h"
-
-#import "RCTConvert.h"
-#import "RCTLog.h"
-#import "UIView+React.h"
-
-@implementation RCTConvert (UITabBarSystemItem)
-
-RCT_ENUM_CONVERTER(UITabBarSystemItem, (@{
- @"bookmarks": @(UITabBarSystemItemBookmarks),
- @"contacts": @(UITabBarSystemItemContacts),
- @"downloads": @(UITabBarSystemItemDownloads),
- @"favorites": @(UITabBarSystemItemFavorites),
- @"featured": @(UITabBarSystemItemFeatured),
- @"history": @(UITabBarSystemItemHistory),
- @"more": @(UITabBarSystemItemMore),
- @"most-recent": @(UITabBarSystemItemMostRecent),
- @"most-viewed": @(UITabBarSystemItemMostViewed),
- @"recents": @(UITabBarSystemItemRecents),
- @"search": @(UITabBarSystemItemSearch),
- @"top-rated": @(UITabBarSystemItemTopRated),
-}), NSNotFound, integerValue)
-
-@end
-
-@implementation RCTTabBarItem{
- UITapGestureRecognizer *_selectRecognizer;
-}
-
-@synthesize barItem = _barItem;
-
-- (instancetype)initWithFrame:(CGRect)frame
-{
- if ((self = [super initWithFrame:frame])) {
- _systemIcon = NSNotFound;
-#if TARGET_OS_TV
- _wasSelectedInJS = NO;
-#endif
- }
- return self;
-}
-
-- (UITabBarItem *)barItem
-{
- if (!_barItem) {
- _barItem = [UITabBarItem new];
- _systemIcon = NSNotFound;
- }
- return _barItem;
-}
-
-- (void)setTestID:(NSString *)testID
-{
- self.barItem.accessibilityIdentifier = testID;
-}
-
-- (void)setBadge:(id)badge
-{
- _badge = [badge copy];
- self.barItem.badgeValue = [badge description];
-}
-
-- (void)setSystemIcon:(UITabBarSystemItem)systemIcon
-{
- if (_systemIcon != systemIcon) {
- _systemIcon = systemIcon;
- UITabBarItem *oldItem = _barItem;
- _barItem = [[UITabBarItem alloc] initWithTabBarSystemItem:_systemIcon
- tag:oldItem.tag];
- _barItem.title = oldItem.title;
- _barItem.imageInsets = oldItem.imageInsets;
- _barItem.badgeValue = oldItem.badgeValue;
- }
-}
-
-- (void)setIcon:(UIImage *)icon
-{
- _icon = icon;
- if (_icon && _systemIcon != NSNotFound) {
- _systemIcon = NSNotFound;
- UITabBarItem *oldItem = _barItem;
- _barItem = [UITabBarItem new];
- _barItem.title = oldItem.title;
- _barItem.imageInsets = oldItem.imageInsets;
- _barItem.selectedImage = oldItem.selectedImage;
- _barItem.badgeValue = oldItem.badgeValue;
- }
-
- if (_renderAsOriginal) {
- self.barItem.image = [_icon imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
- } else {
- self.barItem.image = _icon;
- }
-}
-
-- (void)setSelectedIcon:(UIImage *)selectedIcon
-{
- _selectedIcon = selectedIcon;
-
- if (_renderAsOriginal) {
- self.barItem.selectedImage = [_selectedIcon imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
- } else {
- self.barItem.selectedImage = _selectedIcon;
- }
-}
-
-- (void)setBadgeColor:(UIColor *)badgeColor
-{
- // badgeColor available since iOS 10
- if ([self.barItem respondsToSelector:@selector(badgeColor)]) {
- self.barItem.badgeColor = badgeColor;
- }
-}
-
-- (UIViewController *)reactViewController
-{
- return self.superview.reactViewController;
-}
-
-#if TARGET_OS_TV
-
-// On Apple TV, we let native control the tab bar selection after initial render
-- (void)setSelected:(BOOL)selected
-{
- if (!_wasSelectedInJS) {
- _selected = selected;
- }
-}
-
-#endif
-
-@end

React/Views/RCTTabBarItemManager.h

@@ -1,12 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#import <React/RCTViewManager.h>
-
-@interface RCTTabBarItemManager : RCTViewManager
-
-@end

React/Views/RCTTabBarItemManager.m

@@ -1,38 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#import "RCTTabBarItemManager.h"
-
-#import "RCTConvert.h"
-#import "RCTTabBarItem.h"
-
-@implementation RCTTabBarItemManager
-
-RCT_EXPORT_MODULE()
-
-- (UIView *)view
-{
- return [RCTTabBarItem new];
-}
-
-RCT_EXPORT_VIEW_PROPERTY(badge, id /* NSString or NSNumber */)
-RCT_EXPORT_VIEW_PROPERTY(renderAsOriginal, BOOL)
-RCT_EXPORT_VIEW_PROPERTY(selected, BOOL)
-RCT_EXPORT_VIEW_PROPERTY(icon, UIImage)
-RCT_EXPORT_VIEW_PROPERTY(selectedIcon, UIImage)
-RCT_EXPORT_VIEW_PROPERTY(systemIcon, UITabBarSystemItem)
-RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)
-RCT_EXPORT_VIEW_PROPERTY(badgeColor, UIColor)
-RCT_EXPORT_VIEW_PROPERTY(isTVSelectable, BOOL)
-RCT_EXPORT_VIEW_PROPERTY(testID, NSString)
-RCT_CUSTOM_VIEW_PROPERTY(title, NSString, RCTTabBarItem)
-{
- view.barItem.title = json ? [RCTConvert NSString:json] : defaultView.barItem.title;
- view.barItem.imageInsets = view.barItem.title.length ? UIEdgeInsetsZero : (UIEdgeInsets){6, 0, -6, 0};
-}
-
-@end

React/Views/RCTTabBar.m

@@ -1,237 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#import "RCTTabBar.h"
-
-#import "RCTEventDispatcher.h"
-#import "RCTLog.h"
-#import "RCTTabBarItem.h"
-#import "RCTUtils.h"
-#import "RCTView.h"
-#import "RCTWrapperViewController.h"
-#import "UIView+React.h"
-
-@interface RCTTabBar() <UITabBarControllerDelegate>
-
-@end
-
-@implementation RCTTabBar
-{
- BOOL _tabsChanged;
- UITabBarController *_tabController;
-}
-
-- (instancetype)initWithFrame:(CGRect)frame
-{
- if ((self = [super initWithFrame:frame])) {
- _tabController = [UITabBarController new];
- _tabController.delegate = self;
- [self addSubview:_tabController.view];
- }
- return self;
-}
-
-RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
-
-- (UIViewController *)reactViewController
-{
- return _tabController;
-}
-
-- (void)dealloc
-{
- _tabController.delegate = nil;
- [_tabController removeFromParentViewController];
-}
-
-- (void)insertReactSubview:(RCTTabBarItem *)subview atIndex:(NSInteger)atIndex
-{
- if (![subview isKindOfClass:[RCTTabBarItem class]]) {
- RCTLogError(@"subview should be of type RCTTabBarItem");
- return;
- }
- [super insertReactSubview:subview atIndex:atIndex];
- _tabsChanged = YES;
-}
-
-- (void)removeReactSubview:(RCTTabBarItem *)subview
-{
- if (self.reactSubviews.count == 0) {
- RCTLogError(@"should have at least one view to remove a subview");
- return;
- }
- [super removeReactSubview:subview];
- _tabsChanged = YES;
-}
-
-- (void)didUpdateReactSubviews
-{
- // Do nothing, as subviews are managed by `uiManagerDidPerformMounting`
-}
-
-- (void)layoutSubviews
-{
- [super layoutSubviews];
- [self reactAddControllerToClosestParent:_tabController];
- _tabController.view.frame = self.bounds;
-}
-
-- (void)uiManagerDidPerformMounting
-{
- // we can't hook up the VC hierarchy in 'init' because the subviews aren't
- // hooked up yet, so we do it on demand here whenever a transaction has finished
- [self reactAddControllerToClosestParent:_tabController];
-
- if (_tabsChanged) {
-
- NSMutableArray<UIViewController *> *viewControllers = [NSMutableArray array];
- for (RCTTabBarItem *tab in [self reactSubviews]) {
- UIViewController *controller = tab.reactViewController;
- if (!controller) {
- controller = [[RCTWrapperViewController alloc] initWithContentView:tab];
- }
- [viewControllers addObject:controller];
- }
-
- _tabController.viewControllers = viewControllers;
- _tabsChanged = NO;
- }
-
- [self.reactSubviews enumerateObjectsUsingBlock:^(UIView *view, NSUInteger index, __unused BOOL *stop) {
-
- RCTTabBarItem *tab = (RCTTabBarItem *)view;
- UIViewController *controller = self->_tabController.viewControllers[index];
- if (self->_unselectedTintColor) {
- [tab.barItem setTitleTextAttributes:@{NSForegroundColorAttributeName: self->_unselectedTintColor} forState:UIControlStateNormal];
- }
-
- [tab.barItem setTitleTextAttributes:@{NSForegroundColorAttributeName: self.tintColor} forState:UIControlStateSelected];
-
- controller.tabBarItem = tab.barItem;
-#if TARGET_OS_TV
-// On Apple TV, disable JS control of selection after initial render
- if (tab.selected && !tab.wasSelectedInJS) {
- self->_tabController.selectedViewController = controller;
- }
- tab.wasSelectedInJS = YES;
-#else
- if (tab.selected) {
- self->_tabController.selectedViewController = controller;
- }
-#endif
- }];
-}
-
-- (UIColor *)barTintColor
-{
- return _tabController.tabBar.barTintColor;
-}
-
-- (void)setBarTintColor:(UIColor *)barTintColor
-{
- _tabController.tabBar.barTintColor = barTintColor;
-}
-
-- (UIColor *)tintColor
-{
- return _tabController.tabBar.tintColor;
-}
-
-- (void)setTintColor:(UIColor *)tintColor
-{
- _tabController.tabBar.tintColor = tintColor;
-}
-
-- (BOOL)translucent
-{
- return _tabController.tabBar.isTranslucent;
-}
-
-- (void)setTranslucent:(BOOL)translucent
-{
- _tabController.tabBar.translucent = translucent;
-}
-
-#if !TARGET_OS_TV
-- (UIBarStyle)barStyle
-{
- return _tabController.tabBar.barStyle;
-}
-
-- (void)setBarStyle:(UIBarStyle)barStyle
-{
- _tabController.tabBar.barStyle = barStyle;
-}
-#endif
-
-- (void)setUnselectedItemTintColor:(UIColor *)unselectedItemTintColor {
-#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
- if ([_tabController.tabBar respondsToSelector:@selector(unselectedItemTintColor)]) {
- _tabController.tabBar.unselectedItemTintColor = unselectedItemTintColor;
- }
-#endif
-}
-
-- (UITabBarItemPositioning)itemPositioning
-{
-#if TARGET_OS_TV
- return 0;
-#else
- return _tabController.tabBar.itemPositioning;
-#endif
-}
-
-- (void)setItemPositioning:(UITabBarItemPositioning)itemPositioning
-{
-#if !TARGET_OS_TV
- _tabController.tabBar.itemPositioning = itemPositioning;
-#endif
-}
-
-#pragma mark - UITabBarControllerDelegate
-
-#if TARGET_OS_TV
-
-- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(nonnull UIViewController *)viewController
-{
- NSUInteger index = [tabBarController.viewControllers indexOfObject:viewController];
- RCTTabBarItem *tab = (RCTTabBarItem *)self.reactSubviews[index];
- if (tab.onPress) tab.onPress(nil);
- return;
-}
-
-#else
-
-- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
-{
- NSUInteger index = [tabBarController.viewControllers indexOfObject:viewController];
- RCTTabBarItem *tab = (RCTTabBarItem *)self.reactSubviews[index];
- if (tab.onPress) tab.onPress(nil);
- return NO;
-}
-
-#endif
-
-#if TARGET_OS_TV
-
-- (BOOL)isUserInteractionEnabled
-{
- return YES;
-}
-
-- (void)didUpdateFocusInContext:(UIFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator
-{
- if (context.nextFocusedView == self) {
- [self becomeFirstResponder];
- } else {
- [self resignFirstResponder];
- }
-}
-
-#endif
-
-@end

React/Views/RCTTabBarManager.h

@@ -1,12 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#import <React/RCTViewManager.h>
-
-@interface RCTTabBarManager : RCTViewManager
-
-@end

React/Views/RCTTabBarManager.m

@@ -1,81 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#import "RCTTabBarManager.h"
-
-#import "RCTBridge.h"
-#import "RCTTabBar.h"
-#import "RCTUIManager.h"
-#import "RCTUIManagerObserverCoordinator.h"
-
-@implementation RCTConvert (UITabBar)
-
-RCT_ENUM_CONVERTER(UITabBarItemPositioning, (@{
- @"fill" : @(UITabBarItemPositioningFill),
- @"auto" : @(UITabBarItemPositioningAutomatic),
- @"center" : @(UITabBarItemPositioningCentered)
-}), UITabBarItemPositioningAutomatic, integerValue)
-
-@end
-
-@interface RCTTabBarManager () <RCTUIManagerObserver>
-
-@end
-
-@implementation RCTTabBarManager
-{
- // The main thread only.
- NSHashTable<RCTTabBar *> *_viewRegistry;
-}
-
-- (void)setBridge:(RCTBridge *)bridge
-{
- [super setBridge:bridge];
-
- [self.bridge.uiManager.observerCoordinator addObserver:self];
-}
-
-- (void)invalidate
-{
- [self.bridge.uiManager.observerCoordinator removeObserver:self];
-}
-
-RCT_EXPORT_MODULE()
-
-- (UIView *)view
-{
- if (!_viewRegistry) {
- _viewRegistry = [NSHashTable hashTableWithOptions:NSPointerFunctionsWeakMemory];
- }
-
- RCTTabBar *view = [RCTTabBar new];
- [_viewRegistry addObject:view];
- return view;
-}
-
-RCT_EXPORT_VIEW_PROPERTY(unselectedTintColor, UIColor)
-RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
-RCT_EXPORT_VIEW_PROPERTY(barTintColor, UIColor)
-RCT_EXPORT_VIEW_PROPERTY(translucent, BOOL)
-#if !TARGET_OS_TV
-RCT_EXPORT_VIEW_PROPERTY(barStyle, UIBarStyle)
-#endif
-RCT_EXPORT_VIEW_PROPERTY(itemPositioning, UITabBarItemPositioning)
-RCT_EXPORT_VIEW_PROPERTY(unselectedItemTintColor, UIColor)
-
-#pragma mark - RCTUIManagerObserver
-
-- (void)uiManagerDidPerformMounting:(__unused RCTUIManager *)manager
-{
- RCTExecuteOnMainQueue(^{
- for (RCTTabBar *view in self->_viewRegistry) {
- [view uiManagerDidPerformMounting];
- }
- });
-}
-
-@end

React/Views/RCTTextDecorationLineType.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTTVView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTTVView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -237,7 +237,6 @@
rootview = [rootview superview];
- [(RCTRootView *)rootview setReactPreferredFocusedView:self];
[rootview setNeedsFocusUpdate];
[rootview updateFocusIfNeeded];
});

React/Views/RCTView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -24,6 +24,7 @@
@property (nonatomic, copy) RCTDirectEventBlock onAccessibilityAction;
@property (nonatomic, copy) RCTDirectEventBlock onAccessibilityTap;
@property (nonatomic, copy) RCTDirectEventBlock onMagicTap;
+@property (nonatomic, copy) RCTDirectEventBlock onAccessibilityEscape;
/**
* Accessibility properties

React/Views/RCTView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -284,6 +284,16 @@
}
}
+- (BOOL)accessibilityPerformEscape
+{
+ if (_onAccessibilityEscape) {
+ _onAccessibilityEscape(nil);
+ return YES;
+ } else {
+ return NO;
+ }
+}
+
- (NSString *)description
{
NSString *superDescription = super.description;
@@ -655,8 +665,8 @@
CGRectMake(
insets.left / size.width,
insets.top / size.height,
- 1.0 / size.width,
- 1.0 / size.height
+ (CGFloat)1.0 / size.width,
+ (CGFloat)1.0 / size.height
);
});

React/Views/RCTViewManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTViewManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -109,7 +109,7 @@
// Acessibility related properties
RCT_REMAP_VIEW_PROPERTY(accessible, reactAccessibilityElement.isAccessibilityElement, BOOL)
-RCT_REMAP_VIEW_PROPERTY(accessibilityActions, reactAccessibilityElement.accessibilityActions, NSString)
+RCT_REMAP_VIEW_PROPERTY(accessibilityActions, reactAccessibilityElement.accessibilityActions, NSArray<NSString *>)
RCT_REMAP_VIEW_PROPERTY(accessibilityLabel, reactAccessibilityElement.accessibilityLabel, NSString)
RCT_REMAP_VIEW_PROPERTY(accessibilityHint, reactAccessibilityElement.accessibilityHint, NSString)
RCT_REMAP_VIEW_PROPERTY(accessibilityTraits, reactAccessibilityElement.accessibilityTraits, UIAccessibilityTraits)
@@ -119,6 +119,7 @@
RCT_REMAP_VIEW_PROPERTY(onAccessibilityAction, reactAccessibilityElement.onAccessibilityAction, RCTDirectEventBlock)
RCT_REMAP_VIEW_PROPERTY(onAccessibilityTap, reactAccessibilityElement.onAccessibilityTap, RCTDirectEventBlock)
RCT_REMAP_VIEW_PROPERTY(onMagicTap, reactAccessibilityElement.onMagicTap, RCTDirectEventBlock)
+RCT_REMAP_VIEW_PROPERTY(onAccessibilityEscape, reactAccessibilityElement.onAccessibilityEscape, RCTDirectEventBlock)
RCT_REMAP_VIEW_PROPERTY(testID, reactAccessibilityElement.accessibilityIdentifier, NSString)
RCT_EXPORT_VIEW_PROPERTY(backgroundColor, UIColor)
@@ -151,7 +152,7 @@
RCT_CUSTOM_VIEW_PROPERTY(accessibilityRole, UIAccessibilityTraits, RCTView)
{
- // This mask must be kept in sync with the AccessibilityRoles enum defined in ViewAccessibility.js
+ // This mask must be kept in sync with the AccessibilityRoles enum defined in ViewAccessibility.js and DeprecatedViewAccessibility.js
const UIAccessibilityTraits AccessibilityRolesMask = UIAccessibilityTraitNone | UIAccessibilityTraitButton | UIAccessibilityTraitLink | UIAccessibilityTraitSearchField | UIAccessibilityTraitImage | UIAccessibilityTraitKeyboardKey | UIAccessibilityTraitStaticText | UIAccessibilityTraitAdjustable | UIAccessibilityTraitHeader | UIAccessibilityTraitSummaryElement;
UIAccessibilityTraits newTraits = json ? [RCTConvert UIAccessibilityTraits:json] : defaultView.accessibilityTraits;
@@ -161,7 +162,7 @@
RCT_CUSTOM_VIEW_PROPERTY(accessibilityStates, UIAccessibilityTraits, RCTView)
{
- // This mask must be kept in sync with the AccessibilityStates enum defined in ViewAccessibility.js
+ // This mask must be kept in sync with the AccessibilityStates enum defined in ViewAccessibility.js and DeprecatedViewAccessibility.js
const UIAccessibilityTraits AccessibilityStatesMask = UIAccessibilityTraitNotEnabled | UIAccessibilityTraitSelected;
UIAccessibilityTraits newTraits = json ? [RCTConvert UIAccessibilityTraits:json] : defaultView.accessibilityTraits;

React/Views/RCTWebView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTWebView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -247,7 +247,7 @@
if (isJSNavigation && [request.URL.host isEqualToString:kPostMessageHost]) {
NSString *data = request.URL.query;
data = [data stringByReplacingOccurrencesOfString:@"+" withString:@" "];
- data = [data stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+ data = [data stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet];
NSMutableDictionary<NSString *, id> *event = [self baseEvent];
[event addEntriesFromDictionary: @{

React/Views/RCTWebViewManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTWebViewManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTWKWebView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -36,6 +36,7 @@
@property (nonatomic, assign) UIEdgeInsets contentInset;
@property (nonatomic, assign) BOOL automaticallyAdjustContentInsets;
++ (void)setClientAuthenticationCredential:(nullable NSURLCredential*)credential;
- (void)postMessage:(NSString *)message;
- (void)injectJavaScript:(NSString *)script;
- (void)goForward;

React/Views/RCTWKWebView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,6 +10,8 @@
#import "RCTAutoInsetsProtocol.h"
static NSString *const MessageHanderName = @"ReactNative";
+static NSURLCredential* clientAuthenticationCredential;
+
@interface RCTWKWebView () <WKUIDelegate, WKNavigationDelegate, WKScriptMessageHandler, UIScrollViewDelegate, RCTAutoInsetsProtocol>
@property (nonatomic, copy) RCTDirectEventBlock onLoadingStart;
@@ -312,6 +314,25 @@
[self setBackgroundColor: _savedBackgroundColor];
}
++ (void)setClientAuthenticationCredential:(nullable NSURLCredential*)credential {
+ clientAuthenticationCredential = credential;
+}
+
+- (void) webView:(WKWebView *)webView
+ didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
+ completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable))completionHandler
+{
+ if (!clientAuthenticationCredential) {
+ completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
+ return;
+ }
+ if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodClientCertificate) {
+ completionHandler(NSURLSessionAuthChallengeUseCredential, clientAuthenticationCredential);
+ } else {
+ completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
+}
+}
+
- (void)evaluateJS:(NSString *)js
thenCall: (void (^)(NSString*)) callback
{

React/Views/RCTWKWebViewManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTWKWebViewManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/RCTWrapperViewController.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,22 +7,10 @@
#import <UIKit/UIKit.h>
-@class RCTNavItem;
@class RCTWrapperViewController;
-@protocol RCTWrapperViewControllerNavigationListener <NSObject>
-
-- (void)wrapperViewController:(RCTWrapperViewController *)wrapperViewController
-didMoveToNavigationController:(UINavigationController *)navigationController;
-
-@end
-
@interface RCTWrapperViewController : UIViewController
- (instancetype)initWithContentView:(UIView *)contentView NS_DESIGNATED_INITIALIZER;
-- (instancetype)initWithNavItem:(RCTNavItem *)navItem;
-
-@property (nonatomic, weak) id<RCTWrapperViewControllerNavigationListener> navigationListener;
-@property (nonatomic, strong) RCTNavItem *navItem;
@end

React/Views/RCTWrapperViewController.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,7 +10,6 @@
#import <UIKit/UIScrollView.h>
#import "RCTEventDispatcher.h"
-#import "RCTNavItem.h"
#import "RCTUtils.h"
#import "UIView+React.h"
#import "RCTAutoInsetsProtocol.h"
@@ -38,14 +37,6 @@
return self;
}
-- (instancetype)initWithNavItem:(RCTNavItem *)navItem
-{
- if ((self = [self initWithContentView:navItem])) {
- _navItem = navItem;
- }
- return self;
-}
-
RCT_NOT_IMPLEMENTED(- (instancetype)initWithNibName:(NSString *)nn bundle:(NSBundle *)nb)
RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
@@ -83,55 +74,6 @@
}
}
-static UIView *RCTFindNavBarShadowViewInView(UIView *view)
-{
- if ([view isKindOfClass:[UIImageView class]] && view.bounds.size.height <= 1) {
- return view;
- }
- for (UIView *subview in view.subviews) {
- UIView *shadowView = RCTFindNavBarShadowViewInView(subview);
- if (shadowView) {
- return shadowView;
- }
- }
- return nil;
-}
-
-- (void)viewWillAppear:(BOOL)animated
-{
- [super viewWillAppear:animated];
-
- // TODO: find a way to make this less-tightly coupled to navigation controller
- if ([self.parentViewController isKindOfClass:[UINavigationController class]])
- {
- [self.navigationController
- setNavigationBarHidden:_navItem.navigationBarHidden
- animated:animated];
-
- UINavigationBar *bar = self.navigationController.navigationBar;
- bar.barTintColor = _navItem.barTintColor;
- bar.tintColor = _navItem.tintColor;
- bar.translucent = _navItem.translucent;
-#if !TARGET_OS_TV
- bar.barStyle = _navItem.barStyle;
-#endif
- bar.titleTextAttributes = _navItem.titleTextColor ? @{
- NSForegroundColorAttributeName: _navItem.titleTextColor
- } : nil;
-
- RCTFindNavBarShadowViewInView(bar).hidden = _navItem.shadowHidden;
-
- UINavigationItem *item = self.navigationItem;
- item.title = _navItem.title;
- item.titleView = _navItem.titleImageView;
-#if !TARGET_OS_TV
- item.backBarButtonItem = _navItem.backButtonItem;
-#endif //TARGET_OS_TV
- item.leftBarButtonItem = _navItem.leftButtonItem;
- item.rightBarButtonItem = _navItem.rightButtonItem;
- }
-}
-
- (void)loadView
{
// Add a wrapper so that the wrapper view managed by the
@@ -142,16 +84,4 @@
self.view = _wrapperView;
}
-- (void)didMoveToParentViewController:(UIViewController *)parent
-{
- // There's no clear setter for navigation controllers, but did move to parent
- // view controller provides the desired effect. This is called after a pop
- // finishes, be it a swipe to go back or a standard tap on the back button
- [super didMoveToParentViewController:parent];
- if (parent == nil || [parent isKindOfClass:[UINavigationController class]]) {
- [self.navigationListener wrapperViewController:self
- didMoveToNavigationController:(UINavigationController *)parent];
- }
-}
-
@end

React/Views/SafeAreaView/RCTSafeAreaShadowView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/SafeAreaView/RCTSafeAreaShadowView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/SafeAreaView/RCTSafeAreaView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -17,6 +17,8 @@
- (instancetype)initWithBridge:(RCTBridge *)bridge;
+@property (nonatomic, assign) BOOL emulateUnlessSupported;
+
@end
NS_ASSUME_NONNULL_END

React/Views/SafeAreaView/RCTSafeAreaViewLocalData.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/SafeAreaView/RCTSafeAreaViewLocalData.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/SafeAreaView/RCTSafeAreaView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -21,6 +21,7 @@
{
if (self = [super initWithFrame:CGRectZero]) {
_bridge = bridge;
+ _emulateUnlessSupported = YES; // The default.
}
return self;
@@ -29,7 +30,45 @@
RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)decoder)
RCT_NOT_IMPLEMENTED(- (instancetype)initWithFrame:(CGRect)frame)
+- (BOOL)isSupportedByOS
+{
+ return [self respondsToSelector:@selector(safeAreaInsets)];
+}
+
+- (UIEdgeInsets)safeAreaInsetsIfSupportedAndEnabled
+{
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
+ if (self.isSupportedByOS) {
+ return self.safeAreaInsets;
+ }
+#endif
+ return self.emulateUnlessSupported ? self.emulatedSafeAreaInsets : UIEdgeInsetsZero;
+}
+
+- (UIEdgeInsets)emulatedSafeAreaInsets
+{
+ UIViewController* vc = self.reactViewController;
+
+ if (!vc) {
+ return UIEdgeInsetsZero;
+ }
+
+ CGFloat topLayoutOffset = vc.topLayoutGuide.length;
+ CGFloat bottomLayoutOffset = vc.bottomLayoutGuide.length;
+ CGRect safeArea = vc.view.bounds;
+ safeArea.origin.y += topLayoutOffset;
+ safeArea.size.height -= topLayoutOffset + bottomLayoutOffset;
+ CGRect localSafeArea = [vc.view convertRect:safeArea toView:self];
+ UIEdgeInsets safeAreaInsets = UIEdgeInsetsMake(0, 0, 0, 0);
+ if (CGRectGetMinY(localSafeArea) > CGRectGetMinY(self.bounds)) {
+ safeAreaInsets.top = CGRectGetMinY(localSafeArea) - CGRectGetMinY(self.bounds);
+ }
+ if (CGRectGetMaxY(localSafeArea) < CGRectGetMaxY(self.bounds)) {
+ safeAreaInsets.bottom = CGRectGetMaxY(self.bounds) - CGRectGetMaxY(localSafeArea);
+ }
+
+ return safeAreaInsets;
+}
static BOOL UIEdgeInsetsEqualToEdgeInsetsWithThreshold(UIEdgeInsets insets1, UIEdgeInsets insets2, CGFloat threshold) {
return
@@ -41,23 +80,44 @@
- (void)safeAreaInsetsDidChange
{
- if (![self respondsToSelector:@selector(safeAreaInsets)]) {
- return;
- }
+ [self invalidateSafeAreaInsets];
+}
+
+- (void)invalidateSafeAreaInsets
+{
+ [self setSafeAreaInsets:self.safeAreaInsetsIfSupportedAndEnabled];
+}
- UIEdgeInsets safeAreaInsets = self.safeAreaInsets;
+- (void)layoutSubviews
+{
+ [super layoutSubviews];
+
+ if (!self.isSupportedByOS && self.emulateUnlessSupported) {
+ [self invalidateSafeAreaInsets];
+ }
+}
+- (void)setSafeAreaInsets:(UIEdgeInsets)safeAreaInsets
+{
if (UIEdgeInsetsEqualToEdgeInsetsWithThreshold(safeAreaInsets, _currentSafeAreaInsets, 1.0 / RCTScreenScale())) {
return;
}
_currentSafeAreaInsets = safeAreaInsets;
- RCTSafeAreaViewLocalData *localData =
- [[RCTSafeAreaViewLocalData alloc] initWithInsets:safeAreaInsets];
+ RCTSafeAreaViewLocalData *localData = [[RCTSafeAreaViewLocalData alloc] initWithInsets:safeAreaInsets];
[_bridge.uiManager setLocalData:localData forView:self];
}
-#endif
+- (void)setEmulateUnlessSupported:(BOOL)emulateUnlessSupported
+{
+ if (_emulateUnlessSupported == emulateUnlessSupported) {
+ return;
+ }
+
+ _emulateUnlessSupported = emulateUnlessSupported;
+
+ [self invalidateSafeAreaInsets];
+}
@end

React/Views/SafeAreaView/RCTSafeAreaViewManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/SafeAreaView/RCTSafeAreaViewManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -15,6 +15,8 @@
RCT_EXPORT_MODULE()
+RCT_EXPORT_VIEW_PROPERTY(emulateUnlessSupported, BOOL)
+
- (UIView *)view
{
return [[RCTSafeAreaView alloc] initWithBridge:self.bridge];

React/Views/ScrollView/RCTScrollableProtocol.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/ScrollView/RCTScrollContentShadowView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/ScrollView/RCTScrollContentShadowView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/ScrollView/RCTScrollContentView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/ScrollView/RCTScrollContentView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/ScrollView/RCTScrollContentViewManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/ScrollView/RCTScrollContentViewManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/ScrollView/RCTScrollView.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -44,8 +44,11 @@
@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;
+@property (nonatomic, assign) BOOL snapToEnd;
@property (nonatomic, copy) NSString *snapToAlignment;
// NOTE: currently these event props are only declared so we can export the
@@ -53,6 +56,7 @@
// need to be coalesced before sending, for performance reasons.
@property (nonatomic, copy) RCTDirectEventBlock onScrollBeginDrag;
@property (nonatomic, copy) RCTDirectEventBlock onScroll;
+@property (nonatomic, copy) RCTDirectEventBlock onScrollToTop;
@property (nonatomic, copy) RCTDirectEventBlock onScrollEndDrag;
@property (nonatomic, copy) RCTDirectEventBlock onMomentumScrollBegin;
@property (nonatomic, copy) RCTDirectEventBlock onMomentumScrollEnd;

React/Views/ScrollView/RCTScrollView.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -588,8 +588,19 @@
- (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];
}
}
@@ -651,6 +662,7 @@
RCT_SCROLL_EVENT_HANDLER(scrollViewWillBeginDecelerating, onMomentumScrollBegin)
RCT_SCROLL_EVENT_HANDLER(scrollViewDidZoom, onScroll)
+RCT_SCROLL_EVENT_HANDLER(scrollViewDidScrollToTop, onScrollToTop)
- (void)addScrollListener:(NSObject<UIScrollViewDelegate> *)scrollListener
{
@@ -739,6 +751,8 @@
// Find which axis to snap
BOOL isHorizontal = [self isHorizontal:scrollView];
+ CGFloat velocityAlongAxis = isHorizontal ? velocity.x : velocity.y;
+ CGFloat offsetAlongAxis = isHorizontal ? _scrollView.contentOffset.x : _scrollView.contentOffset.y;
// Calculate maximum content offset
CGSize viewportSize = [self _calculateViewportSize];
@@ -772,9 +786,26 @@
? smallerOffset
: largerOffset;
- // Chose the correct snap offset based on velocity
- CGFloat velocityAlongAxis = isHorizontal ? velocity.x : velocity.y;
- if (velocityAlongAxis > 0.0) {
+ CGFloat firstOffset = [[self.snapToOffsets firstObject] floatValue];
+ CGFloat lastOffset = [[self.snapToOffsets lastObject] floatValue];
+
+ // if scrolling after the last snap offset and snapping to the
+ // end of the list is disabled, then we allow free scrolling
+ if (!self.snapToEnd && targetOffset >= lastOffset) {
+ if (offsetAlongAxis >= lastOffset) {
+ // free scrolling
+ } else {
+ // snap to end
+ targetOffset = lastOffset;
+ }
+ } else if (!self.snapToStart && targetOffset <= firstOffset) {
+ if (offsetAlongAxis <= firstOffset) {
+ // free scrolling
+ } else {
+ // snap to beginning
+ targetOffset = firstOffset;
+ }
+ } else if (velocityAlongAxis > 0.0) {
targetOffset = largerOffset;
} else if (velocityAlongAxis < 0.0) {
targetOffset = smallerOffset;

React/Views/ScrollView/RCTScrollViewManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/ScrollView/RCTScrollViewManager.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -80,12 +80,16 @@
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)
+RCT_EXPORT_VIEW_PROPERTY(snapToEnd, BOOL)
RCT_EXPORT_VIEW_PROPERTY(snapToAlignment, NSString)
RCT_REMAP_VIEW_PROPERTY(contentOffset, scrollView.contentOffset, CGPoint)
RCT_EXPORT_VIEW_PROPERTY(onScrollBeginDrag, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onScroll, RCTDirectEventBlock)
+RCT_EXPORT_VIEW_PROPERTY(onScrollToTop, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onScrollEndDrag, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onMomentumScrollBegin, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onMomentumScrollEnd, RCTDirectEventBlock)

React/Views/UIView+Private.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/UIView+React.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

React/Views/UIView+React.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/build.gradle

@@ -1,4 +1,4 @@
-// Copyright (c) 2015-present, Facebook, Inc.
+// 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.
@@ -26,7 +26,6 @@
// - double-conversion-1.1.6
// - folly-deprecate-dynamic-initializer
// - glog-0.3.5
-// - jsc-headers
def dependenciesPath = System.getenv("REACT_NATIVE_DEPENDENCIES")
// The Boost library is a very large download (>100MB).
@@ -40,124 +39,136 @@
}
task downloadBoost(dependsOn: createNativeDepsDirectories, type: Download) {
- src "https://github.com/react-native-community/boost-for-react-native/releases/download/v${BOOST_VERSION.replace("_", ".")}-0/boost_${BOOST_VERSION}.tar.gz"
- onlyIfNewer true
- overwrite false
- dest new File(downloadsDir, "boost_${BOOST_VERSION}.tar.gz")
+ src("https://github.com/react-native-community/boost-for-react-native/releases/download/v${BOOST_VERSION.replace("_", ".")}-0/boost_${BOOST_VERSION}.tar.gz")
+ onlyIfNewer(true)
+ overwrite(false)
+ dest(new File(downloadsDir, "boost_${BOOST_VERSION}.tar.gz"))
}
task prepareBoost(dependsOn: boostPath ? [] : [downloadBoost], type: Copy) {
- from boostPath ?: tarTree(resources.gzip(downloadBoost.dest))
- from 'src/main/jni/third-party/boost/Android.mk'
- include 'Android.mk', "boost_${BOOST_VERSION}/boost/**/*.hpp", 'boost/boost/**/*.hpp'
+ from(boostPath ?: tarTree(resources.gzip(downloadBoost.dest)))
+ from("src/main/jni/third-party/boost/Android.mk")
+ include("Android.mk", "boost_${BOOST_VERSION}/boost/**/*.hpp", "boost/boost/**/*.hpp")
includeEmptyDirs = false
- into "$thirdPartyNdkDir/boost"
+ into("$thirdPartyNdkDir/boost")
doLast {
file("$thirdPartyNdkDir/boost/boost").renameTo("$thirdPartyNdkDir/boost/boost_${BOOST_VERSION}")
}
}
task downloadDoubleConversion(dependsOn: createNativeDepsDirectories, type: Download) {
- src "https://github.com/google/double-conversion/archive/v${DOUBLE_CONVERSION_VERSION}.tar.gz"
- onlyIfNewer true
- overwrite false
- dest new File(downloadsDir, "double-conversion-${DOUBLE_CONVERSION_VERSION}.tar.gz")
+ src("https://github.com/google/double-conversion/archive/v${DOUBLE_CONVERSION_VERSION}.tar.gz")
+ onlyIfNewer(true)
+ overwrite(false)
+ dest(new File(downloadsDir, "double-conversion-${DOUBLE_CONVERSION_VERSION}.tar.gz"))
}
task prepareDoubleConversion(dependsOn: dependenciesPath ? [] : [downloadDoubleConversion], type: Copy) {
- from dependenciesPath ?: tarTree(downloadDoubleConversion.dest)
- from 'src/main/jni/third-party/double-conversion/Android.mk'
- include "double-conversion-${DOUBLE_CONVERSION_VERSION}/src/**/*", 'Android.mk'
- filesMatching('*/src/**/*', {fname -> fname.path = "double-conversion/${fname.name}"})
+ from(dependenciesPath ?: tarTree(downloadDoubleConversion.dest))
+ from("src/main/jni/third-party/double-conversion/Android.mk")
+ include("double-conversion-${DOUBLE_CONVERSION_VERSION}/src/**/*", "Android.mk")
+ filesMatching("*/src/**/*", { fname -> fname.path = "double-conversion/${fname.name}" })
includeEmptyDirs = false
- into "$thirdPartyNdkDir/double-conversion"
+ into("$thirdPartyNdkDir/double-conversion")
}
task downloadFolly(dependsOn: createNativeDepsDirectories, type: Download) {
- src "https://github.com/facebook/folly/archive/v${FOLLY_VERSION}.tar.gz"
- onlyIfNewer true
- overwrite false
- dest new File(downloadsDir, "folly-${FOLLY_VERSION}.tar.gz");
+ src("https://github.com/facebook/folly/archive/v${FOLLY_VERSION}.tar.gz")
+ onlyIfNewer(true)
+ overwrite(false)
+ dest(new File(downloadsDir, "folly-${FOLLY_VERSION}.tar.gz"))
}
task prepareFolly(dependsOn: dependenciesPath ? [] : [downloadFolly], type: Copy) {
- from dependenciesPath ?: tarTree(downloadFolly.dest)
- from 'src/main/jni/third-party/folly/Android.mk'
- include "folly-${FOLLY_VERSION}/folly/**/*", 'Android.mk'
- eachFile {fname -> fname.path = (fname.path - "folly-${FOLLY_VERSION}/")}
+ from(dependenciesPath ?: tarTree(downloadFolly.dest))
+ from("src/main/jni/third-party/folly/Android.mk")
+ include("folly-${FOLLY_VERSION}/folly/**/*", "Android.mk")
+ eachFile { fname -> fname.path = (fname.path - "folly-${FOLLY_VERSION}/") }
includeEmptyDirs = false
- into "$thirdPartyNdkDir/folly"
+ into("$thirdPartyNdkDir/folly")
}
task downloadGlog(dependsOn: createNativeDepsDirectories, type: Download) {
- src "https://github.com/google/glog/archive/v${GLOG_VERSION}.tar.gz"
- onlyIfNewer true
- overwrite false
- dest new File(downloadsDir, "glog-${GLOG_VERSION}.tar.gz")
+ src("https://github.com/google/glog/archive/v${GLOG_VERSION}.tar.gz")
+ onlyIfNewer(true)
+ overwrite(false)
+ dest(new File(downloadsDir, "glog-${GLOG_VERSION}.tar.gz"))
}
// Prepare glog sources to be compiled, this task will perform steps that normally should've been
// executed by automake. This way we can avoid dependencies on make/automake
task prepareGlog(dependsOn: dependenciesPath ? [] : [downloadGlog], type: Copy) {
- from dependenciesPath ?: tarTree(downloadGlog.dest)
- from 'src/main/jni/third-party/glog/'
- include "glog-${GLOG_VERSION}/src/**/*", 'Android.mk', 'config.h'
+ from(dependenciesPath ?: tarTree(downloadGlog.dest))
+ from("src/main/jni/third-party/glog/")
+ include("glog-${GLOG_VERSION}/src/**/*", "Android.mk", "config.h")
includeEmptyDirs = false
- filesMatching('**/*.h.in') {
+ filesMatching("**/*.h.in") {
filter(ReplaceTokens, tokens: [
- ac_cv_have_unistd_h: '1',
- ac_cv_have_stdint_h: '1',
- ac_cv_have_systypes_h: '1',
- ac_cv_have_inttypes_h: '1',
- ac_cv_have_libgflags: '0',
- ac_google_start_namespace: 'namespace google {',
- ac_cv_have_uint16_t: '1',
- ac_cv_have_u_int16_t: '1',
- ac_cv_have___uint16: '0',
- ac_google_end_namespace: '}',
- ac_cv_have___builtin_expect: '1',
- ac_google_namespace: 'google',
- ac_cv___attribute___noinline: '__attribute__ ((noinline))',
- ac_cv___attribute___noreturn: '__attribute__ ((noreturn))',
- ac_cv___attribute___printf_4_5: '__attribute__((__format__ (__printf__, 4, 5)))'
+ ac_cv_have_unistd_h : "1",
+ ac_cv_have_stdint_h : "1",
+ ac_cv_have_systypes_h : "1",
+ ac_cv_have_inttypes_h : "1",
+ ac_cv_have_libgflags : "0",
+ ac_google_start_namespace : "namespace google {",
+ ac_cv_have_uint16_t : "1",
+ ac_cv_have_u_int16_t : "1",
+ ac_cv_have___uint16 : "0",
+ ac_google_end_namespace : "}",
+ ac_cv_have___builtin_expect : "1",
+ ac_google_namespace : "google",
+ ac_cv___attribute___noinline : "__attribute__ ((noinline))",
+ ac_cv___attribute___noreturn : "__attribute__ ((noreturn))",
+ ac_cv___attribute___printf_4_5: "__attribute__((__format__ (__printf__, 4, 5)))"
])
- it.path = (it.name - '.in')
+ it.path = (it.name - ".in")
+ }
+ into("$thirdPartyNdkDir/glog")
+
+ doLast {
+ copy {
+ from(fileTree(dir: "$thirdPartyNdkDir/glog", includes: ["stl_logging.h", "logging.h", "raw_logging.h", "vlog_is_on.h", "**/glog/log_severity.h"]).files)
+ includeEmptyDirs = false
+ into("$thirdPartyNdkDir/glog/exported/glog")
+ }
}
- into "$thirdPartyNdkDir/glog"
}
-task downloadJSCHeaders(type: Download) {
- // in sync with webkit SVN revision 174650
- def jscAPIBaseURL = 'https://raw.githubusercontent.com/WebKit/webkit/38b15a3ba3c1b0798f2036f7cea36ffdc096202e/Source/JavaScriptCore/API/'
- def jscHeaderFiles = ['JavaScript.h', 'JSBase.h', 'JSContextRef.h', 'JSObjectRef.h', 'JSRetainPtr.h', 'JSStringRef.h', 'JSValueRef.h', 'WebKitAvailability.h']
- def output = new File(downloadsDir, 'jsc')
- output.mkdirs()
- src(jscHeaderFiles.collect { headerName -> "$jscAPIBaseURL$headerName" })
- onlyIfNewer true
- overwrite false
- dest output
+task downloadJSC(dependsOn: createNativeDepsDirectories, type: Download) {
+ src("https://registry.npmjs.org/jsc-android/-/jsc-android-${JSC_VERSION}.tgz")
+ onlyIfNewer(true)
+ overwrite(false)
+ dest(new File(downloadsDir, "jsc-${JSC_VERSION}.tar.gz"))
}
-// Create Android.mk library module based on so files from mvn + include headers fetched from webkit.org
-task prepareJSC(dependsOn: dependenciesPath ? [] : [downloadJSCHeaders]) << {
+// Create Android.mk library module based on jsc from npm
+task prepareJSC(dependsOn: downloadJSC) {
+ doLast {
+ def jscTar = tarTree(downloadJSC.dest)
+ def jscAAR = jscTar.matching({ it.include "**/android-jsc/**/*.aar" }).singleFile
+ def soFiles = zipTree(jscAAR).matching({ it.include "**/*.so" })
+
+ def headerFiles = jscTar.matching({ it.include "**/include/*.h" })
+
copy {
- from zipTree(configurations.compile.fileCollection { dep -> dep.name == 'android-jsc' }.singleFile)
- from dependenciesPath ? "$dependenciesPath/jsc-headers" : {downloadJSCHeaders.dest}
- from 'src/main/jni/third-party/jsc/Android.mk'
- include 'jni/**/*.so', '*.h', 'Android.mk'
- filesMatching('*.h', { fname -> fname.path = "JavaScriptCore/${fname.path}"})
- into "$thirdPartyNdkDir/jsc";
+ from(soFiles)
+ from(headerFiles)
+ from("src/main/jni/third-party/jsc/Android.mk")
+
+ filesMatching("**/*.h", { it.path = "JavaScriptCore/${it.name}" })
+
+ includeEmptyDirs(false)
+ into("$thirdPartyNdkDir/jsc")
+ }
}
}
-
task downloadNdkBuildDependencies {
if (!boostPath) {
- dependsOn downloadBoost
+ dependsOn(downloadBoost)
}
- dependsOn downloadDoubleConversion
- dependsOn downloadFolly
- dependsOn downloadGlog
- dependsOn downloadJSCHeaders
+ dependsOn(downloadDoubleConversion)
+ dependsOn(downloadFolly)
+ dependsOn(downloadGlog)
+ dependsOn(downloadJSC)
}
def getNdkBuildName() {
@@ -170,21 +181,21 @@
def findNdkBuildFullPath() {
// we allow to provide full path to ndk-build tool
- if (hasProperty('ndk.command')) {
- return property('ndk.command')
+ if (hasProperty("ndk.command")) {
+ return property("ndk.command")
}
// or just a path to the containing directory
- if (hasProperty('ndk.path')) {
- def ndkDir = property('ndk.path')
+ if (hasProperty("ndk.path")) {
+ def ndkDir = property("ndk.path")
return new File(ndkDir, getNdkBuildName()).getAbsolutePath()
}
- if (System.getenv('ANDROID_NDK') != null) {
- def ndkDir = System.getenv('ANDROID_NDK')
+ if (System.getenv("ANDROID_NDK") != null) {
+ def ndkDir = System.getenv("ANDROID_NDK")
return new File(ndkDir, getNdkBuildName()).getAbsolutePath()
}
- def ndkDir = android.hasProperty('plugin') ? android.plugin.ndkFolder :
- plugins.getPlugin('com.android.library').hasProperty('sdkHandler') ?
- plugins.getPlugin('com.android.library').sdkHandler.getNdkFolder() :
+ def ndkDir = android.hasProperty("plugin") ? android.plugin.ndkFolder :
+ plugins.getPlugin("com.android.library").hasProperty("sdkHandler") ?
+ plugins.getPlugin("com.android.library").sdkHandler.getNdkFolder() :
android.ndkDirectory.absolutePath
if (ndkDir) {
return new File(ndkDir, getNdkBuildName()).getAbsolutePath()
@@ -212,112 +223,123 @@
}
task buildReactNdkLib(dependsOn: [prepareJSC, prepareBoost, prepareDoubleConversion, prepareFolly, prepareGlog], type: Exec) {
- inputs.file('src/main/jni/react')
+ inputs.dir("src/main/jni/react")
outputs.dir("$buildDir/react-ndk/all")
- commandLine getNdkBuildFullPath(),
- 'NDK_PROJECT_PATH=null',
+ commandLine(getNdkBuildFullPath(),
+ "NDK_PROJECT_PATH=null",
"NDK_APPLICATION_MK=$projectDir/src/main/jni/Application.mk",
- 'NDK_OUT=' + temporaryDir,
+ "NDK_OUT=" + temporaryDir,
"NDK_LIBS_OUT=$buildDir/react-ndk/all",
"THIRD_PARTY_NDK_DIR=$buildDir/third-party-ndk",
"REACT_COMMON_DIR=$projectDir/../ReactCommon",
- '-C', file('src/main/jni/react/jni').absolutePath,
- '--jobs', project.hasProperty("jobs") ? project.property("jobs") : Runtime.runtime.availableProcessors()
+ "REACT_SRC_DIR=$projectDir/src/main/java/com/facebook/react",
+ "-C", file("src/main/jni/react/jni").absolutePath,
+ "--jobs", project.findProperty("jobs") ?: Runtime.runtime.availableProcessors()
+ )
}
task cleanReactNdkLib(type: Exec) {
- commandLine getNdkBuildFullPath(),
+ ignoreExitValue(true)
+ errorOutput(new ByteArrayOutputStream())
+ commandLine(getNdkBuildFullPath(),
"NDK_APPLICATION_MK=$projectDir/src/main/jni/Application.mk",
"THIRD_PARTY_NDK_DIR=$buildDir/third-party-ndk",
"REACT_COMMON_DIR=$projectDir/../ReactCommon",
- '-C', file('src/main/jni/react/jni').absolutePath,
- 'clean'
+ "-C", file("src/main/jni/react/jni").absolutePath,
+ "clean")
+ doLast {
+ file(AAR_OUTPUT_URL).delete()
+ println("Deleted aar output dir at ${file(AAR_OUTPUT_URL)}")
+ }
}
task packageReactNdkLibs(dependsOn: buildReactNdkLib, type: Copy) {
- from "$buildDir/react-ndk/all"
- exclude '**/libjsc.so'
- into "$buildDir/react-ndk/exported"
+ from("$buildDir/react-ndk/all")
+ from("$thirdPartyNdkDir/jsc/jni")
+ into("$buildDir/react-ndk/exported")
}
task packageReactNdkLibsForBuck(dependsOn: packageReactNdkLibs, type: Copy) {
- from "$buildDir/react-ndk/exported"
- into "src/main/jni/prebuilt/lib"
+ from("$buildDir/react-ndk/exported")
+ into("src/main/jni/prebuilt/lib")
}
android {
- compileSdkVersion 27
- buildToolsVersion "27.0.3"
+ compileSdkVersion 28
+
+ compileOptions {
+ sourceCompatibility(JavaVersion.VERSION_1_8)
+ targetCompatibility(JavaVersion.VERSION_1_8)
+ }
defaultConfig {
- minSdkVersion 16
- targetSdkVersion 26
- versionCode 1
- versionName "1.0"
+ minSdkVersion(16)
+ targetSdkVersion(28)
+ versionCode(1)
+ versionName("1.0")
- consumerProguardFiles 'proguard-rules.pro'
+ consumerProguardFiles("proguard-rules.pro")
ndk {
- moduleName "reactnativejni"
+ moduleName("reactnativejni")
}
- buildConfigField 'boolean', 'IS_INTERNAL_BUILD', 'false'
- buildConfigField 'int', 'EXOPACKAGE_FLAGS', '0'
- testApplicationId "com.facebook.react.tests.gradle"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ buildConfigField("boolean", "IS_INTERNAL_BUILD", "false")
+ buildConfigField("int", "EXOPACKAGE_FLAGS", "0")
+ testApplicationId("com.facebook.react.tests.gradle")
+ testInstrumentationRunner("android.support.test.runner.AndroidJUnitRunner")
}
sourceSets.main {
jni.srcDirs = []
- jniLibs.srcDir "$buildDir/react-ndk/exported"
- res.srcDirs = ['src/main/res/devsupport', 'src/main/res/shell', 'src/main/res/views/modal', 'src/main/res/views/uimanager']
+ jniLibs.srcDir("$buildDir/react-ndk/exported")
+ res.srcDirs = ["src/main/res/devsupport", "src/main/res/shell", "src/main/res/views/modal", "src/main/res/views/uimanager"]
java {
- srcDirs = ['src/main/java', 'src/main/libraries/soloader/java', 'src/main/jni/first-party/fb/jni/java']
- exclude 'com/facebook/react/processing'
- exclude 'com/facebook/react/module/processing'
+ srcDirs = ["src/main/java", "src/main/libraries/soloader/java", "src/main/jni/first-party/fb/jni/java"]
+ exclude("com/facebook/react/processing")
+ exclude("com/facebook/react/module/processing")
}
}
tasks.withType(JavaCompile) {
- compileTask -> compileTask.dependsOn packageReactNdkLibs
+ compileTask -> compileTask.dependsOn(packageReactNdkLibs)
}
- clean.dependsOn cleanReactNdkLib
+ clean.dependsOn(cleanReactNdkLib)
lintOptions {
- abortOnError false
+ abortOnError(false)
}
packagingOptions {
- exclude 'META-INF/NOTICE'
- exclude 'META-INF/LICENSE'
+ exclude("META-INF/NOTICE")
+ exclude("META-INF/LICENSE")
}
}
dependencies {
- api 'com.facebook.infer.annotation:infer-annotation:0.11.2'
- api 'javax.inject:javax.inject:1'
- api 'com.android.support:appcompat-v7:27.1.1'
- api "com.facebook.fresco:fresco:${FRESCO_VERSION}"
- api "com.facebook.fresco:imagepipeline-okhttp3:${FRESCO_VERSION}"
- api 'com.facebook.soloader:soloader:0.5.1'
- api 'com.google.code.findbugs:jsr305:3.0.2'
- api "com.squareup.okhttp3:okhttp:${OKHTTP_VERSION}"
- api "com.squareup.okhttp3:okhttp-urlconnection:${OKHTTP_VERSION}"
- api 'com.squareup.okio:okio:1.14.0'
- compile 'org.webkit:android-jsc:r174650'
-
- testImplementation "junit:junit:${JUNIT_VERSION}"
- testImplementation "org.powermock:powermock-api-mockito:${POWERMOCK_VERSION}"
- testImplementation "org.powermock:powermock-module-junit4-rule:${POWERMOCK_VERSION}"
- testImplementation "org.powermock:powermock-classloading-xstream:${POWERMOCK_VERSION}"
- testImplementation "org.mockito:mockito-core:${MOCKITO_CORE_VERSION}"
- testImplementation "org.easytesting:fest-assert-core:${FEST_ASSERT_CORE_VERSION}"
- testImplementation "org.robolectric:robolectric:${ROBOLECTRIC_VERSION}"
-
- androidTestImplementation fileTree(dir: 'src/main/third-party/java/buck-android-support/', include: ['*.jar'])
- androidTestImplementation "com.android.support.test:runner:${ANDROID_SUPPORT_TEST_VERSION}"
- androidTestImplementation "com.android.support.test:rules:${ANDROID_SUPPORT_TEST_VERSION}"
- androidTestImplementation "org.mockito:mockito-core:${MOCKITO_CORE_VERSION}"
+ api("com.facebook.infer.annotation:infer-annotation:0.11.2")
+ api("javax.inject:javax.inject:1")
+ api("com.android.support:appcompat-v7:28.0.0")
+ api("com.facebook.fresco:fresco:${FRESCO_VERSION}")
+ api("com.facebook.fresco:imagepipeline-okhttp3:${FRESCO_VERSION}")
+ api("com.facebook.soloader:soloader:${SO_LOADER_VERSION}")
+ api("com.google.code.findbugs:jsr305:3.0.2")
+ api("com.squareup.okhttp3:okhttp:${OKHTTP_VERSION}")
+ api("com.squareup.okhttp3:okhttp-urlconnection:${OKHTTP_VERSION}")
+ api("com.squareup.okio:okio:1.15.0")
+
+ testImplementation("junit:junit:${JUNIT_VERSION}")
+ testImplementation("org.powermock:powermock-api-mockito:${POWERMOCK_VERSION}")
+ testImplementation("org.powermock:powermock-module-junit4-rule:${POWERMOCK_VERSION}")
+ testImplementation("org.powermock:powermock-classloading-xstream:${POWERMOCK_VERSION}")
+ testImplementation("org.mockito:mockito-core:${MOCKITO_CORE_VERSION}")
+ testImplementation("org.easytesting:fest-assert-core:${FEST_ASSERT_CORE_VERSION}")
+ testImplementation("org.robolectric:robolectric:${ROBOLECTRIC_VERSION}")
+
+ androidTestImplementation(fileTree(dir: "src/main/third-party/java/buck-android-support/", include: ["*.jar"]))
+ androidTestImplementation("com.android.support.test:runner:${ANDROID_SUPPORT_TEST_VERSION}")
+ androidTestImplementation("com.android.support.test:rules:${ANDROID_SUPPORT_TEST_VERSION}")
+ androidTestImplementation("org.mockito:mockito-core:${MOCKITO_CORE_VERSION}")
}
-apply from: 'release.gradle'
+apply(from: "release.gradle")

ReactAndroid/gradle.properties

@@ -1,4 +1,4 @@
-VERSION_NAME=0.57.8
+VERSION_NAME=0.59.4
GROUP=com.facebook.react
POM_NAME=ReactNative
@@ -13,9 +13,11 @@
ANDROID_SUPPORT_TEST_VERSION=1.0.2
FRESCO_VERSION=1.10.0
-OKHTTP_VERSION=3.11.0
+OKHTTP_VERSION=3.12.1
+SO_LOADER_VERSION=0.6.0
BOOST_VERSION=1_63_0
DOUBLE_CONVERSION_VERSION=1.1.6
-FOLLY_VERSION=2016.10.31.00
+FOLLY_VERSION=2018.10.22.00
GLOG_VERSION=0.3.5
+JSC_VERSION=236355.1.1

ReactAndroid/libs/BUCK

@@ -1,21 +1,24 @@
-android_prebuilt_aar(
+load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
+load("//tools/build_defs/oss:rn_defs.bzl", "rn_android_prebuilt_aar")
+
+rn_android_prebuilt_aar(
name = "appcompat",
aar = ":appcompat-binary-aar",
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "appcompat-binary-aar",
- sha1 = "22b1ef4ff9ef1a3513c18eb132d597eac6ef1a86",
- url = "mvn:com.android.support:appcompat-v7:aar:27.1.1",
+ sha1 = "132586ec59604a86703796851a063a0ac61f697b",
+ url = "mvn:com.android.support:appcompat-v7:aar:28.0.0",
)
-android_prebuilt_aar(
+rn_android_prebuilt_aar(
name = "android-jsc",
aar = ":android-jsc-aar",
)
-remote_file(
+fb_native.remote_file(
name = "android-jsc-aar",
sha1 = "880cedd93f43e0fc841f01f2fa185a63d9230f85",
url = "mvn:org.webkit:android-jsc:aar:r174650",

ReactAndroid/proguard-rules.pro

@@ -1,3 +1,8 @@
+# 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.
+
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
@@ -44,7 +49,6 @@
-keep class * extends com.facebook.react.bridge.JavaScriptModule { *; }
-keep class * extends com.facebook.react.bridge.NativeModule { *; }
-keepclassmembers,includedescriptorclasses class * { native <methods>; }
--keepclassmembers class * { @com.facebook.react.uimanager.UIProp <fields>; }
-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp <methods>; }
-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup <methods>; }

ReactAndroid/release.gradle

@@ -1,57 +1,61 @@
-// Copyright (c) 2015-present, Facebook, Inc.
+// 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.
-apply plugin: 'maven'
-apply plugin: 'signing'
+apply(plugin: "maven")
+apply(plugin: "signing")
+
+ext {
+ AAR_OUTPUT_URL = "file://${projectDir}/../android"
+}
// Gradle tasks for publishing to maven
// 1) To install in local maven repo use :installArchives task
// 2) To upload artifact to maven central use: :uploadArchives (you'd need to have the permission to do that)
def isReleaseBuild() {
- return VERSION_NAME.contains('SNAPSHOT') == false
+ return VERSION_NAME.contains("SNAPSHOT") == false
}
def getRepositoryUrl() {
- return project.hasProperty('repositoryUrl') ? property('repositoryUrl') : 'https://oss.sonatype.org/service/local/staging/deploy/maven2/'
+ return project.findProperty("repositoryUrl") ?: "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
}
def getRepositoryUsername() {
- return project.hasProperty('repositoryUsername') ? property('repositoryUsername') : ''
+ return project.findProperty("repositoryUsername") ?: ""
}
def getRepositoryPassword() {
- return project.hasProperty('repositoryPassword') ? property('repositoryPassword') : ''
+ return project.findProperty("repositoryPassword") ?: ""
}
def configureReactNativePom(def pom) {
pom.project {
- name POM_NAME
- artifactId POM_ARTIFACT_ID
- packaging POM_PACKAGING
- description 'A framework for building native apps with React'
- url 'https://github.com/facebook/react-native'
+ name(POM_NAME)
+ artifactId(POM_ARTIFACT_ID)
+ packaging(POM_PACKAGING)
+ description("A framework for building native apps with React")
+ url("https://github.com/facebook/react-native")
scm {
- url 'https://github.com/facebook/react-native.git'
- connection 'scm:git:https://github.com/facebook/react-native.git'
- developerConnection 'scm:git:git@github.com:facebook/react-native.git'
+ url("https://github.com/facebook/react-native.git")
+ connection("scm:git:https://github.com/facebook/react-native.git")
+ developerConnection("scm:git:git@github.com:facebook/react-native.git")
}
licenses {
license {
- name 'MIT License'
- url 'https://github.com/facebook/react-native/blob/master/LICENSE'
- distribution 'repo'
+ name("MIT License")
+ url("https://github.com/facebook/react-native/blob/master/LICENSE")
+ distribution("repo")
}
}
developers {
developer {
- id 'facebook'
- name 'Facebook'
+ id("facebook")
+ name("Facebook")
}
}
}
@@ -60,7 +64,7 @@
if (JavaVersion.current().isJava8Compatible()) {
allprojects {
tasks.withType(Javadoc) {
- options.addStringOption('Xdoclint:none', '-quiet')
+ options.addStringOption("Xdoclint:none", "-quiet")
}
}
}
@@ -70,40 +74,40 @@
task androidJavadoc(type: Javadoc) {
source = android.sourceSets.main.java.srcDirs
classpath += files(android.bootClasspath)
- classpath += files(project.getConfigurations().getByName('compile').asList())
- include '**/*.java'
- exclude '**/ReactBuildConfig.java'
+ classpath += files(project.getConfigurations().getByName("compile").asList())
+ include("**/*.java")
+ exclude("**/ReactBuildConfig.java")
}
task androidJavadocJar(type: Jar, dependsOn: androidJavadoc) {
- classifier = 'javadoc'
- from androidJavadoc.destinationDir
+ classifier = "javadoc"
+ from(androidJavadoc.destinationDir)
}
task androidSourcesJar(type: Jar) {
- classifier = 'sources'
- from android.sourceSets.main.java.srcDirs
- include '**/*.java'
+ classifier = "sources"
+ from(android.sourceSets.main.java.srcDirs)
+ include("**/*.java")
}
android.libraryVariants.all { variant ->
def name = variant.name.capitalize()
- task "jar${name}"(type: Jar, dependsOn: variant.javaCompile) {
- from variant.javaCompile.destinationDir
+ task "jar${name}"(type: Jar, dependsOn: variant.javaCompileProvider.get()) {
+ from(variant.javaCompileProvider.get().destinationDir)
}
}
artifacts {
- archives androidSourcesJar
- archives androidJavadocJar
+ archives(androidSourcesJar)
+ archives(androidJavadocJar)
}
version = VERSION_NAME
group = GROUP
signing {
- required { isReleaseBuild() && gradle.taskGraph.hasTask('uploadArchives') }
- sign configurations.archives
+ required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
+ sign(configurations.archives)
}
uploadArchives {
@@ -120,7 +124,7 @@
}
- configureReactNativePom pom
+ configureReactNativePom(pom)
}
}
@@ -128,9 +132,9 @@
configuration = configurations.archives
repositories.mavenDeployer {
// Deploy to react-native/android, ready to publish to npm
- repository url: "file://${projectDir}/../android"
+ repository(url: AAR_OUTPUT_URL)
- configureReactNativePom pom
+ configureReactNativePom(pom)
}
}
}

ReactAndroid/src/androidTest/AndroidManifest.xml

@@ -6,6 +6,8 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- needed for screenshot tests -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <!-- needed for image onError tests -->
+ <uses-permission android:name="android.permission.INTERNET" />
<application
android:hardwareAccelerated="false">

ReactAndroid/src/androidTest/buck-runner/AndroidManifest.xml

@@ -7,6 +7,8 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- needed for screenshot tests -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <!-- needed for image onError tests -->
+ <uses-permission android:name="android.permission.INTERNET" />
<application
android:hardwareAccelerated="false">

ReactAndroid/src/androidTest/buck-runner/BUCK

@@ -3,7 +3,7 @@
# We are running instrumentation tests in simple mode: app code and instrumentation are in the same APK
# Currently you need to run these commands to execute tests:
#
-# node local-cli/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
# gradle :ReactAndroid:packageReactNdkLibsForBuck
# buck install ReactAndroid/src/androidTest/buck-runner:instrumentation-tests
# ./scripts/run-android-instrumentation-tests.sh com.facebook.react.tests

ReactAndroid/src/androidTest/java/com/facebook/react/testing/AbstractScrollViewTestCase.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/testing/AssertModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/testing/BUCK

@@ -3,7 +3,7 @@
rn_android_library(
name = "testing",
srcs = glob(
- ["**/*.java"],
+ ["*.java"],
exclude = [
"idledetection/**/*.java",
"network/**/*.java",
@@ -28,7 +28,7 @@
react_native_target("java/com/facebook/react/common:common"),
react_native_target("java/com/facebook/react/devsupport:interfaces"),
react_native_target("java/com/facebook/react/fabric:fabric"),
- react_native_target("java/com/facebook/react/fabric/jsc:jsc"),
+ react_native_target("java/com/facebook/react/jscexecutor:jscexecutor"),
react_native_target("java/com/facebook/react/module/annotations:annotations"),
react_native_target("java/com/facebook/react/module/model:model"),
react_native_target("java/com/facebook/react/modules/core:core"),

ReactAndroid/src/androidTest/java/com/facebook/react/testing/FabricUIManagerFactory.java

@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * <p>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.testing;
+
+import com.facebook.react.bridge.JavaScriptContextHolder;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.UIManager;
+import com.facebook.react.uimanager.ViewManagerRegistry;
+
+/** Factory used to create FabricUIManager in Testing infrastructure. */
+public interface FabricUIManagerFactory {
+
+ UIManager getFabricUIManager(
+ ReactApplicationContext reactApplicationContext,
+ ViewManagerRegistry viewManagerRegistry,
+ JavaScriptContextHolder jsContext);
+}

ReactAndroid/src/androidTest/java/com/facebook/react/testing/FakeAsyncLocalStorage.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/testing/FakeWebSocketModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/testing/idledetection/IdleWaiter.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/testing/idledetection/ReactBridgeIdleSignaler.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/testing/idledetection/ReactIdleDetectionUtil.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.
@@ -7,6 +7,7 @@
package com.facebook.react.testing.idledetection;
+import android.view.Choreographer;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -55,7 +56,8 @@
new Runnable() {
@Override
public void run() {
- ChoreographerCompat.getInstance().postFrameCallback(
+ final ChoreographerCompat choreographerCompat = ChoreographerCompat.getInstance();
+ choreographerCompat.postFrameCallback(
new ChoreographerCompat.FrameCallback() {
private int frameCount = 0;
@@ -66,7 +68,7 @@
if (frameCount == waitFrameCount) {
latch.countDown();
} else {
- ChoreographerCompat.getInstance().postFrameCallback(this);
+ choreographerCompat.postFrameCallback(this);
}
}
});

ReactAndroid/src/androidTest/java/com/facebook/react/testing/InstanceSpecForTestPackage.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/testing/IntRecordingModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/testing/JSIntegrationTestChecker.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/testing/MultipleFailureException.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/testing/network/NetworkRecordingModuleMock.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppInstrumentationTestCase.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc. and its affiliates.
*
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
* directory of this source tree.
@@ -10,7 +10,6 @@
import android.content.Intent;
import android.graphics.Bitmap;
-import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.View;
@@ -29,8 +28,6 @@
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.UIManager;
import com.facebook.react.common.LifecycleState;
-import com.facebook.react.fabric.FabricUIManager;
-import com.facebook.react.fabric.jsc.FabricJSCBinding;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.modules.core.PermissionAwareActivity;
import com.facebook.react.modules.core.PermissionListener;
@@ -56,7 +53,7 @@
private static final String DEFAULT_BUNDLE_NAME = "AndroidTestBundle.js";
private static final int ROOT_VIEW_ID = 8675309;
// we need a bigger timeout for CI builds because they run on a slow emulator
- private static final long IDLE_TIMEOUT_MS = 120000;
+ private static final long IDLE_TIMEOUT_MS = 240000;
private final CountDownLatch mDestroyCountDownLatch = new CountDownLatch(1);
private CountDownLatch mLayoutEvent = new CountDownLatch(1);
private @Nullable ReactBridgeIdleSignaler mBridgeIdleSignaler;
@@ -199,7 +196,7 @@
throw new RuntimeException("Layout never occurred for component " + appKey, e);}
}
- public void loadBundle(ReactInstanceSpecForTest spec, String bundleName, boolean useDevSupport) {
+ public void loadBundle(final ReactInstanceSpecForTest spec, String bundleName, boolean useDevSupport) {
mBridgeIdleSignaler = new ReactBridgeIdleSignaler();
@@ -208,6 +205,9 @@
.getReactInstanceManagerBuilder()
.setApplication(getApplication())
.setBundleAssetName(bundleName);
+ if (spec.getJavaScriptExecutorFactory() != null) {
+ builder.setJavaScriptExecutorFactory(spec.getJavaScriptExecutorFactory());
+ }
if (!spec.getAlternativeReactPackagesForTest().isEmpty()) {
builder.addPackages(spec.getAlternativeReactPackagesForTest());
} else {
@@ -239,22 +239,13 @@
public JSIModuleProvider getJSIModuleProvider() {
return new JSIModuleProvider() {
@Override
- public FabricUIManager get() {
- List<ViewManager> viewManagers =
- mReactInstanceManager.getOrCreateViewManagers(
- reactApplicationContext);
- EventDispatcher eventDispatcher =
- reactApplicationContext
- .getNativeModule(UIManagerModule.class)
- .getEventDispatcher();
- FabricUIManager fabricUIManager =
- new FabricUIManager(
- reactApplicationContext,
- new ViewManagerRegistry(viewManagers),
- jsContext,
- eventDispatcher);
- new FabricJSCBinding().installFabric(jsContext, fabricUIManager);
- return fabricUIManager;
+ public UIManager get() {
+ ViewManagerRegistry viewManagerRegistry =
+ new ViewManagerRegistry(
+ mReactInstanceManager.getOrCreateViewManagers(reactApplicationContext));
+
+ FabricUIManagerFactory factory = spec.getFabricUIManagerFactory();
+ return factory != null ? factory.getFabricUIManager(reactApplicationContext, viewManagerRegistry, jsContext) : null;
}
};
}

ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstanceSpecForTest.java

@@ -1,20 +1,21 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.
+ * <p>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.testing;
import android.annotation.SuppressLint;
import com.facebook.react.ReactPackage;
+import com.facebook.react.bridge.JavaScriptExecutorFactory;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import javax.annotation.Nullable;
/**
* A spec that allows a test to add additional NativeModules/JS modules to the ReactInstance. This
@@ -29,12 +30,20 @@
private final List<Class<? extends JavaScriptModule>> mJSModuleSpecs = new ArrayList<>();
private final List<ViewManager> mViewManagers = new ArrayList<>();
private final ArrayList<ReactPackage> mReactPackages = new ArrayList<>();
+ @Nullable private FabricUIManagerFactory mFabricUIManagerFactory = null;
+ @Nullable private JavaScriptExecutorFactory mJavaScriptExecutorFactory = null;
public ReactInstanceSpecForTest addNativeModule(NativeModule module) {
mNativeModules.add(module);
return this;
}
+ public ReactInstanceSpecForTest setJavaScriptExecutorFactory(
+ JavaScriptExecutorFactory javaScriptExecutorFactory) {
+ mJavaScriptExecutorFactory = javaScriptExecutorFactory;
+ return this;
+ }
+
public ReactInstanceSpecForTest setPackage(ReactPackage reactPackage) {
if (!mReactPackages.isEmpty()) {
throw new IllegalStateException(
@@ -44,6 +53,16 @@
return this;
}
+ public ReactInstanceSpecForTest setFabricUIManagerFactory(@Nullable FabricUIManagerFactory fabricUIManagerFactory) {
+ mFabricUIManagerFactory = fabricUIManagerFactory;
+ return this;
+ }
+
+ @Nullable
+ public FabricUIManagerFactory getFabricUIManagerFactory() {
+ return mFabricUIManagerFactory;
+ }
+
public ReactInstanceSpecForTest addPackages(List<ReactPackage> reactPackages) {
mReactPackages.addAll(reactPackages);
return this;
@@ -66,6 +85,11 @@
return mReactPackages.get(0);
}
+ @Nullable
+ public JavaScriptExecutorFactory getJavaScriptExecutorFactory() {
+ return mJavaScriptExecutorFactory;
+ }
+
public List<ReactPackage> getAlternativeReactPackagesForTest() {
return mReactPackages;
}

ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstrumentationTest.java

@@ -1,32 +1,37 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.
+ * <p>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.testing;
import android.content.Intent;
import android.test.ActivityInstrumentationTestCase2;
import android.view.View;
import android.view.ViewGroup;
+import com.facebook.react.bridge.JavaScriptExecutorFactory;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.testing.idledetection.IdleWaiter;
+import javax.annotation.Nullable;
/**
* Base class for instrumentation tests that runs React based application.
*
- * This is similar to ReactAppInstrumentationTestCase except ReactInstrumentationTest allows
+ * <p>This is similar to ReactAppInstrumentationTestCase except ReactInstrumentationTest allows
* optional rendering of components. A test case can render no components or render multiple
* components.
*/
-public abstract class ReactInstrumentationTest extends
- ActivityInstrumentationTestCase2<ReactAppTestActivity> implements IdleWaiter {
+public abstract class ReactInstrumentationTest
+ extends ActivityInstrumentationTestCase2<ReactAppTestActivity> implements IdleWaiter {
protected StringRecordingModule mRecordingModule;
+ @Nullable protected FabricUIManagerFactory mFabricUIManagerFactory = null;
+
+ @Nullable protected JavaScriptExecutorFactory mJavaScriptExecutorFactory = null;
+
public ReactInstrumentationTest() {
super(ReactAppTestActivity.class);
}
@@ -40,16 +45,11 @@
setActivityIntent(intent);
mRecordingModule = new StringRecordingModule();
final ReactAppTestActivity activity = getActivity();
- activity.loadBundle(
- createReactInstanceSpecForTest(),
- getBundleName(),
- getEnableDevSupport());
+ activity.loadBundle(createReactInstanceSpecForTest(), getBundleName(), getEnableDevSupport());
}
- /**
- * Renders this component within this test's activity
- */
- public void renderComponent(final String componentName) throws Exception {
+ /** Renders this component within this test's activity */
+ public void renderComponent(final String componentName) {
getActivity().renderComponent(componentName, null);
waitForBridgeAndUIIdle();
}
@@ -66,8 +66,8 @@
}
public <T extends View> T getViewByTestId(String testID) {
- return (T) ReactTestHelper
- .getViewWithReactTestId((ViewGroup) getRootView().getParent(), testID);
+ return (T)
+ ReactTestHelper.getViewWithReactTestId((ViewGroup) getRootView().getParent(), testID);
}
public SingleTouchGestureGenerator createGestureGenerator() {
@@ -94,16 +94,20 @@
return getReactContext().getJSModule(jsInterface);
}
- /**
- * Override this method to provide extra native modules to be loaded before the app starts
- */
+ /** Override this method to provide extra native modules to be loaded before the app starts */
protected ReactInstanceSpecForTest createReactInstanceSpecForTest() {
- return new ReactInstanceSpecForTest().addNativeModule(mRecordingModule);
+ ReactInstanceSpecForTest reactInstanceSpecForTest =
+ new ReactInstanceSpecForTest().addNativeModule(mRecordingModule);
+ if (mJavaScriptExecutorFactory != null) {
+ reactInstanceSpecForTest.setJavaScriptExecutorFactory(mJavaScriptExecutorFactory);
+ }
+ if (mFabricUIManagerFactory != null) {
+ reactInstanceSpecForTest.setFabricUIManagerFactory(mFabricUIManagerFactory);
+ }
+ return reactInstanceSpecForTest;
}
- /**
- * Implement this method to provide the bundle for this test
- */
+ /** Implement this method to provide the bundle for this test */
protected abstract String getBundleName();
protected ReactContext getReactContext() {

ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactSettingsForTests.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestApplicationImpl.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestAppShell.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestFactory.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.
@@ -7,6 +7,10 @@
package com.facebook.react.testing;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
import javax.annotation.Nullable;
import android.app.Instrumentation;
@@ -20,6 +24,7 @@
import com.facebook.react.R;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactInstanceManagerBuilder;
+import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.CatalystInstance;
import com.facebook.react.bridge.JavaScriptModuleRegistry;
import com.facebook.react.bridge.NativeModule;
@@ -29,10 +34,10 @@
import com.facebook.react.bridge.queue.ReactQueueConfigurationSpec;
import com.facebook.react.bridge.CatalystInstanceImpl;
import com.facebook.react.bridge.JSBundleLoader;
-import com.facebook.react.bridge.JSCJavaScriptExecutorFactory;
import com.facebook.react.bridge.JavaScriptExecutor;
+import com.facebook.react.jscexecutor.JSCExecutorFactory;
import com.facebook.react.modules.core.ReactChoreographer;
-
+import com.facebook.react.uimanager.ViewManager;
import com.android.internal.util.Predicate;
public class ReactTestHelper {
@@ -50,14 +55,24 @@
}
@Override
- public ReactInstanceEasyBuilder addNativeModule(NativeModule nativeModule) {
+ public ReactInstanceEasyBuilder addNativeModule(final NativeModule nativeModule) {
if (mNativeModuleRegistryBuilder == null) {
mNativeModuleRegistryBuilder = new NativeModuleRegistryBuilder(
(ReactApplicationContext) mContext,
null);
}
Assertions.assertNotNull(nativeModule);
- mNativeModuleRegistryBuilder.addNativeModule(nativeModule);
+ mNativeModuleRegistryBuilder.processPackage(new ReactPackage(){
+ @Override
+ public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
+ return Arrays.asList(nativeModule);
+ }
+ });
return this;
}
@@ -70,7 +85,7 @@
}
JavaScriptExecutor executor = null;
try {
- executor = new JSCJavaScriptExecutorFactory("ReactTestHelperApp", "ReactTestHelperDevice").create();
+ executor = new JSCExecutorFactory("ReactTestHelperApp", "ReactTestHelperDevice").create();
} catch (Exception e) {
throw new RuntimeException(e);
}

ReactAndroid/src/androidTest/java/com/facebook/react/testing/rule/BUCK

@@ -0,0 +1,37 @@
+# BUILD FILE SYNTAX: SKYLARK
+load(
+ "//tools/build_defs/oss:rn_defs.bzl",
+ "IS_OSS_BUILD",
+ "react_native_dep",
+ "react_native_integration_tests_target",
+ "react_native_target",
+ "rn_android_library",
+)
+
+rn_android_library(
+ name = "rule",
+ srcs = glob(["*.java"]),
+ visibility = [
+ "PUBLIC",
+ ],
+ deps = ([
+ react_native_dep("third-party/java/espresso:espresso"),
+ react_native_dep("third-party/java/jsr-305:jsr-305"),
+ react_native_dep("third-party/java/junit:junit"),
+ react_native_dep("third-party/java/testing-support-lib:testing-support-lib"),
+ 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("third-party/java/jsr-305:jsr-305"),
+ react_native_integration_tests_target("java/com/facebook/react/testing:testing"),
+ react_native_integration_tests_target("java/com/facebook/react/testing/idledetection:idledetection"),
+ react_native_target("java/com/facebook/react:react"),
+ react_native_target("java/com/facebook/react/bridge:bridge"),
+ react_native_target("java/com/facebook/react/common:common"),
+ react_native_target("java/com/facebook/react/modules/core:core"),
+ react_native_target("java/com/facebook/react/shell:shell"),
+ react_native_target("java/com/facebook/react/uimanager:uimanager"),
+ ]) + ([
+ react_native_dep("java/com/facebook/testing/instrumentation:instrumentation"),
+ react_native_dep("java/com/facebook/testing/instrumentation/base:base"),
+ ]) if not IS_OSS_BUILD else [],
+)

ReactAndroid/src/androidTest/java/com/facebook/react/testing/rule/ReactNativeTestRule.java

@@ -0,0 +1,176 @@
+// 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.testing.rule;
+
+import android.app.Activity;
+import android.os.Build;
+import android.support.test.rule.ActivityTestRule;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+import com.facebook.react.ReactInstanceManager;
+import com.facebook.react.ReactPackage;
+import com.facebook.react.ReactRootView;
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.common.LifecycleState;
+import com.facebook.react.shell.MainReactPackage;
+import com.facebook.react.testing.ReactInstanceSpecForTest;
+import com.facebook.react.testing.ReactTestHelper;
+import com.facebook.react.testing.idledetection.ReactBridgeIdleSignaler;
+import com.facebook.react.testing.idledetection.ReactIdleDetectionUtil;
+import com.facebook.react.uimanager.ReactShadowNode;
+import com.facebook.react.uimanager.UIImplementation;
+import com.facebook.react.uimanager.UIManagerModule;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/** A test rule to simplify React Native rendering tests. */
+public class ReactNativeTestRule implements TestRule {
+
+ // we need a bigger timeout for CI builds because they run on a slow emulator
+ private static final long IDLE_TIMEOUT_MS = 120000;
+
+ @Rule public ActivityTestRule<Activity> mActivityRule = new ActivityTestRule<>(Activity.class);
+
+ private final String mBundleName;
+ private ReactPackage mReactPackage;
+ private ReactInstanceManager mReactInstanceManager;
+ private ReactBridgeIdleSignaler mBridgeIdleSignaler;
+ private ReactRootView mView;
+ private CountDownLatch mLatch;
+
+ public ReactNativeTestRule(String bundleName) {
+ this(bundleName, null);
+ }
+
+ public ReactNativeTestRule(String bundleName, ReactPackage reactPackage) {
+ mBundleName = bundleName;
+ mReactPackage = reactPackage;
+ }
+
+ @Override
+ public Statement apply(final Statement base, final Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ setUp();
+ base.evaluate();
+ tearDown();
+ }
+ };
+ }
+
+ @SuppressWarnings("deprecation")
+ private void setUp() {
+ final Activity activity = mActivityRule.launchActivity(null);
+ mView = new ReactRootView(activity);
+
+ activity.runOnUiThread(
+ new Runnable() {
+ @Override
+ public void run() {
+ mBridgeIdleSignaler = new ReactBridgeIdleSignaler();
+ mReactInstanceManager =
+ ReactTestHelper.getReactTestFactory()
+ .getReactInstanceManagerBuilder()
+ .setApplication(activity.getApplication())
+ .setBundleAssetName(mBundleName)
+ .setInitialLifecycleState(LifecycleState.BEFORE_CREATE)
+ .setBridgeIdleDebugListener(mBridgeIdleSignaler)
+ .addPackage(mReactPackage != null ? mReactPackage : new MainReactPackage())
+ .build();
+ mReactInstanceManager.onHostResume(activity);
+
+ // This threading garbage will be replaced by Surface
+ final AtomicBoolean isLayoutUpdated = new AtomicBoolean(false);
+ mReactInstanceManager.addReactInstanceEventListener(
+ new ReactInstanceManager.ReactInstanceEventListener() {
+ @Override
+ public void onReactContextInitialized(ReactContext reactContext) {
+ final UIManagerModule uiManagerModule =
+ reactContext.getCatalystInstance().getNativeModule(UIManagerModule.class);
+ uiManagerModule
+ .getUIImplementation()
+ .setLayoutUpdateListener(
+ new UIImplementation.LayoutUpdateListener() {
+ @Override
+ public void onLayoutUpdated(ReactShadowNode reactShadowNode) {
+ uiManagerModule.getUIImplementation().removeLayoutUpdateListener();
+ isLayoutUpdated.set(true);
+ }
+ });
+ }
+ });
+ mView
+ .getViewTreeObserver()
+ .addOnGlobalLayoutListener(
+ new OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ if (isLayoutUpdated.get()) {
+ mView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ mLatch.countDown();
+ }
+ }
+ });
+ }
+ });
+ }
+
+ private void tearDown() {
+ final ReactRootView view = mView;
+ final ReactInstanceManager reactInstanceManager = mReactInstanceManager;
+ mView = null;
+ mReactInstanceManager = null;
+ mActivityRule
+ .getActivity()
+ .runOnUiThread(
+ new Runnable() {
+ @Override
+ public void run() {
+ view.unmountReactApplication();
+ reactInstanceManager.destroy();
+ }
+ });
+ }
+
+ /** Renders the react component and waits until the layout has completed before returning */
+ public void render(final String componentName) {
+ mLatch = new CountDownLatch(1);
+ final Activity activity = mActivityRule.getActivity();
+ activity.runOnUiThread(
+ new Runnable() {
+ @Override
+ public void run() {
+ ReactRootView view = getView();
+ view.startReactApplication(mReactInstanceManager, componentName);
+ activity.setContentView(view);
+ }
+ });
+ int timeoutSec = 10;
+ try {
+ mLatch.await(timeoutSec, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(
+ "Failed to render " + componentName + " after " + timeoutSec + " seconds");
+ }
+ }
+
+ public void waitForIdleSync() {
+ ReactIdleDetectionUtil.waitForBridgeAndUIIdle(
+ mBridgeIdleSignaler,
+ mReactInstanceManager.getCurrentReactContext(),
+ IDLE_TIMEOUT_MS);
+ }
+
+ /** Returns the react view */
+ public ReactRootView getView() {
+ return mView;
+ }
+}

ReactAndroid/src/androidTest/java/com/facebook/react/testing/ScreenshotingFrameLayout.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/testing/SingleTouchGestureGenerator.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/testing/StringRecordingModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/tests/AnimatedTransformTest.java

@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2013-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+package com.facebook.react.tests;
+
+import android.view.View;
+
+
+import com.facebook.react.testing.ReactInstanceSpecForTest;
+import com.facebook.react.testing.StringRecordingModule;
+import com.facebook.react.bridge.JavaScriptModule;
+import com.facebook.react.testing.ReactAppInstrumentationTestCase;
+import com.facebook.react.testing.ReactTestHelper;
+
+/**
+ * Integration test for {@code removeClippedSubviews} property that verify correct scrollview
+ * behavior
+ */
+public class AnimatedTransformTest extends ReactAppInstrumentationTestCase {
+
+ private StringRecordingModule mStringRecordingModule;
+
+ @Override
+ protected String getReactApplicationKeyUnderTest() {
+ return "AnimatedTransformTestApp";
+ }
+
+ @Override
+ protected ReactInstanceSpecForTest createReactInstanceSpecForTest() {
+ mStringRecordingModule = new StringRecordingModule();
+ return super.createReactInstanceSpecForTest()
+ .addNativeModule(mStringRecordingModule);
+ }
+
+ public void testAnimatedRotation() {
+ waitForBridgeAndUIIdle();
+
+ View button = ReactTestHelper.getViewWithReactTestId(
+ getActivity().getRootView(),
+ "TouchableOpacity");
+
+ // Tap the button which triggers the animated transform containing the
+ // rotation strings.
+ createGestureGenerator().startGesture(button).endGesture();
+ waitForBridgeAndUIIdle();
+
+ // The previous cast error will prevent it from getting here
+ assertEquals(2, mStringRecordingModule.getCalls().size());
+ }
+
+}

ReactAndroid/src/androidTest/java/com/facebook/react/tests/BUCK

@@ -2,11 +2,12 @@
rn_android_library(
name = "tests",
- srcs = glob(["**/*.java"]),
+ srcs = glob(["*.java"]),
visibility = [
"PUBLIC",
],
deps = [
+ react_native_dep("third-party/android/support/v7/appcompat-orig:appcompat"),
react_native_dep("third-party/android/support/v4:lib-support-v4"),
react_native_dep("third-party/java/jsr-305:jsr-305"),
react_native_dep("third-party/java/junit:junit"),

ReactAndroid/src/androidTest/java/com/facebook/react/tests/CatalystMeasureLayoutTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/tests/CatalystMultitouchHandlingTestCase.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/tests/CatalystNativeJavaToJSArgumentsTestCase.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/tests/CatalystNativeJavaToJSReturnValuesTestCase.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/tests/CatalystNativeJSToJavaParametersTestCase.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/tests/CatalystSubviewsClippingTestCase.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/tests/CatalystTouchBubblingTestCase.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/tests/CatalystUIManagerTestCase.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/BUCK

@@ -0,0 +1,29 @@
+# BUILD FILE SYNTAX: SKYLARK
+load(
+ "//tools/build_defs/oss:rn_defs.bzl",
+ "IS_OSS_BUILD",
+ "react_native_dep",
+ "react_native_integration_tests_target",
+ "react_native_target",
+ "rn_android_library",
+)
+
+rn_android_library(
+ name = "core",
+ srcs = glob(["*.java"]),
+ deps = ([
+ react_native_dep("third-party/java/espresso:espresso"),
+ react_native_dep("third-party/java/fest:fest"),
+ react_native_dep("third-party/java/junit:junit"),
+ react_native_dep("third-party/java/testing-support-lib:testing-support-lib"),
+ react_native_integration_tests_target("java/com/facebook/react/testing:testing"),
+ react_native_integration_tests_target("java/com/facebook/react/testing/rule:rule"),
+ react_native_target("java/com/facebook/react:react"),
+ react_native_target("java/com/facebook/react/bridge:bridge"),
+ react_native_target("java/com/facebook/react/common:common"),
+ react_native_target("java/com/facebook/react/shell:shell"),
+ react_native_target("java/com/facebook/react/uimanager:uimanager"),
+ ]) + ([
+ react_native_dep("java/com/facebook/fbreact/testing:testing"),
+ ]) if not IS_OSS_BUILD else [],
+)

ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/ReactInstanceManagerTest.java

@@ -0,0 +1,92 @@
+// 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.tests.core;
+
+import android.app.Activity;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import com.facebook.react.ReactInstanceManager;
+import com.facebook.react.ReactRootView;
+import com.facebook.react.common.LifecycleState;
+import com.facebook.react.shell.MainReactPackage;
+import com.facebook.react.testing.ReactTestHelper;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class ReactInstanceManagerTest {
+
+ private static final String TEST_MODULE = "ViewLayoutTestApp";
+
+ private ReactInstanceManager mReactInstanceManager;
+ private ReactRootView mReactRootView;
+
+ @Rule public ActivityTestRule<Activity> mActivityRule = new ActivityTestRule<>(Activity.class);
+
+ @Before
+ public void setup() {
+ Activity activity = mActivityRule.getActivity();
+ mReactRootView = new ReactRootView(activity);
+ mReactInstanceManager =
+ ReactTestHelper.getReactTestFactory()
+ .getReactInstanceManagerBuilder()
+ .setApplication(activity.getApplication())
+ .setBundleAssetName("AndroidTestBundle.js")
+ .setInitialLifecycleState(LifecycleState.BEFORE_CREATE)
+ .addPackage(new MainReactPackage())
+ .build();
+ }
+
+ @After
+ public void tearDown() {
+ final ReactRootView reactRootView = mReactRootView;
+ final ReactInstanceManager reactInstanceManager = mReactInstanceManager;
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ reactRootView.unmountReactApplication();
+ reactInstanceManager.destroy();
+ }
+ });
+ }
+
+ @Test
+ @UiThreadTest
+ public void testMountUnmount() {
+ mReactInstanceManager.onHostResume(mActivityRule.getActivity());
+ mReactRootView.startReactApplication(mReactInstanceManager, TEST_MODULE);
+ mReactRootView.unmountReactApplication();
+ }
+
+ @Test
+ @UiThreadTest
+ public void testResume() throws InterruptedException {
+ mReactInstanceManager.onHostResume(mActivityRule.getActivity());
+ mReactRootView.startReactApplication(mReactInstanceManager, TEST_MODULE);
+ mReactInstanceManager.onHostResume(mActivityRule.getActivity());
+ }
+
+ @Test
+ @UiThreadTest
+ public void testRecreateContext() throws InterruptedException {
+ mReactInstanceManager.onHostResume(mActivityRule.getActivity());
+ mReactInstanceManager.createReactContextInBackground();
+ mReactRootView.startReactApplication(mReactInstanceManager, TEST_MODULE);
+ }
+
+ @Test
+ @UiThreadTest
+ public void testMountTwice() {
+ mReactInstanceManager.onHostResume(mActivityRule.getActivity());
+ mReactRootView.startReactApplication(mReactInstanceManager, TEST_MODULE);
+ mReactInstanceManager.attachRootView(mReactRootView);
+ }
+}

ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/ReactRootViewTest.java

@@ -0,0 +1,132 @@
+// 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.tests.core;
+
+import static org.fest.assertions.api.Assertions.assertThat;
+
+import android.app.Instrumentation;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import com.facebook.react.ReactPackage;
+import com.facebook.react.ReactRootView;
+import com.facebook.react.bridge.ModuleSpec;
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.shell.MainReactPackage;
+import com.facebook.react.testing.StringRecordingModule;
+import com.facebook.react.testing.rule.ReactNativeTestRule;
+import java.util.ArrayList;
+import java.util.List;
+import javax.inject.Provider;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class ReactRootViewTest {
+
+ final StringRecordingModule mRecordingModule = new StringRecordingModule();
+ final ReactPackage mReactPackage = new MainReactPackage() {
+ @Override
+ public List<ModuleSpec> getNativeModules(ReactApplicationContext context) {
+ List<ModuleSpec> modules = new ArrayList<>(super.getNativeModules(context));
+ modules.add(
+ ModuleSpec.nativeModuleSpec(
+ StringRecordingModule.class,
+ new Provider<NativeModule>() {
+ @Override
+ public NativeModule get() {
+ return mRecordingModule;
+ }
+ }));
+ return modules;
+ }
+ };
+
+ @Rule
+ public ReactNativeTestRule mReactNativeRule =
+ new ReactNativeTestRule("AndroidTestBundle.js", mReactPackage);
+
+ @Before
+ public void setup() {
+ mReactNativeRule.render("CatalystRootViewTestApp");
+ }
+
+ @Test
+ public void testResizeRootView() {
+ final ReactRootView rootView = mReactNativeRule.getView();
+ final View childView = rootView.getChildAt(0);
+
+ assertThat(rootView.getWidth()).isEqualTo(childView.getWidth());
+
+ final int newWidth = rootView.getWidth() / 2;
+
+ Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ instrumentation.runOnMainSync(
+ new Runnable() {
+ @Override
+ public void run() {
+ rootView.setLayoutParams(new FrameLayout.LayoutParams(
+ newWidth,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ }
+ });
+
+ instrumentation.waitForIdleSync();
+ mReactNativeRule.waitForIdleSync();
+
+ assertThat(newWidth).isEqualTo(childView.getWidth());
+ }
+
+ /**
+ * Verify that removing the root view from hierarchy will trigger subviews removal both on JS and
+ * native side
+ */
+ @Test
+ public void testRemoveRootView() {
+ final ReactRootView rootView = mReactNativeRule.getView();
+
+ assertThat(rootView.getChildCount()).isEqualTo(1);
+
+ Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ instrumentation.runOnMainSync(
+ new Runnable() {
+ @Override
+ public void run() {
+ ViewGroup parent = (ViewGroup) rootView.getParent();
+ parent.removeView(rootView);
+ // removing from parent should not remove child views, child views should be removed as
+ // an effect of native call to UIManager.removeRootView
+ assertThat(rootView.getChildCount()).isEqualTo(1);
+ }
+ });
+
+ instrumentation.waitForIdleSync();
+ mReactNativeRule.waitForIdleSync();
+
+ assertThat(mRecordingModule.getCalls().size())
+ .isEqualTo(0)
+ .overridingErrorMessage("root component should not be automatically unmounted");
+ assertThat(rootView.getChildCount()).isEqualTo(1);
+
+ instrumentation.runOnMainSync(
+ new Runnable() {
+ @Override
+ public void run() {
+ rootView.unmountReactApplication();
+ }
+ });
+ mReactNativeRule.waitForIdleSync();
+
+ assertThat(mRecordingModule.getCalls().size()).isEqualTo(1);
+ assertThat(mRecordingModule.getCalls().get(0)).isEqualTo("RootComponentWillUnmount");
+ assertThat(rootView.getChildCount()).isEqualTo(0);
+ }
+}

ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/WritableNativeMapTest.java

@@ -0,0 +1,104 @@
+package com.facebook.react.tests.core;
+
+import static org.fest.assertions.api.Assertions.assertThat;
+
+import android.support.test.runner.AndroidJUnit4;
+import com.facebook.react.bridge.UnexpectedNativeTypeException;
+import com.facebook.react.bridge.WritableNativeArray;
+import com.facebook.react.bridge.WritableNativeMap;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class WritableNativeMapTest {
+
+ private WritableNativeMap mMap;
+
+ @Before
+ public void setup() {
+ mMap = new WritableNativeMap();
+ mMap.putBoolean("boolean", true);
+ mMap.putDouble("double", 1.2);
+ mMap.putInt("int", 1);
+ mMap.putString("string", "abc");
+ mMap.putMap("map", new WritableNativeMap());
+ mMap.putArray("array", new WritableNativeArray());
+ mMap.putBoolean("dvacca", true);
+ mMap.setUseNativeAccessor(true);
+ }
+
+ @Test
+ public void testBoolean() {
+ assertThat(mMap.getBoolean("boolean")).isEqualTo(true);
+ }
+
+ @Test(expected = UnexpectedNativeTypeException.class)
+ public void testBooleanInvalidType() {
+ mMap.getBoolean("string");
+ }
+
+ @Test
+ public void testDouble() {
+ assertThat(mMap.getDouble("double")).isEqualTo(1.2);
+ }
+
+ @Test(expected = UnexpectedNativeTypeException.class)
+ public void testDoubleInvalidType() {
+ mMap.getDouble("string");
+ }
+
+ @Test
+ public void testInt() {
+ assertThat(mMap.getInt("int")).isEqualTo(1);
+ }
+
+ @Test(expected = UnexpectedNativeTypeException.class)
+ public void testIntInvalidType() {
+ mMap.getInt("string");
+ }
+
+ @Test
+ public void testString() {
+ assertThat(mMap.getString("string")).isEqualTo("abc");
+ }
+
+ @Test(expected = UnexpectedNativeTypeException.class)
+ public void testStringInvalidType() {
+ mMap.getString("int");
+ }
+
+ @Test
+ public void testMap() {
+ assertThat(mMap.getMap("map")).isNotNull();
+ }
+
+ @Test(expected = UnexpectedNativeTypeException.class)
+ public void testMapInvalidType() {
+ mMap.getMap("string");
+ }
+
+ @Test
+ public void testArray() {
+ assertThat(mMap.getArray("array")).isNotNull();
+ }
+
+ @Test(expected = UnexpectedNativeTypeException.class)
+ public void testArrayInvalidType() {
+ mMap.getArray("string");
+ }
+
+ @Ignore("Needs to be implemented")
+ @Test
+ public void testErrorMessageContainsKey() {
+ String key = "fkg";
+ try {
+ mMap.getString(key);
+ Assert.fail("Expected an UnexpectedNativeTypeException to be thrown");
+ } catch (UnexpectedNativeTypeException e) {
+ assertThat(e.getMessage()).contains(key);
+ }
+ }
+}

ReactAndroid/src/androidTest/java/com/facebook/react/tests/DatePickerDialogTestCase.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/tests/ImageErrorTestCase.java

@@ -0,0 +1,46 @@
+/**
+ * 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.tests;
+
+import android.view.View;
+import com.facebook.react.testing.ReactAppInstrumentationTestCase;
+import com.facebook.react.testing.ReactInstanceSpecForTest;
+import com.facebook.react.testing.StringRecordingModule;
+
+/**
+ * Simple test case to check that onError does not get called with undefined
+ */
+public class ImageErrorTestCase extends ReactAppInstrumentationTestCase {
+
+ private StringRecordingModule mStringRecordingModule;
+
+ @Override
+ protected String getReactApplicationKeyUnderTest() {
+ return "ImageErrorTestApp";
+ }
+
+ public void testErrorHasCause() throws Exception {
+ assertNotNull(getViewByTestId("image-1"));
+ assertNotNull(getViewByTestId("image-2"));
+ assertNotNull(getViewByTestId("image-3"));
+
+ Thread.sleep(3000);
+
+ assertEquals(3, mStringRecordingModule.getCalls().size());
+ assertEquals("Got error: Unsupported uri scheme! Uri is: ", mStringRecordingModule.getCalls().get(0));
+ assertEquals("Got error: /does/not/exist: open failed: ENOENT (No such file or directory)", mStringRecordingModule.getCalls().get(1));
+ assertEquals("Got error: Unexpected HTTP code Response{protocol=http/1.1, code=404, message=Not Found, url=https://typo_error_facebook.github.io/react/logo-og.png}", mStringRecordingModule.getCalls().get(2));
+ }
+
+ @Override
+ protected ReactInstanceSpecForTest createReactInstanceSpecForTest() {
+ mStringRecordingModule = new StringRecordingModule();
+ return super.createReactInstanceSpecForTest()
+ .addNativeModule(mStringRecordingModule);
+ }
+}

ReactAndroid/src/androidTest/java/com/facebook/react/tests/ImageOverlayColorTestCase.java

@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+package com.facebook.react.tests;
+
+import android.view.View;
+import com.facebook.react.testing.ReactAppInstrumentationTestCase;
+
+/**
+ * Simple test case for passing overlayColor prop to the Image component
+ */
+public class ImageOverlayColorTestCase extends ReactAppInstrumentationTestCase {
+
+ @Override
+ protected String getReactApplicationKeyUnderTest() {
+ return "ImageOverlayColorTestApp";
+ }
+
+ public void testOverlayColorDoesNotCrash() {
+ View image = getViewByTestId("image");
+ assertNotNull(image);
+ }
+}

ReactAndroid/src/androidTest/java/com/facebook/react/tests/InitialPropsTestCase.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/tests/JSLocaleTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/tests/JSResponderTestCase.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/tests/LayoutEventsTestCase.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/tests/NativeIdTestCase.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/tests/ProgressBarTestCase.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/tests/ReactHorizontalScrollViewTestCase.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/tests/ReactPickerTestCase.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/tests/ReactRootViewTestCase.java

@@ -1,105 +0,0 @@
-/**
- * Copyright (c) 2014-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-package com.facebook.react.tests;
-
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-
-import com.facebook.react.testing.ReactInstanceSpecForTest;
-import com.facebook.react.testing.ReactAppInstrumentationTestCase;
-import com.facebook.react.testing.StringRecordingModule;
-import com.facebook.react.ReactRootView;
-
-import org.junit.Ignore;
-
-/**
- * Integration test for {@link ReactRootView}.
- */
-public class ReactRootViewTestCase extends ReactAppInstrumentationTestCase {
-
- private StringRecordingModule mRecordingModule;
-
- @Override
- protected String getReactApplicationKeyUnderTest() {
- return "CatalystRootViewTestApp";
- }
-
- @Ignore("t6596940: fix intermittently failing test")
- public void testResizeRootView() throws Throwable {
- final ReactRootView rootView = (ReactRootView) getRootView();
- final View childView = rootView.getChildAt(0);
-
- assertEquals(rootView.getWidth(), childView.getWidth());
-
- final int newWidth = rootView.getWidth() / 2;
-
- runTestOnUiThread(
- new Runnable() {
- @Override
- public void run() {
- rootView.setLayoutParams(new FrameLayout.LayoutParams(
- newWidth,
- ViewGroup.LayoutParams.MATCH_PARENT));
- }
- });
-
- getInstrumentation().waitForIdleSync();
- waitForBridgeAndUIIdle();
-
- assertEquals(newWidth, childView.getWidth());
- }
-
- /**
- * Verify that removing the root view from hierarchy will trigger subviews removal both on JS and
- * native side
- */
- public void testRemoveRootView() throws Throwable {
- final ReactRootView rootView = (ReactRootView) getRootView();
-
- assertEquals(1, rootView.getChildCount());
-
- runTestOnUiThread(
- new Runnable() {
- @Override
- public void run() {
- ViewGroup parent = (ViewGroup) rootView.getParent();
- parent.removeView(rootView);
- // removing from parent should not remove child views, child views should be removed as
- // an effect of native call to UIManager.removeRootView
- assertEquals(1, rootView.getChildCount());
- }
- });
-
- getInstrumentation().waitForIdleSync();
- waitForBridgeAndUIIdle();
-
- assertEquals("root component should not be automatically unmounted", 0, mRecordingModule.getCalls().size());
- assertEquals(1, rootView.getChildCount());
-
- runTestOnUiThread(
- new Runnable() {
- @Override
- public void run() {
- rootView.unmountReactApplication();
- }
- });
- waitForBridgeAndUIIdle();
-
- assertEquals(1, mRecordingModule.getCalls().size());
- assertEquals("RootComponentWillUnmount", mRecordingModule.getCalls().get(0));
- assertEquals(0, rootView.getChildCount());
- }
-
- @Override
- protected ReactInstanceSpecForTest createReactInstanceSpecForTest() {
- mRecordingModule = new StringRecordingModule();
- return new ReactInstanceSpecForTest()
- .addNativeModule(mRecordingModule);
- }
-}

ReactAndroid/src/androidTest/java/com/facebook/react/tests/ReactScrollViewTestCase.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/tests/ReactSwipeRefreshLayoutTestCase.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/tests/ShareTestCase.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/tests/TestIdTestCase.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/tests/TextInputTestCase.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/tests/TimePickerDialogTestCase.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/java/com/facebook/react/tests/ViewRenderingTestCase.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/js/AnimatedTransformTestModule.js

@@ -0,0 +1,81 @@
+/**
+ * Copyright (c) 2013-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @providesModule AnimatedTransformTestModule
+ */
+
+'use strict';
+
+var BatchedBridge = require('BatchedBridge');
+var React = require('React');
+var StyleSheet = require('StyleSheet');
+var View = require('View');
+var TouchableOpacity = require('TouchableOpacity');
+var Text = require('Text');
+var RecordingModule = require('NativeModules').Recording;
+
+const styles = StyleSheet.create({
+ base: {
+ width: 200,
+ height: 200,
+ backgroundColor: 'red',
+ transform: [{rotate: '0deg'}],
+ },
+ transformed: {
+ transform: [{rotate: '45deg'}],
+ },
+});
+
+/**
+ * This app presents a TouchableOpacity which was the simplest way to
+ * demonstrate this issue. Tapping the TouchableOpacity causes an animated
+ * transform to be created for the rotation property. Since the property isn't
+ * animated itself, it comes through as a static property, but static properties
+ * can't currently handle strings which causes a string->double cast exception.
+ */
+class AnimatedTransformTestApp extends React.Component {
+ constructor(props) {
+ super(props);
+ this.toggle = this.toggle.bind(this);
+ }
+
+ state = {
+ flag: false,
+ };
+
+ toggle() {
+ this.setState({
+ flag: !this.state.flag,
+ });
+ }
+
+ render() {
+ // Using this to verify if its fixed.
+ RecordingModule.record('render');
+
+ return (
+ <View style={StyleSheet.absoluteFill}>
+ <TouchableOpacity
+ onPress={this.toggle}
+ testID="TouchableOpacity"
+ style={[styles.base, this.state.flag ? styles.transformed : null]}>
+ <Text>TouchableOpacity</Text>
+ </TouchableOpacity>
+ </View>
+ );
+ }
+}
+
+var AnimatedTransformTestModule = {
+ AnimatedTransformTestApp: AnimatedTransformTestApp,
+};
+
+BatchedBridge.registerCallableModule(
+ 'AnimatedTransformTestModule',
+ AnimatedTransformTestModule
+);
+
+module.exports = AnimatedTransformTestModule;

ReactAndroid/src/androidTest/js/Asserts.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -9,9 +9,9 @@
'use strict';
-var Assert = require('NativeModules').Assert;
+const Assert = require('NativeModules').Assert;
-var Asserts = {
+const Asserts = {
assertEquals: function(expected, actual, msg) {
if (expected !== actual) {
Assert.fail(

ReactAndroid/src/androidTest/js/CatalystRootViewTestModule.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -9,9 +9,10 @@
'use strict';
-var React = require('React');
-var Recording = require('NativeModules').Recording;
-var View = require('View');
+const React = require('React');
+const Recording = require('NativeModules').Recording;
+const StyleSheet = require('StyleSheet');
+const View = require('View');
class CatalystRootViewTestApp extends React.Component {
componentWillUnmount() {
@@ -19,10 +20,16 @@
}
render() {
- return <View collapsable={false} style={{alignSelf: 'stretch'}} />;
+ return <View collapsable={false} style={styles.container} />;
}
}
+const styles = StyleSheet.create({
+ container: {
+ alignSelf: 'stretch',
+ },
+});
+
module.exports = {
CatalystRootViewTestApp: CatalystRootViewTestApp,
};

ReactAndroid/src/androidTest/js/DatePickerDialogTestModule.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -9,11 +9,12 @@
'use strict';
-var BatchedBridge = require('BatchedBridge');
-var DatePickerAndroid = require('DatePickerAndroid');
-var React = require('React');
-var RecordingModule = require('NativeModules').DatePickerDialogRecordingModule;
-var View = require('View');
+const BatchedBridge = require('BatchedBridge');
+const DatePickerAndroid = require('DatePickerAndroid');
+const React = require('React');
+const RecordingModule = require('NativeModules')
+ .DatePickerDialogRecordingModule;
+const View = require('View');
class DatePickerDialogTestApp extends React.Component {
render() {
@@ -21,7 +22,7 @@
}
}
-var DatePickerDialogTestModule = {
+const DatePickerDialogTestModule = {
DatePickerDialogTestApp: DatePickerDialogTestApp,
showDatePickerDialog: function(options) {
DatePickerAndroid.open(options).then(

ReactAndroid/src/androidTest/js/ImageErrorTestApp.js

@@ -0,0 +1,58 @@
+/**
+ * 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
+ */
+
+'use strict';
+
+const React = require('React');
+const Image = require('Image');
+const StyleSheet = require('StyleSheet');
+const View = require('View');
+
+const RecordingModule = require('NativeModules').Recording;
+
+class ImageErrorTestApp extends React.Component {
+ onError = e => {
+ RecordingModule.record('Got error: ' + e.nativeEvent.error);
+ };
+
+ render() {
+ // For some reason image-2 needs explicit height. Without it onError is not triggered.
+ return (
+ <View>
+ <Image
+ testID="image-1"
+ source={{uri: '/does/not/exist'}}
+ onError={this.onError}
+ />
+ <Image
+ testID="image-2"
+ source={{uri: 'file:///does/not/exist'}}
+ style={styles.image}
+ onError={this.onError}
+ />
+ <Image
+ testID="image-3"
+ source={{
+ uri: 'https://TYPO_ERROR_facebook.github.io/react/logo-og.png',
+ }}
+ onError={this.onError}
+ />
+ </View>
+ );
+ }
+}
+
+const styles = StyleSheet.create({
+ image: {
+ height: 50,
+ width: 50,
+ },
+});
+
+module.exports = ImageErrorTestApp;

ReactAndroid/src/androidTest/js/ImageOverlayColorTestApp.js

@@ -0,0 +1,29 @@
+/**
+ * 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
+ */
+
+'use strict';
+
+const React = require('React');
+const Image = require('Image');
+
+class ImageOverlayColorTestApp extends React.Component {
+ render() {
+ const uri =
+ 'data:image/gif;base64,' +
+ 'R0lGODdhMAAwAPAAAAAAAP///ywAAAAAMAAwAAAC8IyPqcvt3wCcDkiLc7C0qwyGHhSWpjQu5yqmCYsapy' +
+ 'uvUUlvONmOZtfzgFzByTB10QgxOR0TqBQejhRNzOfkVJ+5YiUqrXF5Y5lKh/DeuNcP5yLWGsEbtLiOSpa/' +
+ 'TPg7JpJHxyendzWTBfX0cxOnKPjgBzi4diinWGdkF8kjdfnycQZXZeYGejmJlZeGl9i2icVqaNVailT6F5' +
+ 'iJ90m6mvuTS4OK05M0vDk0Q4XUtwvKOzrcd3iq9uisF81M1OIcR7lEewwcLp7tuNNkM3uNna3F2JQFo97V' +
+ 'riy/Xl4/f1cf5VWzXyym7PHhhx4dbgYKAAA7';
+
+ return <Image testID="image" source={{uri: uri}} overlayColor="#FF0000" />;
+ }
+}
+
+module.exports = ImageOverlayColorTestApp;

ReactAndroid/src/androidTest/js/InitialPropsTestApp.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -9,9 +9,9 @@
'use strict';
-var React = require('React');
-var RecordingModule = require('NativeModules').InitialPropsRecordingModule;
-var Text = require('Text');
+const React = require('React');
+const RecordingModule = require('NativeModules').InitialPropsRecordingModule;
+const Text = require('Text');
class InitialPropsTestApp extends React.Component {
componentDidMount() {

ReactAndroid/src/androidTest/js/JSResponderTestApp.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -9,12 +9,12 @@
'use strict';
-var React = require('React');
-var StyleSheet = require('StyleSheet');
-var View = require('View');
-var Text = require('Text');
-var PanResponder = require('PanResponder');
-var ScrollView = require('ScrollView');
+const React = require('React');
+const StyleSheet = require('StyleSheet');
+const View = require('View');
+const Text = require('Text');
+const PanResponder = require('PanResponder');
+const ScrollView = require('ScrollView');
class JSResponderTestApp extends React.Component {
_handleMoveShouldSetPanResponder = (e, gestureState) => {
@@ -28,8 +28,8 @@
}
render() {
- var views = [];
- for (var i = 0; i < 100; i++) {
+ const views = [];
+ for (let i = 0; i < 100; i++) {
views[i] = (
<View key={i} style={styles.row} collapsable={false}>
<Text>I am row {i}</Text>
@@ -49,7 +49,7 @@
}
}
-var styles = StyleSheet.create({
+const styles = StyleSheet.create({
container: {
flex: 1,
},

ReactAndroid/src/androidTest/js/LayoutEventsTestApp.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -9,10 +9,11 @@
'use strict';
-var React = require('React');
-var View = require('View');
+const React = require('React');
+const View = require('View');
+const StyleSheet = require('StyleSheet');
-var RecordingModule = require('NativeModules').Recording;
+const RecordingModule = require('NativeModules').Recording;
const LAYOUT_SPECS = [
[10, 10, 100, 100],
@@ -31,7 +32,7 @@
}
handleOnLayout = e => {
- var layout = e.nativeEvent.layout;
+ const layout = e.nativeEvent.layout;
RecordingModule.record(
layout.x + ',' + layout.y + '-' + layout.width + 'x' + layout.height,
);
@@ -61,7 +62,7 @@
<View
onLayout={this.handleParentOnLayout}
testID="parent"
- style={{left: 0, top: 0, width: 500, height: 500}}>
+ style={styles.container}>
<View
onLayout={this.handleOnLayout}
testID="container"
@@ -77,4 +78,13 @@
}
}
+const styles = StyleSheet.create({
+ container: {
+ left: 0,
+ top: 0,
+ width: 500,
+ height: 500,
+ },
+});
+
module.exports = LayoutEventsTestApp;

ReactAndroid/src/androidTest/js/MeasureLayoutTestModule.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -9,16 +9,16 @@
'use strict';
-var BatchedBridge = require('BatchedBridge');
-var React = require('React');
-var ReactNative = require('ReactNative');
-var View = require('View');
-var StyleSheet = require('StyleSheet');
-var UIManager = require('UIManager');
+const BatchedBridge = require('BatchedBridge');
+const React = require('React');
+const ReactNative = require('ReactNative');
+const View = require('View');
+const StyleSheet = require('StyleSheet');
+const UIManager = require('UIManager');
-var assertEquals = require('Asserts').assertEquals;
+const assertEquals = require('Asserts').assertEquals;
-var styles = StyleSheet.create({
+const styles = StyleSheet.create({
A: {
width: 500,
height: 500,
@@ -46,7 +46,7 @@
},
});
-var A, B, C, D;
+let A, B, C, D;
class MeasureLayoutTestApp extends React.Component {
componentDidMount() {
@@ -72,7 +72,7 @@
assertEquals(false, true);
}
-var MeasureLayoutTestModule = {
+const MeasureLayoutTestModule = {
MeasureLayoutTestApp: MeasureLayoutTestApp,
verifyMeasureOnViewA: function() {
UIManager.measure(A, function(a, b, width, height, x, y) {

ReactAndroid/src/androidTest/js/MultitouchHandlingTestAppModule.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -9,11 +9,23 @@
'use strict';
-var React = require('React');
-var Recording = require('NativeModules').Recording;
-var StyleSheet = require('StyleSheet');
-var TouchEventUtils = require('fbjs/lib/TouchEventUtils');
-var View = require('View');
+const React = require('React');
+const Recording = require('NativeModules').Recording;
+const StyleSheet = require('StyleSheet');
+const View = require('View');
+
+const extractSingleTouch = nativeEvent => {
+ const touches = nativeEvent.touches;
+ const changedTouches = nativeEvent.changedTouches;
+ const hasTouches = touches && touches.length > 0;
+ const hasChangedTouches = changedTouches && changedTouches.length > 0;
+
+ return !hasTouches && hasChangedTouches
+ ? changedTouches[0]
+ : hasTouches
+ ? touches[0]
+ : nativeEvent;
+};
class TouchTestApp extends React.Component {
handleStartShouldSetResponder = e => {
@@ -21,12 +33,12 @@
};
handleOnResponderMove = e => {
- e = TouchEventUtils.extractSingleTouch(e.nativeEvent);
+ e = extractSingleTouch(e.nativeEvent);
Recording.record('move;' + e.touches.length);
};
handleResponderStart = e => {
- e = TouchEventUtils.extractSingleTouch(e.nativeEvent);
+ e = extractSingleTouch(e.nativeEvent);
if (e.touches) {
Recording.record('start;' + e.touches.length);
} else {
@@ -35,7 +47,7 @@
};
handleResponderEnd = e => {
- e = TouchEventUtils.extractSingleTouch(e.nativeEvent);
+ e = extractSingleTouch(e.nativeEvent);
if (e.touches) {
Recording.record('end;' + e.touches.length);
} else {
@@ -57,7 +69,7 @@
}
}
-var styles = StyleSheet.create({
+const styles = StyleSheet.create({
container: {
flex: 1,
},

ReactAndroid/src/androidTest/js/NativeIdTestModule.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/androidTest/js/PickerAndroidTestModule.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -9,15 +9,15 @@
'use strict';
-var BatchedBridge = require('BatchedBridge');
-var React = require('React');
-var RecordingModule = require('NativeModules').PickerAndroidRecordingModule;
-var Picker = require('Picker');
-var View = require('View');
+const BatchedBridge = require('BatchedBridge');
+const React = require('React');
+const RecordingModule = require('NativeModules').PickerAndroidRecordingModule;
+const Picker = require('Picker');
+const View = require('View');
-var Item = Picker.Item;
+const Item = Picker.Item;
-var appInstance;
+let appInstance;
class PickerAndroidTestApp extends React.Component {
state = {
@@ -69,7 +69,7 @@
};
}
-var PickerAndroidTestModule = {
+const PickerAndroidTestModule = {
PickerAndroidTestApp: PickerAndroidTestApp,
selectItem: function(value) {
appInstance.setState({selected: value});

ReactAndroid/src/androidTest/js/ProgressBarTestModule.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -9,12 +9,14 @@
'use strict';
-var BatchedBridge = require('BatchedBridge');
-var React = require('React');
-var ProgressBar = require('ProgressBarAndroid');
-var View = require('View');
+const BatchedBridge = require('BatchedBridge');
+const React = require('React');
+const ReactNative = require('react-native');
+const {StyleSheet} = ReactNative;
+const ProgressBar = require('ProgressBarAndroid');
+const View = require('View');
-var renderApplication = require('renderApplication');
+const renderApplication = require('renderApplication');
class ProgressBarSampleApp extends React.Component {
state = {};
@@ -29,7 +31,7 @@
<ProgressBar styleAttr="Inverse" testID="Inverse" />
<ProgressBar styleAttr="SmallInverse" testID="SmallInverse" />
<ProgressBar styleAttr="LargeInverse" testID="LargeInverse" />
- <View style={{width: 200}}>
+ <View style={styles.wrapper}>
<ProgressBar styleAttr="Horizontal" testID="Horizontal200" />
</View>
</View>
@@ -37,7 +39,7 @@
}
}
-var ProgressBarTestModule = {
+const ProgressBarTestModule = {
renderProgressBarApplication: function(rootTag) {
renderApplication(ProgressBarSampleApp, {}, rootTag);
},
@@ -48,4 +50,10 @@
ProgressBarTestModule,
);
+const styles = StyleSheet.create({
+ wrapper: {
+ width: 200,
+ },
+});
+
module.exports = ProgressBarTestModule;

ReactAndroid/src/androidTest/js/ScrollViewTestModule.js

@@ -1,31 +1,40 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
+ * @flow
*/
'use strict';
-var BatchedBridge = require('BatchedBridge');
-var React = require('React');
-var createReactClass = require('create-react-class');
-var View = require('View');
-var ScrollView = require('ScrollView');
-var Text = require('Text');
-var StyleSheet = require('StyleSheet');
-var TouchableWithoutFeedback = require('TouchableWithoutFeedback');
-var ScrollListener = require('NativeModules').ScrollListener;
+const BatchedBridge = require('BatchedBridge');
+const React = require('React');
+const View = require('View');
+const ScrollView = require('ScrollView');
+const Text = require('Text');
+const StyleSheet = require('StyleSheet');
+const TouchableWithoutFeedback = require('TouchableWithoutFeedback');
+const ScrollListener = require('NativeModules').ScrollListener;
-var NUM_ITEMS = 100;
+const NUM_ITEMS = 100;
+
+import type {PressEvent} from 'CoreEventTypes';
// Shared by integration tests for ScrollView and HorizontalScrollView
-var scrollViewApp;
+let scrollViewApp;
+
+type ItemProps = $ReadOnly<{|
+ onPress: (event: PressEvent) => void,
+ text: string,
+|}>;
+
+type ItemState = {||};
-class Item extends React.Component {
+class Item extends React.Component<ItemProps, ItemState> {
render() {
return (
<TouchableWithoutFeedback onPress={this.props.onPress}>
@@ -37,9 +46,9 @@
}
}
-var getInitialState = function() {
- var data = [];
- for (var i = 0; i < NUM_ITEMS; i++) {
+const getInitialState = function() {
+ const data = [];
+ for (let i = 0; i < NUM_ITEMS; i++) {
data[i] = {text: 'Item ' + i + '!'};
}
return {
@@ -47,92 +56,107 @@
};
};
-var onScroll = function(e) {
+const onScroll = function(e) {
ScrollListener.onScroll(
e.nativeEvent.contentOffset.x,
e.nativeEvent.contentOffset.y,
);
};
-var onScrollBeginDrag = function(e) {
+const onScrollBeginDrag = function(e) {
ScrollListener.onScrollBeginDrag(
e.nativeEvent.contentOffset.x,
e.nativeEvent.contentOffset.y,
);
};
-var onScrollEndDrag = function(e) {
+const onScrollEndDrag = function(e) {
ScrollListener.onScrollEndDrag(
e.nativeEvent.contentOffset.x,
e.nativeEvent.contentOffset.y,
);
};
-var onItemPress = function(itemNumber) {
+const onItemPress = function(itemNumber) {
ScrollListener.onItemPress(itemNumber);
};
-var ScrollViewTestApp = createReactClass({
- displayName: 'ScrollViewTestApp',
- getInitialState: getInitialState,
- onScroll: onScroll,
- onItemPress: onItemPress,
- onScrollBeginDrag: onScrollBeginDrag,
- onScrollEndDrag: onScrollEndDrag,
+type Props = $ReadOnly<{||}>;
+type State = {|
+ data: $ReadOnlyArray<{|text: string|}>,
+|};
+
+class ScrollViewTestApp extends React.Component<Props, State> {
+ /* $FlowFixMe(>=0.87.0 site=react_native_fb) This comment suppresses an error
+ * found when Flow v0.87 was deployed. To see the error, delete this comment
+ * and run Flow. */
+ scrollView = React.createRef();
+ state = getInitialState();
+
+ scrollTo(destX: number, destY: number) {
+ const scrollView = this.scrollView.current;
+ if (scrollView == null) {
+ return;
+ }
- scrollTo: function(destX, destY) {
- this.refs.scrollView.scrollTo(destY, destX);
- },
+ scrollView.scrollTo(destY, destX);
+ }
- render: function() {
+ render() {
scrollViewApp = this;
- var children = this.state.data.map((item, index) => (
+ const children = this.state.data.map((item, index) => (
<Item
key={index}
text={item.text}
- onPress={this.onItemPress.bind(this, index)}
+ onPress={onItemPress.bind(this, index)}
/>
));
return (
<ScrollView
- onScroll={this.onScroll}
- onScrollBeginDrag={this.onScrollBeginDrag}
- onScrollEndDrag={this.onScrollEndDrag}
- ref="scrollView">
+ onScroll={onScroll}
+ onScrollBeginDrag={onScrollBeginDrag}
+ onScrollEndDrag={onScrollEndDrag}
+ ref={this.scrollView}>
{children}
</ScrollView>
);
- },
-});
+ }
+}
-var HorizontalScrollViewTestApp = createReactClass({
- displayName: 'HorizontalScrollViewTestApp',
- getInitialState: getInitialState,
- onScroll: onScroll,
- onItemPress: onItemPress,
+class HorizontalScrollViewTestApp extends React.Component<Props, State> {
+ /* $FlowFixMe(>=0.87.0 site=react_native_fb) This comment suppresses an error
+ * found when Flow v0.87 was deployed. To see the error, delete this comment
+ * and run Flow. */
+ scrollView = React.createRef();
+ state = getInitialState();
+
+ scrollTo(destX: number, destY: number) {
+ const scrollView = this.scrollView.current;
+ if (scrollView == null) {
+ return;
+ }
- scrollTo: function(destX, destY) {
- this.refs.scrollView.scrollTo(destY, destX);
- },
+ scrollView.scrollTo(destY, destX);
+ }
- render: function() {
+ render() {
scrollViewApp = this;
- var children = this.state.data.map((item, index) => (
+ const children = this.state.data.map((item, index) => (
<Item
key={index}
text={item.text}
- onPress={this.onItemPress.bind(this, index)}
+ onPress={onItemPress.bind(this, index)}
/>
));
return (
- <ScrollView horizontal={true} onScroll={this.onScroll} ref="scrollView">
+ <ScrollView horizontal={true} onScroll={onScroll} ref={this.scrollView}>
{children}
</ScrollView>
);
- },
-});
+ }
+}
-var styles = StyleSheet.create({
+const styles = StyleSheet.create({
item_container: {
padding: 30,
backgroundColor: '#ffffff',
@@ -144,10 +168,10 @@
},
});
-var ScrollViewTestModule = {
+const ScrollViewTestModule = {
ScrollViewTestApp: ScrollViewTestApp,
HorizontalScrollViewTestApp: HorizontalScrollViewTestApp,
- scrollTo: function(destX, destY) {
+ scrollTo(destX: number, destY: number) {
scrollViewApp.scrollTo(destX, destY);
},
};

ReactAndroid/src/androidTest/js/ShareTestModule.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -9,11 +9,11 @@
'use strict';
-var BatchedBridge = require('BatchedBridge');
-var React = require('React');
-var RecordingModule = require('NativeModules').ShareRecordingModule;
-var Share = require('Share');
-var View = require('View');
+const BatchedBridge = require('BatchedBridge');
+const React = require('React');
+const RecordingModule = require('NativeModules').ShareRecordingModule;
+const Share = require('Share');
+const View = require('View');
class ShareTestApp extends React.Component {
render() {
@@ -21,7 +21,7 @@
}
}
-var ShareTestModule = {
+const ShareTestModule = {
ShareTestApp: ShareTestApp,
showShareDialog: function(content, options) {
Share.share(content, options).then(

ReactAndroid/src/androidTest/js/SubviewsClippingTestModule.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -9,44 +9,43 @@
'use strict';
-var BatchedBridge = require('BatchedBridge');
-var React = require('React');
-var ScrollView = require('ScrollView');
-var StyleSheet = require('StyleSheet');
-var View = require('View');
+const BatchedBridge = require('BatchedBridge');
+const React = require('React');
+const ScrollView = require('ScrollView');
+const StyleSheet = require('StyleSheet');
+const View = require('View');
-var requireNativeComponent = require('requireNativeComponent');
+const requireNativeComponent = require('requireNativeComponent');
-var ClippableView = requireNativeComponent('ClippableView');
+const ClippableView = requireNativeComponent('ClippableView');
class ClippingSample1 extends React.Component {
render() {
- var styles = sample1Styles;
return (
<View>
<ClippableView
clippableViewID="outer"
- style={styles.outer}
+ style={sample1Styles.outer}
removeClippedSubviews={true}>
<ClippableView
clippableViewID="inner1"
- style={[styles.inner, styles.inner1]}
+ style={[sample1Styles.inner, sample1Styles.inner1]}
/>
<ClippableView
clippableViewID="inner2"
- style={[styles.inner, styles.inner2]}
+ style={[sample1Styles.inner, sample1Styles.inner2]}
/>
<ClippableView
clippableViewID="inner3"
- style={[styles.inner, styles.inner3]}
+ style={[sample1Styles.inner, sample1Styles.inner3]}
/>
<ClippableView
clippableViewID="inner4"
- style={[styles.inner, styles.inner4]}
+ style={[sample1Styles.inner, sample1Styles.inner4]}
/>
<ClippableView
clippableViewID="inner5"
- style={[styles.inner, styles.inner5]}
+ style={[sample1Styles.inner, sample1Styles.inner5]}
/>
</ClippableView>
</View>
@@ -54,7 +53,7 @@
}
}
-var sample1Styles = StyleSheet.create({
+const sample1Styles = StyleSheet.create({
outer: {
width: 200,
height: 200,
@@ -90,32 +89,31 @@
class ClippingSample2 extends React.Component {
render() {
- var styles = sample2Styles;
return (
<View>
<ClippableView
clippableViewID="outer"
- style={styles.outer}
+ style={sample2Styles.outer}
removeClippedSubviews={true}>
<ClippableView
clippableViewID="complexInner"
- style={styles.complexInner}
+ style={sample2Styles.complexInner}
removeClippedSubviews={true}>
<ClippableView
clippableViewID="inner1"
- style={[styles.inner, styles.inner1]}
+ style={[sample2Styles.inner, sample2Styles.inner1]}
/>
<ClippableView
clippableViewID="inner2"
- style={[styles.inner, styles.inner2]}
+ style={[sample2Styles.inner, sample2Styles.inner2]}
/>
<ClippableView
clippableViewID="inner3"
- style={[styles.inner, styles.inner3]}
+ style={[sample2Styles.inner, sample2Styles.inner3]}
/>
<ClippableView
clippableViewID="inner4"
- style={[styles.inner, styles.inner4]}
+ style={[sample2Styles.inner, sample2Styles.inner4]}
/>
</ClippableView>
</ClippableView>
@@ -124,7 +122,7 @@
}
}
-var sample2Styles = StyleSheet.create({
+const sample2Styles = StyleSheet.create({
outer: {
width: 200,
height: 200,
@@ -164,17 +162,21 @@
class UpdatingSample1 extends React.Component {
render() {
- var styles = updating1Styles;
- var inner1Styles = [
- styles.inner1,
+ const inner1Styles = [
+ updating1Styles.inner1,
{height: this.props.update1 ? 200 : 100},
];
- var inner2Styles = [styles.inner2, {top: this.props.update2 ? 200 : 50}];
+
+ const inner2Styles = [
+ updating1Styles.inner2,
+ {top: this.props.update2 ? 200 : 50},
+ ];
+
return (
<View>
<ClippableView
clippableViewID="outer"
- style={styles.outer}
+ style={updating1Styles.outer}
removeClippedSubviews={true}>
<ClippableView clippableViewID="inner1" style={inner1Styles} />
<ClippableView clippableViewID="inner2" style={inner2Styles} />
@@ -184,7 +186,7 @@
}
}
-var updating1Styles = StyleSheet.create({
+const updating1Styles = StyleSheet.create({
outer: {
width: 200,
height: 200,
@@ -210,22 +212,28 @@
class UpdatingSample2 extends React.Component {
render() {
- var styles = updating2Styles;
- var outerStyles = [styles.outer, {height: this.props.update ? 200 : 100}];
+ const outerStyles = [
+ updating2Styles.outer,
+ {height: this.props.update ? 200 : 100},
+ ];
+
return (
<View>
<ClippableView
clippableViewID="outer"
style={outerStyles}
removeClippedSubviews={true}>
- <ClippableView clippableViewID="inner" style={styles.inner} />
+ <ClippableView
+ clippableViewID="inner"
+ style={updating2Styles.inner}
+ />
</ClippableView>
</View>
);
}
}
-var updating2Styles = StyleSheet.create({
+const updating2Styles = StyleSheet.create({
outer: {
width: 100,
height: 100,
@@ -242,23 +250,32 @@
class ScrollViewTest extends React.Component {
render() {
- var styles = scrollTestStyles;
- var children = [];
- for (var i = 0; i < 4; i++) {
+ const children = [];
+ for (let i = 0; i < 4; i++) {
children[i] = (
- <ClippableView key={i} style={styles.row} clippableViewID={'' + i} />
+ <ClippableView
+ key={i}
+ style={scrollTestStyles.row}
+ clippableViewID={'' + i}
+ />
);
}
- for (var i = 4; i < 6; i++) {
- var viewID = 'C' + (i - 4);
+ for (let i = 4; i < 6; i++) {
+ const viewID = 'C' + (i - 4);
children[i] = (
<ClippableView
key={i}
- style={styles.complex}
+ style={scrollTestStyles.complex}
clippableViewID={viewID}
removeClippedSubviews={true}>
- <ClippableView style={styles.inner} clippableViewID={viewID + '.1'} />
- <ClippableView style={styles.inner} clippableViewID={viewID + '.2'} />
+ <ClippableView
+ style={scrollTestStyles.inner}
+ clippableViewID={viewID + '.1'}
+ />
+ <ClippableView
+ style={scrollTestStyles.inner}
+ clippableViewID={viewID + '.2'}
+ />
</ClippableView>
);
}
@@ -266,7 +283,7 @@
return (
<ScrollView
removeClippedSubviews={true}
- style={styles.scrollView}
+ style={scrollTestStyles.scrollView}
testID="scroll_view">
{children}
</ScrollView>
@@ -274,7 +291,7 @@
}
}
-var scrollTestStyles = StyleSheet.create({
+const scrollTestStyles = StyleSheet.create({
scrollView: {
width: 200,
height: 300,
@@ -303,7 +320,7 @@
},
});
-var appInstance = null;
+let appInstance = null;
class SubviewsClippingTestApp extends React.Component {
state = {};
@@ -317,12 +334,12 @@
};
render() {
- var component = this.state.component;
+ const component = this.state.component;
return <View>{component}</View>;
}
}
-var SubviewsClippingTestModule = {
+const SubviewsClippingTestModule = {
App: SubviewsClippingTestApp,
renderClippingSample1: function() {
appInstance.setComponent(<ClippingSample1 />);

ReactAndroid/src/androidTest/js/SwipeRefreshLayoutTestModule.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -9,15 +9,16 @@
'use strict';
-var BatchedBridge = require('BatchedBridge');
-var React = require('React');
-var RecordingModule = require('NativeModules')
+const BatchedBridge = require('BatchedBridge');
+const React = require('React');
+const RecordingModule = require('NativeModules')
.SwipeRefreshLayoutRecordingModule;
-var ScrollView = require('ScrollView');
-var RefreshControl = require('RefreshControl');
-var Text = require('Text');
-var TouchableWithoutFeedback = require('TouchableWithoutFeedback');
-var View = require('View');
+const ScrollView = require('ScrollView');
+const StyleSheet = require('StyleSheet');
+const RefreshControl = require('RefreshControl');
+const Text = require('Text');
+const TouchableWithoutFeedback = require('TouchableWithoutFeedback');
+const View = require('View');
class Row extends React.Component {
state = {
@@ -39,7 +40,7 @@
};
}
-var app = null;
+let app = null;
class SwipeRefreshLayoutTestApp extends React.Component {
state = {
@@ -51,16 +52,16 @@
}
render() {
- var rows = [];
- for (var i = 0; i < this.state.rows; i++) {
+ const rows = [];
+ for (let i = 0; i < this.state.rows; i++) {
rows.push(<Row key={i} />);
}
return (
<ScrollView
- style={{flex: 1}}
+ style={styles.container}
refreshControl={
<RefreshControl
- style={{flex: 1}}
+ style={styles.content}
refreshing={false}
onRefresh={() => RecordingModule.onRefresh()}
/>
@@ -71,7 +72,7 @@
}
}
-var SwipeRefreshLayoutTestModule = {
+const SwipeRefreshLayoutTestModule = {
SwipeRefreshLayoutTestApp,
setRows: function(rows) {
if (app != null) {
@@ -85,4 +86,13 @@
SwipeRefreshLayoutTestModule,
);
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ },
+ content: {
+ flex: 1,
+ },
+});
+
module.exports = SwipeRefreshLayoutTestModule;

ReactAndroid/src/androidTest/js/TestBundle.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -32,9 +32,14 @@
require('TimePickerDialogTestModule');
// Define catalyst test apps used in integration tests
-var AppRegistry = require('AppRegistry');
+const AppRegistry = require('AppRegistry');
-var apps = [
+const apps = [
+ {
+ appKey: 'AnimatedTransformTestApp',
+ component: () =>
+ require('AnimatedTransformTestModule').AnimatedTransformTestApp,
+ },
{
appKey: 'CatalystRootViewTestApp',
component: () =>
@@ -55,6 +60,14 @@
require('ScrollViewTestModule').HorizontalScrollViewTestApp,
},
{
+ appKey: 'ImageOverlayColorTestApp',
+ component: () => require('ImageOverlayColorTestApp'),
+ },
+ {
+ appKey: 'ImageErrorTestApp',
+ component: () => require('ImageErrorTestApp'),
+ },
+ {
appKey: 'InitialPropsTestApp',
component: () => require('InitialPropsTestApp'),
},

ReactAndroid/src/androidTest/js/TestIdTestModule.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -9,17 +9,16 @@
'use strict';
-var Image = require('Image');
-var React = require('React');
-var StyleSheet = require('StyleSheet');
-var Switch = require('Switch');
-var Text = require('Text');
-var TextInput = require('TextInput');
-var TouchableBounce = require('TouchableBounce');
-var TouchableHighlight = require('TouchableHighlight');
-var TouchableOpacity = require('TouchableOpacity');
-var TouchableWithoutFeedback = require('TouchableWithoutFeedback');
-var View = require('View');
+const Image = require('Image');
+const React = require('React');
+const StyleSheet = require('StyleSheet');
+const Text = require('Text');
+const TextInput = require('TextInput');
+const TouchableBounce = require('TouchableBounce');
+const TouchableHighlight = require('TouchableHighlight');
+const TouchableOpacity = require('TouchableOpacity');
+const TouchableWithoutFeedback = require('TouchableWithoutFeedback');
+const View = require('View');
/**
* All the views implemented on Android, each with the testID property set.
@@ -73,7 +72,7 @@
}
}
-var styles = StyleSheet.create({
+const styles = StyleSheet.create({
base: {
width: 150,
height: 50,

ReactAndroid/src/androidTest/js/TestJavaToJSArgumentsModule.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -9,14 +9,14 @@
'use strict';
-var BatchedBridge = require('BatchedBridge');
-var {assertEquals, assertTrue} = require('Asserts');
+const BatchedBridge = require('BatchedBridge');
+const {assertEquals, assertTrue} = require('Asserts');
function strictStringCompare(a, b) {
if (typeof a !== 'string' || typeof b !== 'string' || a.length !== b.length) {
return false;
}
- for (var i = 0; i < a.length; i++) {
+ for (let i = 0; i < a.length; i++) {
if (a.charCodeAt(i) !== b.charCodeAt(i)) {
return false;
}
@@ -28,7 +28,7 @@
assertTrue(strictStringCompare(a, b), 'Expected: ' + a + ', received: ' + b);
}
-var TestJavaToJSArgumentsModule = {
+const TestJavaToJSArgumentsModule = {
receiveBasicTypes: function(str, dbl, bool, null_arg) {
assertEquals('foo', str);
assertEquals(3.14, dbl);
@@ -45,15 +45,15 @@
receiveNestedArray: function(arr) {
assertEquals(2, arr.length);
assertEquals('level1', arr[0]);
- var arr2 = arr[1];
+ const arr2 = arr[1];
assertEquals('level2', arr2[0]);
- var arr3 = arr2[1];
+ const arr3 = arr2[1];
assertEquals('level3', arr3[0]);
},
receiveArrayWithMaps: function(arr) {
assertEquals(2, arr.length);
- var m1 = arr[0];
- var m2 = arr[1];
+ const m1 = arr[0];
+ const m2 = arr[1];
assertEquals('m1v1', m1.m1k1);
assertEquals('m1v2', m1.m1k2);
assertEquals('m2v1', m2.m2k1);
@@ -65,12 +65,12 @@
assertEquals(null, map.nullKey);
},
receiveNestedMap: function(map) {
- var nestedMap = map.nestedMap;
+ const nestedMap = map.nestedMap;
assertEquals('foxes', nestedMap.animals);
},
receiveMapWithArrays: function(map) {
- var a1 = map.array1;
- var a2 = map.array2;
+ const a1 = map.array1;
+ const a2 = map.array2;
assertEquals(3, a1.length);
assertEquals(2, a2.length);
assertEquals(3, a1[0]);

ReactAndroid/src/androidTest/js/TestJavaToJSReturnValuesModule.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -14,7 +14,7 @@
const {assertEquals, assertTrue} = require('Asserts');
const {TestModule} = require('NativeModules');
-var TestJavaToJSReturnValuesModule = {
+const TestJavaToJSReturnValuesModule = {
callMethod: function(methodName, expectedType, expectedJSON) {
const result = TestModule[methodName]();
assertEquals(expectedType, typeof result);

ReactAndroid/src/androidTest/js/TestJSLocaleModule.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -9,10 +9,10 @@
'use strict';
-var BatchedBridge = require('BatchedBridge');
-var Recording = require('NativeModules').Recording;
+const BatchedBridge = require('BatchedBridge');
+const Recording = require('NativeModules').Recording;
-var TestJSLocaleModule = {
+const TestJSLocaleModule = {
toUpper: function(s) {
Recording.record(s.toUpperCase());
},

ReactAndroid/src/androidTest/js/TestJSToJavaParametersModule.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -9,10 +9,10 @@
'use strict';
-var BatchedBridge = require('BatchedBridge');
-var Recording = require('NativeModules').Recording;
+const BatchedBridge = require('BatchedBridge');
+const Recording = require('NativeModules').Recording;
-var TestJSToJavaParametersModule = {
+const TestJSToJavaParametersModule = {
returnBasicTypes: function() {
Recording.receiveBasicTypes('foo', 3.14, true, null);
},

ReactAndroid/src/androidTest/js/TextInputTestModule.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -9,16 +9,16 @@
'use strict';
-var BatchedBridge = require('BatchedBridge');
-var React = require('React');
-var StyleSheet = require('StyleSheet');
-var Text = require('Text');
-var TextInput = require('TextInput');
-var View = require('View');
+const BatchedBridge = require('BatchedBridge');
+const React = require('React');
+const StyleSheet = require('StyleSheet');
+const Text = require('Text');
+const TextInput = require('TextInput');
+const View = require('View');
-var Recording = require('NativeModules').Recording;
+const Recording = require('NativeModules').Recording;
-var app;
+let app;
class TokenizedTextExample extends React.Component {
constructor(props) {
@@ -122,18 +122,18 @@
/>
<TextInput
ref="textInput4"
- style={[styles.textInput, {color: '#00ff00'}]}
+ style={[styles.textInput, styles.textInputColor]}
testID="textInput4"
/>
<TextInput
ref="textInput5"
- style={[styles.textInput, {color: '#00ff00'}]}
+ style={[styles.textInput, styles.textInputColor]}
defaultValue=""
testID="textInput5"
/>
<TextInput
ref="textInput6"
- style={[styles.textInput, {color: '#00ff00'}]}
+ style={[styles.textInput, styles.textInputColor]}
defaultValue="Text"
testID="textInput6"
/>
@@ -149,7 +149,7 @@
}
}
-var styles = StyleSheet.create({
+const styles = StyleSheet.create({
container: {
padding: 5,
margin: 10,
@@ -166,9 +166,12 @@
color: 'blue',
fontWeight: 'bold',
},
+ textInputColor: {
+ marginLeft: 20,
+ },
});
-var TextInputTestModule = {
+const TextInputTestModule = {
TextInputTestApp,
setValueRef: function(ref, value) {
app.refs[ref].setNativeProps({

ReactAndroid/src/androidTest/js/TimePickerDialogTestModule.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -9,11 +9,12 @@
'use strict';
-var BatchedBridge = require('BatchedBridge');
-var TimePickerAndroid = require('TimePickerAndroid');
-var React = require('React');
-var RecordingModule = require('NativeModules').TimePickerDialogRecordingModule;
-var View = require('View');
+const BatchedBridge = require('BatchedBridge');
+const TimePickerAndroid = require('TimePickerAndroid');
+const React = require('React');
+const RecordingModule = require('NativeModules')
+ .TimePickerDialogRecordingModule;
+const View = require('View');
class TimePickerDialogTestApp extends React.Component {
render() {
@@ -21,7 +22,7 @@
}
}
-var TimePickerDialogTestModule = {
+const TimePickerDialogTestModule = {
TimePickerDialogTestApp: TimePickerDialogTestApp,
showTimePickerDialog: function(options) {
TimePickerAndroid.open(options).then(

ReactAndroid/src/androidTest/js/TouchBubblingTestAppModule.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -9,12 +9,12 @@
'use strict';
-var Recording = require('NativeModules').Recording;
+const Recording = require('NativeModules').Recording;
-var React = require('React');
-var StyleSheet = require('StyleSheet');
-var View = require('View');
-var TouchableWithoutFeedback = require('TouchableWithoutFeedback');
+const React = require('React');
+const StyleSheet = require('StyleSheet');
+const View = require('View');
+const TouchableWithoutFeedback = require('TouchableWithoutFeedback');
class TouchBubblingTestApp extends React.Component {
handlePress = record => {
@@ -48,7 +48,7 @@
}
}
-var styles = StyleSheet.create({
+const styles = StyleSheet.create({
container: {
flexDirection: 'column',
backgroundColor: '#ccdd44',

ReactAndroid/src/androidTest/js/UIManagerTestModule.js

@@ -1,26 +1,45 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
+ * @flow
*/
'use strict';
-var BatchedBridge = require('BatchedBridge');
-var React = require('React');
-var StyleSheet = require('StyleSheet');
-var View = require('View');
-var Text = require('Text');
-
-var createReactClass = require('create-react-class');
-var renderApplication = require('renderApplication');
-
-var FlexTestApp = createReactClass({
- displayName: 'FlexTestApp',
- _styles: StyleSheet.create({
+const BatchedBridge = require('BatchedBridge');
+const React = require('React');
+const StyleSheet = require('StyleSheet');
+const View = require('View');
+const Text = require('Text');
+
+const renderApplication = require('renderApplication');
+
+type FlexTestAppProps = $ReadOnly<{||}>;
+class FlexTestApp extends React.Component<FlexTestAppProps> {
+ render() {
+ return (
+ <View
+ style={FlexTestAppStyles.container}
+ testID="container"
+ collapsable={false}>
+ <View
+ style={[FlexTestAppStyles.child, FlexTestAppStyles.bgRed]}
+ collapsable={false}
+ />
+ <View
+ style={[FlexTestAppStyles.child, FlexTestAppStyles.bgBlue]}
+ collapsable={false}
+ />
+ </View>
+ );
+ }
+}
+
+const FlexTestAppStyles = StyleSheet.create({
container: {
width: 200,
height: 200,
@@ -29,36 +48,32 @@
child: {
flex: 1,
},
- absolute: {
- position: 'absolute',
- top: 15,
- left: 10,
- width: 50,
- height: 60,
+ bgRed: {
+ backgroundColor: '#ff0000',
+ },
+ bgBlue: {
+ backgroundColor: '#0000ff',
},
- }),
- render: function() {
+});
+
+type FlexWithTextProps = $ReadOnly<{||}>;
+class FlexWithText extends React.Component<FlexWithTextProps> {
+ render() {
return (
<View
- style={this._styles.container}
+ style={FlexWithTextStyles.container}
testID="container"
collapsable={false}>
- <View
- style={[this._styles.child, {backgroundColor: '#ff0000'}]}
- collapsable={false}
- />
- <View
- style={[this._styles.child, {backgroundColor: '#0000ff'}]}
- collapsable={false}
- />
+ <View style={FlexWithTextStyles.row} collapsable={false}>
+ <Text style={FlexWithTextStyles.inner}>Hello</Text>
+ <Text style={FlexWithTextStyles.inner}>World</Text>
+ </View>
</View>
);
- },
-});
+ }
+}
-var FlexWithText = createReactClass({
- displayName: 'FlexWithText',
- _styles: StyleSheet.create({
+const FlexWithTextStyles = StyleSheet.create({
container: {
flexDirection: 'column',
margin: 20,
@@ -72,25 +87,24 @@
flex: 1,
margin: 10,
},
- }),
- render: function() {
+});
+
+type AbsolutePositionTestAppProps = $ReadOnly<{||}>;
+class AbsolutePositionTestApp extends React.Component<
+ AbsolutePositionTestAppProps,
+> {
+ render() {
return (
<View
- style={this._styles.container}
- testID="container"
- collapsable={false}>
- <View style={this._styles.row} collapsable={false}>
- <Text style={this._styles.inner}>Hello</Text>
- <Text style={this._styles.inner}>World</Text>
- </View>
- </View>
+ style={AbsolutePositionTestAppStyles.absolute}
+ testID="absolute"
+ collapsable={false}
+ />
);
- },
-});
+ }
+}
-var AbsolutePositionTestApp = createReactClass({
- displayName: 'AbsolutePositionTestApp',
- _styles: StyleSheet.create({
+const AbsolutePositionTestAppStyles = StyleSheet.create({
absolute: {
position: 'absolute',
top: 15,
@@ -98,21 +112,28 @@
width: 50,
height: 60,
},
- }),
- render: function() {
+});
+
+type AbsolutePositionBottomRightTestAppProps = $ReadOnly<{||}>;
+class AbsolutePositionBottomRightTestApp extends React.Component<
+ AbsolutePositionBottomRightTestAppProps,
+> {
+ render() {
return (
<View
- style={this._styles.absolute}
- testID="absolute"
+ style={AbsolutePositionBottomRightTestAppStyles.container}
+ testID="container"
+ collapsable={false}>
+ <View
+ style={AbsolutePositionBottomRightTestAppStyles.absolute}
collapsable={false}
/>
+ </View>
);
- },
-});
+ }
+}
-var AbsolutePositionBottomRightTestApp = createReactClass({
- displayName: 'AbsolutePositionBottomRightTestApp',
- _styles: StyleSheet.create({
+const AbsolutePositionBottomRightTestAppStyles = StyleSheet.create({
container: {
width: 100,
height: 100,
@@ -124,22 +145,26 @@
width: 50,
height: 60,
},
- }),
- render: function() {
+});
+
+type CenteredTextViewProps = $ReadOnly<{|
+ text?: ?string,
+|}>;
+class CenteredTextView extends React.Component<CenteredTextViewProps> {
+ render() {
return (
- <View
- style={this._styles.container}
- testID="container"
- collapsable={false}>
- <View style={this._styles.absolute} collapsable={false} />
+ <View collapsable={false}>
+ <View style={CenteredTextViewStyles.parent} collapsable={false}>
+ <Text style={CenteredTextViewStyles.text} testID="text">
+ {this.props.text}
+ </Text>
+ </View>
</View>
);
- },
-});
+ }
+}
-var CenteredTextView = createReactClass({
- displayName: 'CenteredTextView',
- _styles: StyleSheet.create({
+const CenteredTextViewStyles = StyleSheet.create({
parent: {
width: 200,
height: 100,
@@ -151,74 +176,92 @@
fontSize: 15,
color: '#672831',
},
- }),
- render: function() {
- return (
- <View collapsable={false}>
- <View style={this._styles.parent} collapsable={false}>
- <Text style={this._styles.text} testID="text">
- {this.props.text}
- </Text>
- </View>
- </View>
- );
- },
});
-var flushUpdatePositionInList = null;
-var UpdatePositionInListTestApp = createReactClass({
- displayName: 'UpdatePositionInListTestApp',
- _styles: StyleSheet.create({
- element: {
- height: 10,
- },
- active: {
- height: 50,
- },
- }),
- getInitialState: function() {
+let flushUpdatePositionInList = null;
+
+type UpdatePositionInListTestAppProps = $ReadOnly<{||}>;
+type UpdatePositionInListTestAppState = {|
+ active: boolean,
+|};
+class UpdatePositionInListTestApp extends React.Component<
+ UpdatePositionInListTestAppProps,
+ UpdatePositionInListTestAppState,
+> {
+ state = {
+ active: false,
+ };
+
+ constructor(...args) {
+ super(...args);
flushUpdatePositionInList = () => this.setState({active: true});
- return {active: false};
- },
- render: function() {
+ }
+
+ render() {
return (
<View collapsable={false} testID="container">
- <View style={this._styles.element} collapsable={false} />
+ <View
+ style={UpdatePositionInListTestAppStyles.element}
+ collapsable={false}
+ />
<View
style={[
- this._styles.element,
- this.state.active && this._styles.active,
+ UpdatePositionInListTestAppStyles.element,
+ this.state.active && UpdatePositionInListTestAppStyles.active,
]}
collapsable={false}
/>
- <View style={this._styles.element} collapsable={false} />
+ <View
+ style={UpdatePositionInListTestAppStyles.element}
+ collapsable={false}
+ />
</View>
);
- },
-});
+ }
+}
-var UIManagerTestModule = {
- renderFlexTestApplication: function(rootTag) {
- renderApplication(FlexTestApp, {}, rootTag);
+const UpdatePositionInListTestAppStyles = StyleSheet.create({
+ element: {
+ height: 10,
},
- renderFlexWithTextApplication: function(rootTag) {
- renderApplication(FlexWithText, {}, rootTag);
+ active: {
+ height: 50,
},
- renderAbsolutePositionBottomRightTestApplication: function(rootTag) {
- renderApplication(AbsolutePositionBottomRightTestApp, {}, rootTag);
+});
+
+/**
+ * This is a workaround for the following flow problem:
+ *
+ * const emptyObject: {||} = {}; // Raises error
+ *
+ * @see https://github.com/facebook/flow/issues/2977
+ */
+const emptyExactProps = Object.freeze({});
+
+const UIManagerTestModule = {
+ renderFlexTestApplication(rootTag: number) {
+ renderApplication(FlexTestApp, emptyExactProps, rootTag);
+ },
+ renderFlexWithTextApplication(rootTag: number) {
+ renderApplication(FlexWithText, emptyExactProps, rootTag);
+ },
+ renderAbsolutePositionBottomRightTestApplication(rootTag: number) {
+ renderApplication(
+ AbsolutePositionBottomRightTestApp,
+ emptyExactProps,
+ rootTag,
+ );
},
- renderAbsolutePositionTestApplication: function(rootTag) {
- renderApplication(AbsolutePositionTestApp, {}, rootTag);
+ renderAbsolutePositionTestApplication(rootTag: number) {
+ renderApplication(AbsolutePositionTestApp, emptyExactProps, rootTag);
},
- renderCenteredTextViewTestApplication: function(rootTag, text) {
+ renderCenteredTextViewTestApplication(rootTag: number, text: string) {
renderApplication(CenteredTextView, {text: text}, rootTag);
},
- renderUpdatePositionInListTestApplication: function(rootTag) {
- renderApplication(UpdatePositionInListTestApp, {}, rootTag);
- },
- flushUpdatePositionInList: function() {
- flushUpdatePositionInList();
+ renderUpdatePositionInListTestApplication(rootTag: number) {
+ renderApplication(UpdatePositionInListTestApp, emptyExactProps, rootTag);
},
+ flushUpdatePositionInList,
};
BatchedBridge.registerCallableModule(

ReactAndroid/src/androidTest/js/ViewRenderingTestModule.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -9,20 +9,12 @@
'use strict';
-var BatchedBridge = require('BatchedBridge');
-var React = require('React');
-var View = require('View');
-var StyleSheet = require('StyleSheet');
-
-var renderApplication = require('renderApplication');
-
-var styles = StyleSheet.create({
- view: {
- opacity: 0.75,
- backgroundColor: 'rgb(255, 0, 0)',
- },
-});
+const BatchedBridge = require('BatchedBridge');
+const React = require('React');
+const View = require('View');
+const StyleSheet = require('StyleSheet');
+const renderApplication = require('renderApplication');
class ViewSampleApp extends React.Component {
state = {};
@@ -31,7 +23,7 @@
}
}
-var updateMargins;
+let updateMargins;
class MarginSampleApp extends React.Component {
state = {margin: 10};
@@ -40,7 +32,7 @@
updateMargins = this.setState.bind(this, {margin: 15});
return (
<View
- style={{margin: this.state.margin, marginLeft: 20}}
+ style={[{margin: this.state.margin}, styles.marginSample]}
collapsable={false}
/>
);
@@ -50,13 +42,8 @@
class BorderSampleApp extends React.Component {
render() {
return (
- <View
- style={{borderLeftWidth: 20, borderWidth: 5, backgroundColor: 'blue'}}
- collapsable={false}>
- <View
- style={{backgroundColor: 'red', width: 20, height: 20}}
- collapsable={false}
- />
+ <View style={styles.borderSample} collapsable={false}>
+ <View style={styles.borderSampleContent} collapsable={false} />
</View>
);
}
@@ -64,7 +51,7 @@
class TransformSampleApp extends React.Component {
render() {
- var style = {
+ const style = {
transform: [
{translateX: 20},
{translateY: 25},
@@ -77,7 +64,7 @@
}
}
-var ViewRenderingTestModule = {
+const ViewRenderingTestModule = {
renderViewApplication: function(rootTag) {
renderApplication(ViewSampleApp, {}, rootTag);
},
@@ -100,4 +87,24 @@
ViewRenderingTestModule,
);
+const styles = StyleSheet.create({
+ view: {
+ opacity: 0.75,
+ backgroundColor: 'rgb(255, 0, 0)',
+ },
+ borderSample: {
+ borderLeftWidth: 20,
+ borderWidth: 5,
+ backgroundColor: 'blue',
+ },
+ borderSampleContent: {
+ backgroundColor: 'red',
+ width: 20,
+ height: 20,
+ },
+ marginSample: {
+ marginLeft: 20,
+ },
+});
+
module.exports = ViewRenderingTestModule;

ReactAndroid/src/main/AndroidManifest.xml

@@ -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>

ReactAndroid/src/main/java/com/facebook/debug/debugoverlay/model/DebugOverlayTag.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/debug/holder/NoopPrinter.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/debug/holder/PrinterHolder.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/debug/holder/Printer.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/debug/tags/ReactDebugOverlayTags.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/jni/Countable.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/jni/CpuCapabilitiesJni.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/jni/DestructorThread.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/jni/fbjni.pro

@@ -1,3 +1,8 @@
+# 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.
+
# For common use cases for the hybrid pattern, keep symbols which may
# be referenced only from C++.

ReactAndroid/src/main/java/com/facebook/jni/HybridClassBase.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/jni/HybridData.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/jni/IteratorHelper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/jni/JniTerminateHandler.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/jni/MapIteratorHelper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/jni/NativeRunnable.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/jni/ThreadScopeSupport.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/perftest/PerfTestConfig.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/proguard/annotations/DoNotStrip.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/proguard/annotations/KeepGettersAndSetters.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/proguard/annotations/proguard_annotations.pro

@@ -1,3 +1,8 @@
+# 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.
+
# Keep our interfaces so they can be used by other ProGuard rules.
# See http://sourceforge.net/p/proguard/bugs/466/
-keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip

ReactAndroid/src/main/java/com/facebook/react/animated/AdditionAnimatedNode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animated/AnimatedNode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animated/AnimatedNodeValueListener.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animated/AnimationDriver.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animated/DecayAnimation.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animated/DiffClampAnimatedNode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animated/DivisionAnimatedNode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animated/EventAnimationDriver.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animated/FrameBasedAnimationDriver.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animated/InterpolationAnimatedNode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animated/ModulusAnimatedNode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animated/MultiplicationAnimatedNode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -75,7 +75,7 @@
public class NativeAnimatedModule extends ReactContextBaseJavaModule implements
LifecycleEventListener, UIManagerModuleListener {
- protected static final String NAME = "NativeAnimatedModule";
+ public static final String NAME = "NativeAnimatedModule";
private interface UIThreadOperation {
void execute(NativeAnimatedNodesManager animatedNodesManager);

ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedNodesManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animated/PropsAnimatedNode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animated/SpringAnimation.java

@@ -1,3 +1,10 @@
+/**
+ * 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.animated;
import com.facebook.react.bridge.ReadableMap;

ReactAndroid/src/main/java/com/facebook/react/animated/StyleAnimatedNode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animated/SubtractionAnimatedNode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animated/TrackingAnimatedNode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animated/TransformAnimatedNode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animated/ValueAnimatedNode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animation/AbstractFloatPairPropertyUpdater.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animation/AbstractSingleFloatProperyUpdater.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animation/Animation.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animation/AnimationListener.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animation/AnimationPropertyUpdater.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animation/AnimationRegistry.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animation/ImmediateAnimation.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animation/NoopAnimationPropertyUpdater.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animation/OpacityAnimationPropertyUpdater.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animation/PositionAnimationPairPropertyUpdater.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animation/RotationAnimationPropertyUpdater.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animation/ScaleXAnimationPropertyUpdater.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animation/ScaleXYAnimationPairPropertyUpdater.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/animation/ScaleYAnimationPropertyUpdater.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/ActivityEventListener.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/Arguments.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -25,7 +25,7 @@
object instanceof Long ||
object instanceof Byte ||
object instanceof Short) {
- return new Double(((Number) object).doubleValue());
+ return ((Number) object).doubleValue();
} else if (object.getClass().isArray()) {
return makeNativeArray(object);
} else if (object instanceof List) {

ReactAndroid/src/main/java/com/facebook/react/bridge/AssertionException.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/BaseActivityEventListener.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/bridge.pro

@@ -1,3 +1,8 @@
+# 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.
+
## Putting this here is kind of a hack. I don't want to modify the OSS bridge.
## TODO mhorowitz: add @DoNotStrip to the interface directly.

ReactAndroid/src/main/java/com/facebook/react/bridge/BUCK

@@ -1,8 +1,24 @@
load("//tools/build_defs/oss:rn_defs.bzl", "IS_OSS_BUILD", "react_native_dep", "react_native_target", "rn_android_library")
+INTERFACES = [
+ "Dynamic.java",
+ "ReadableMap.java",
+ "ReadableMapKeySetIterator.java",
+ "WritableArray.java",
+ "WritableMap.java",
+ "NativeModule.java",
+ "JSInstance.java",
+ "ReadableArray.java",
+ "ReadableType.java",
+ "NativeArrayInterface.java",
+]
+
rn_android_library(
name = "bridge",
- srcs = glob(["**/*.java"]),
+ srcs = glob(
+ ["**/*.java"],
+ exclude = INTERFACES,
+ ),
proguard_config = "reactnative.pro",
provided_deps = [
react_native_dep("third-party/android/support/v4:lib-support-v4"),
@@ -21,12 +37,38 @@
react_native_target("java/com/facebook/debug/tags:tags"),
react_native_target("java/com/facebook/debug/holder:holder"),
react_native_target("java/com/facebook/react/common:common"),
+ react_native_target("java/com/facebook/react/config:config"),
react_native_target("java/com/facebook/react/module/model:model"),
react_native_target("java/com/facebook/react/uimanager/common:common"),
+ react_native_target("java/com/facebook/react/module/annotations:annotations"),
+ react_native_target("java/com/facebook/react/turbomodule/core/interfaces:interfaces"),
] + ([react_native_target("jni/react/jni:jni")] if not IS_OSS_BUILD else []),
exported_deps = [
react_native_dep("java/com/facebook/jni:jni"),
react_native_dep("java/com/facebook/proguard/annotations:annotations"),
react_native_dep("third-party/java/jsr-330:jsr-330"),
+ react_native_target("java/com/facebook/react/bridge:interfaces"),
+ ],
+)
+
+rn_android_library(
+ name = "interfaces",
+ srcs = glob(INTERFACES),
+ proguard_config = "reactnative.pro",
+ provided_deps = [
+ react_native_dep("third-party/android/support/v4:lib-support-v4"),
+ ],
+ required_for_source_only_abi = True,
+ visibility = [
+ "PUBLIC",
+ ],
+ deps = [
+ 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/debug/tags:tags"),
+ ],
+ exported_deps = [
+ react_native_dep("java/com/facebook/proguard/annotations:annotations"),
+ react_native_dep("third-party/java/jsr-330:jsr-330"),
],
)

ReactAndroid/src/main/java/com/facebook/react/bridge/CallbackImpl.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/Callback.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,6 +7,8 @@
package com.facebook.react.bridge;
+import static com.facebook.systrace.Systrace.TRACE_TAG_REACT_JAVA_BRIDGE;
+
import android.content.res.AssetManager;
import android.os.AsyncTask;
import android.util.Log;
@@ -21,8 +23,11 @@
import com.facebook.react.bridge.queue.ReactQueueConfigurationSpec;
import com.facebook.react.common.ReactConstants;
import com.facebook.react.common.annotations.VisibleForTesting;
+import com.facebook.react.module.annotations.ReactModule;
import com.facebook.systrace.Systrace;
import com.facebook.systrace.TraceListener;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Native;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
@@ -102,6 +107,8 @@
final JSBundleLoader jsBundleLoader,
NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
Log.d(ReactConstants.TAG, "Initializing React Xplat Bridge.");
+ Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstanceImpl");
+
mHybridData = initHybrid();
mReactQueueConfiguration = ReactQueueConfigurationImpl.create(
@@ -114,8 +121,10 @@
mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
mNativeModulesQueueThread = mReactQueueConfiguration.getNativeModulesQueueThread();
mTraceListener = new JSProfilerTraceListener(this);
+ Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
Log.d(ReactConstants.TAG, "Initializing React Xplat Bridge before initializeBridge");
+ Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "initializeCxxBridge");
initializeBridge(
new BridgeCallback(this),
jsExecutor,
@@ -124,6 +133,7 @@
mNativeModuleRegistry.getJavaModules(this),
mNativeModuleRegistry.getCxxModules());
Log.d(ReactConstants.TAG, "Initializing React Xplat Bridge after initializeBridge");
+ Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
mJavaScriptContextHolder = new JavaScriptContextHolder(getJavaScriptContext());
}
@@ -191,17 +201,8 @@
Collection<JavaModuleWrapper> javaModules,
Collection<ModuleHolder> cxxModules);
- /**
- * This API is used in situations where the JS bundle is being executed not on
- * the device, but on a host machine. In that case, we must provide two source
- * URLs for the JS bundle: One to be used on the device, and one to be used on
- * the remote debugging machine.
- *
- * @param deviceURL A source URL that is accessible from this device.
- * @param remoteURL A source URL that is accessible from the remote machine
- * executing the JS.
- */
- /* package */ void setSourceURLs(String deviceURL, String remoteURL) {
+ @Override
+ public void setSourceURLs(String deviceURL, String remoteURL) {
mSourceURL = deviceURL;
jniSetSourceURL(remoteURL);
}
@@ -211,17 +212,20 @@
jniRegisterSegment(segmentId, path);
}
- /* package */ void loadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously) {
+ @Override
+ public void loadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously) {
mSourceURL = assetURL;
jniLoadScriptFromAssets(assetManager, assetURL, loadSynchronously);
}
- /* package */ void loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously) {
+ @Override
+ public void loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously) {
mSourceURL = sourceURL;
jniLoadScriptFromFile(fileName, sourceURL, loadSynchronously);
}
- /* package */ void loadScriptFromDeltaBundle(
+ @Override
+ public void loadScriptFromDeltaBundle(
String sourceURL,
NativeDeltaClient deltaClient,
boolean loadSynchronously) {
@@ -306,13 +310,13 @@
private native void jniCallJSCallback(int callbackID, NativeArray arguments);
@Override
- public void invokeCallback(final int callbackID, final NativeArray arguments) {
+ public void invokeCallback(final int callbackID, final NativeArrayInterface arguments) {
if (mDestroyed) {
FLog.w(ReactConstants.TAG, "Invoking JS callback after bridge has been destroyed.");
return;
}
- jniCallJSCallback(callbackID, arguments);
+ jniCallJSCallback(callbackID, (NativeArray) arguments);
}
/**
@@ -415,13 +419,25 @@
@Override
public <T extends NativeModule> boolean hasNativeModule(Class<T> nativeModuleInterface) {
- return mNativeModuleRegistry.hasModule(nativeModuleInterface);
+ return mNativeModuleRegistry.hasModule(getNameFromAnnotation(nativeModuleInterface));
}
- // This is only ever called with UIManagerModule or CurrentViewerModule.
@Override
public <T extends NativeModule> T getNativeModule(Class<T> nativeModuleInterface) {
- return mNativeModuleRegistry.getModule(nativeModuleInterface);
+ return (T) mNativeModuleRegistry.getModule(getNameFromAnnotation(nativeModuleInterface));
+ }
+
+ @Override
+ public NativeModule getNativeModule(String moduleName) {
+ return mNativeModuleRegistry.getModule(moduleName);
+ }
+
+ private <T extends NativeModule> String getNameFromAnnotation(Class<T> nativeModuleInterface){
+ ReactModule annotation = nativeModuleInterface.getAnnotation(ReactModule.class);
+ if (annotation == null) {
+ throw new IllegalArgumentException("Could not find @ReactModule annotation in " + nativeModuleInterface.getCanonicalName());
+ }
+ return annotation.name();
}
// This is only used by com.facebook.react.modules.common.ModuleDataCleaner

ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -21,7 +21,7 @@
*/
@DoNotStrip
public interface CatalystInstance
- extends MemoryPressureListener, JSInstance {
+ extends MemoryPressureListener, JSInstance, JSBundleLoaderDelegate {
void runJSBundle();
// Returns the status of running the JS bundle; waits for an answer if runJSBundle is running
@@ -38,7 +38,7 @@
@Override @DoNotStrip
void invokeCallback(
int callbackID,
- NativeArray arguments);
+ NativeArrayInterface arguments);
@DoNotStrip
void callFunction(
String module,
@@ -63,6 +63,7 @@
<T extends JavaScriptModule> T getJSModule(Class<T> jsInterface);
<T extends NativeModule> boolean hasNativeModule(Class<T> nativeModuleInterface);
<T extends NativeModule> T getNativeModule(Class<T> nativeModuleInterface);
+ NativeModule getNativeModule(String moduleName);
<T extends JSIModule> T getJSIModule(Class<T> jsiModuleInterface);
Collection<NativeModule> getNativeModules();

ReactAndroid/src/main/java/com/facebook/react/bridge/ContextBaseJavaModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/CxxCallbackImpl.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/CxxModuleWrapperBase.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/CxxModuleWrapper.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/DefaultNativeModuleCallExceptionHandler.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/DynamicFromArray.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/DynamicFromMap.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/Dynamic.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/FallbackJSBundleLoader.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -50,10 +50,10 @@
* it is replaced by the next most preferred loader.
*/
@Override
- public String loadScript(CatalystInstanceImpl instance) {
+ public String loadScript(JSBundleLoaderDelegate delegate) {
while (true) {
try {
- return getDelegateLoader().loadScript(instance);
+ return getDelegateLoader().loadScript(delegate);
} catch (Exception e) {
if (e.getMessage() == null || !e.getMessage().startsWith(RECOVERABLE)) {
throw e;

ReactAndroid/src/main/java/com/facebook/react/bridge/GuardedAsyncTask.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/GuardedResultAsyncTask.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/GuardedRunnable.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/Inspector.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/InvalidIteratorException.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/JavaJSExecutor.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/JavaMethodWrapper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -26,14 +26,14 @@
}
public abstract @Nullable T extractArgument(
- JSInstance jsInstance, ReadableNativeArray jsArguments, int atIndex);
+ JSInstance jsInstance, ReadableArray jsArguments, int atIndex);
}
static final private ArgumentExtractor<Boolean> ARGUMENT_EXTRACTOR_BOOLEAN =
new ArgumentExtractor<Boolean>() {
@Override
public Boolean extractArgument(
- JSInstance jsInstance, ReadableNativeArray jsArguments, int atIndex) {
+ JSInstance jsInstance, ReadableArray jsArguments, int atIndex) {
return jsArguments.getBoolean(atIndex);
}
};
@@ -42,7 +42,7 @@
new ArgumentExtractor<Double>() {
@Override
public Double extractArgument(
- JSInstance jsInstance, ReadableNativeArray jsArguments, int atIndex) {
+ JSInstance jsInstance, ReadableArray jsArguments, int atIndex) {
return jsArguments.getDouble(atIndex);
}
};
@@ -51,7 +51,7 @@
new ArgumentExtractor<Float>() {
@Override
public Float extractArgument(
- JSInstance jsInstance, ReadableNativeArray jsArguments, int atIndex) {
+ JSInstance jsInstance, ReadableArray jsArguments, int atIndex) {
return (float) jsArguments.getDouble(atIndex);
}
};
@@ -60,7 +60,7 @@
new ArgumentExtractor<Integer>() {
@Override
public Integer extractArgument(
- JSInstance jsInstance, ReadableNativeArray jsArguments, int atIndex) {
+ JSInstance jsInstance, ReadableArray jsArguments, int atIndex) {
return (int) jsArguments.getDouble(atIndex);
}
};
@@ -69,16 +69,16 @@
new ArgumentExtractor<String>() {
@Override
public String extractArgument(
- JSInstance jsInstance, ReadableNativeArray jsArguments, int atIndex) {
+ JSInstance jsInstance, ReadableArray jsArguments, int atIndex) {
return jsArguments.getString(atIndex);
}
};
- static final private ArgumentExtractor<ReadableNativeArray> ARGUMENT_EXTRACTOR_ARRAY =
- new ArgumentExtractor<ReadableNativeArray>() {
+ static final private ArgumentExtractor<ReadableArray> ARGUMENT_EXTRACTOR_ARRAY =
+ new ArgumentExtractor<ReadableArray>() {
@Override
- public ReadableNativeArray extractArgument(
- JSInstance jsInstance, ReadableNativeArray jsArguments, int atIndex) {
+ public ReadableArray extractArgument(
+ JSInstance jsInstance, ReadableArray jsArguments, int atIndex) {
return jsArguments.getArray(atIndex);
}
};
@@ -87,7 +87,7 @@
new ArgumentExtractor<Dynamic>() {
@Override
public Dynamic extractArgument(
- JSInstance jsInstance, ReadableNativeArray jsArguments, int atIndex) {
+ JSInstance jsInstance, ReadableArray jsArguments, int atIndex) {
return DynamicFromArray.create(jsArguments, atIndex);
}
};
@@ -96,7 +96,7 @@
new ArgumentExtractor<ReadableMap>() {
@Override
public ReadableMap extractArgument(
- JSInstance jsInstance, ReadableNativeArray jsArguments, int atIndex) {
+ JSInstance jsInstance, ReadableArray jsArguments, int atIndex) {
return jsArguments.getMap(atIndex);
}
};
@@ -105,7 +105,7 @@
new ArgumentExtractor<Callback>() {
@Override
public @Nullable Callback extractArgument(
- JSInstance jsInstance, ReadableNativeArray jsArguments, int atIndex) {
+ JSInstance jsInstance, ReadableArray jsArguments, int atIndex) {
if (jsArguments.isNull(atIndex)) {
return null;
} else {
@@ -124,7 +124,7 @@
@Override
public Promise extractArgument(
- JSInstance jsInstance, ReadableNativeArray jsArguments, int atIndex) {
+ JSInstance jsInstance, ReadableArray jsArguments, int atIndex) {
Callback resolve = ARGUMENT_EXTRACTOR_CALLBACK
.extractArgument(jsInstance, jsArguments, atIndex);
Callback reject = ARGUMENT_EXTRACTOR_CALLBACK
@@ -328,7 +328,7 @@
}
@Override
- public void invoke(JSInstance jsInstance, ReadableNativeArray parameters) {
+ public void invoke(JSInstance jsInstance, ReadableArray parameters) {
String traceName = mModuleWrapper.getName() + "." + mMethod.getName();
SystraceMessage.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "callJavaModuleMethod")
.arg("method", traceName)

ReactAndroid/src/main/java/com/facebook/react/bridge/JavaModuleWrapper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -49,14 +49,12 @@
private final JSInstance mJSInstance;
private final ModuleHolder mModuleHolder;
- private final String mClassName;
private final ArrayList<NativeModule.NativeMethod> mMethods;
private final ArrayList<MethodDescriptor> mDescs;
- public JavaModuleWrapper(JSInstance jsInstance, String className, ModuleHolder moduleHolder) {
+ public JavaModuleWrapper(JSInstance jsInstance, ModuleHolder moduleHolder) {
mJSInstance = jsInstance;
mModuleHolder = moduleHolder;
- mClassName = className;
mMethods = new ArrayList<>();
mDescs = new ArrayList();
}
@@ -143,10 +141,10 @@
try {
return Arguments.makeNativeMap(map);
} finally {
- ReactMarker.logMarker(CONVERT_CONSTANTS_END);
+ ReactMarker.logMarker(CONVERT_CONSTANTS_END, moduleName);
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
- ReactMarker.logMarker(GET_CONSTANTS_END);
+ ReactMarker.logMarker(GET_CONSTANTS_END, moduleName);
SystraceMessage.endSection(TRACE_TAG_REACT_JAVA_BRIDGE).flush();
}
}

ReactAndroid/src/main/java/com/facebook/react/bridge/JavaOnlyArray.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,6 +11,9 @@
import java.util.Arrays;
import java.util.List;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
/**
* Java {@link ArrayList} backed implementation of {@link ReadableArray} and {@link WritableArray}
* Instances of this class SHOULD NOT be used for communication between java and JS, use instances
@@ -95,7 +98,7 @@
}
@Override
- public String getString(int index) {
+ public @Nullable String getString(int index) {
return (String) mBackingList.get(index);
}
@@ -115,12 +118,12 @@
}
@Override
- public Dynamic getDynamic(int index) {
+ public @Nonnull Dynamic getDynamic(int index) {
return DynamicFromArray.create(this, index);
}
@Override
- public ReadableType getType(int index) {
+ public @Nonnull ReadableType getType(int index) {
Object object = mBackingList.get(index);
if (object == null) {
@@ -157,17 +160,17 @@
}
@Override
- public void pushString(String value) {
+ public void pushString(@Nullable String value) {
mBackingList.add(value);
}
@Override
- public void pushArray(WritableArray array) {
+ public void pushArray(@Nullable WritableArray array) {
mBackingList.add(array);
}
@Override
- public void pushMap(WritableMap map) {
+ public void pushMap(@Nullable WritableMap map) {
mBackingList.add(map);
}
@@ -177,7 +180,7 @@
}
@Override
- public ArrayList<Object> toArrayList() {
+ public @Nonnull ArrayList<Object> toArrayList() {
return new ArrayList<Object>(mBackingList);
}

ReactAndroid/src/main/java/com/facebook/react/bridge/JavaOnlyMap.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,6 +11,9 @@
import java.util.Iterator;
import java.util.Map;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
/**
* Java {@link HashMap} backed implementation of {@link ReadableMap} and {@link WritableMap}
* Instances of this class SHOULD NOT be used for communication between java and JS, use instances
@@ -77,52 +80,52 @@
}
@Override
- public boolean hasKey(String name) {
+ public boolean hasKey(@Nonnull String name) {
return mBackingMap.containsKey(name);
}
@Override
- public boolean isNull(String name) {
+ public boolean isNull(@Nonnull String name) {
return mBackingMap.get(name) == null;
}
@Override
- public boolean getBoolean(String name) {
+ public boolean getBoolean(@Nonnull String name) {
return (Boolean) mBackingMap.get(name);
}
@Override
- public double getDouble(String name) {
+ public double getDouble(@Nonnull String name) {
return ((Number) mBackingMap.get(name)).doubleValue();
}
@Override
- public int getInt(String name) {
+ public int getInt(@Nonnull String name) {
return ((Number) mBackingMap.get(name)).intValue();
}
@Override
- public String getString(String name) {
+ public String getString(@Nonnull String name) {
return (String) mBackingMap.get(name);
}
@Override
- public ReadableMap getMap(String name) {
+ public ReadableMap getMap(@Nonnull String name) {
return (ReadableMap) mBackingMap.get(name);
}
@Override
- public JavaOnlyArray getArray(String name) {
+ public JavaOnlyArray getArray(@Nonnull String name) {
return (JavaOnlyArray) mBackingMap.get(name);
}
@Override
- public Dynamic getDynamic(String name) {
+ public @Nonnull Dynamic getDynamic(@Nonnull String name) {
return DynamicFromMap.create(this, name);
}
@Override
- public ReadableType getType(String name) {
+ public @Nonnull ReadableType getType(@Nonnull String name) {
Object value = mBackingMap.get(name);
if (value == null) {
return ReadableType.Null;
@@ -145,7 +148,7 @@
}
@Override
- public ReadableMapKeySetIterator keySetIterator() {
+ public @Nonnull ReadableMapKeySetIterator keySetIterator() {
return new ReadableMapKeySetIterator() {
Iterator<String> mIterator = mBackingMap.keySet().iterator();
@@ -162,47 +165,47 @@
}
@Override
- public void putBoolean(String key, boolean value) {
+ public void putBoolean(@Nonnull String key, boolean value) {
mBackingMap.put(key, value);
}
@Override
- public void putDouble(String key, double value) {
+ public void putDouble(@Nonnull String key, double value) {
mBackingMap.put(key, value);
}
@Override
- public void putInt(String key, int value) {
+ public void putInt(@Nonnull String key, int value) {
mBackingMap.put(key, value);
}
@Override
- public void putString(String key, String value) {
+ public void putString(@Nonnull String key, @Nullable String value) {
mBackingMap.put(key, value);
}
@Override
- public void putNull(String key) {
+ public void putNull(@Nonnull String key) {
mBackingMap.put(key, null);
}
@Override
- public void putMap(String key, WritableMap value) {
+ public void putMap(@Nonnull String key, @Nullable WritableMap value) {
mBackingMap.put(key, value);
}
@Override
- public void merge(ReadableMap source) {
+ public void merge(@Nonnull ReadableMap source) {
mBackingMap.putAll(((JavaOnlyMap) source).mBackingMap);
}
@Override
- public void putArray(String key, WritableArray value) {
+ public void putArray(@Nonnull String key, @Nullable WritableArray value) {
mBackingMap.put(key, value);
}
@Override
- public HashMap<String, Object> toHashMap() {
+ public @Nonnull HashMap<String, Object> toHashMap() {
return new HashMap<String, Object>(mBackingMap);
}

ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptContextHolder.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptExecutorFactory.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptExecutor.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptModuleRegistry.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/JSApplicationCausedNativeException.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/JSApplicationIllegalArgumentException.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoaderDelegate.java

@@ -0,0 +1,58 @@
+/**
+ * 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.bridge;
+
+import android.content.Context;
+import android.content.res.AssetManager;
+
+/**
+ * An interface for classes that initialize JavaScript using {@link JSBundleLoader}
+ */
+public interface JSBundleLoaderDelegate {
+
+ /**
+ * Load a JS bundle from Android assets. See {@link JSBundleLoader#createAssetLoader(Context, String, boolean)}
+ * @param assetManager
+ * @param assetURL
+ * @param loadSynchronously
+ */
+ void loadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously);
+
+ /**
+ * Load a JS bundle from the filesystem.
+ * See {@link JSBundleLoader#createFileLoader(String)} and {@link JSBundleLoader#createCachedBundleFromNetworkLoader(String, String)}
+ * @param fileName
+ * @param sourceURL
+ * @param loadSynchronously
+ */
+ void loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously);
+
+ /**
+ * Load a delta bundle from Metro.
+ * See {@link JSBundleLoader#createDeltaFromNetworkLoader(String, NativeDeltaClient)}
+ * @param sourceURL
+ * @param deltaClient
+ * @param loadSynchronously
+ */
+ void loadScriptFromDeltaBundle(
+ String sourceURL,
+ NativeDeltaClient deltaClient,
+ boolean loadSynchronously);
+
+ /**
+ * This API is used in situations where the JS bundle is being executed not on
+ * the device, but on a host machine. In that case, we must provide two source
+ * URLs for the JS bundle: One to be used on the device, and one to be used on
+ * the remote debugging machine.
+ *
+ * @param deviceURL A source URL that is accessible from this device.
+ * @param remoteURL A source URL that is accessible from the remote machine
+ * executing the JS.
+ */
+ void setSourceURLs(String deviceURL, String remoteURL);
+}

ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -8,12 +8,11 @@
package com.facebook.react.bridge;
import android.content.Context;
-import com.facebook.react.bridge.NativeDeltaClient;
import com.facebook.react.common.DebugServerException;
/**
- * A class that stores JS bundle information and allows {@link CatalystInstance} to load a correct
- * bundle through {@link ReactBridge}.
+ * A class that stores JS bundle information and allows a {@link JSBundleLoaderDelegate}
+ * (e.g. {@link CatalystInstance}) to load a correct bundle through {@link ReactBridge}.
*/
public abstract class JSBundleLoader {
@@ -28,8 +27,8 @@
final boolean loadSynchronously) {
return new JSBundleLoader() {
@Override
- public String loadScript(CatalystInstanceImpl instance) {
- instance.loadScriptFromAssets(context.getAssets(), assetUrl, loadSynchronously);
+ public String loadScript(JSBundleLoaderDelegate delegate) {
+ delegate.loadScriptFromAssets(context.getAssets(), assetUrl, loadSynchronously);
return assetUrl;
}
};
@@ -49,8 +48,8 @@
final boolean loadSynchronously) {
return new JSBundleLoader() {
@Override
- public String loadScript(CatalystInstanceImpl instance) {
- instance.loadScriptFromFile(fileName, assetUrl, loadSynchronously);
+ public String loadScript(JSBundleLoaderDelegate delegate) {
+ delegate.loadScriptFromFile(fileName, assetUrl, loadSynchronously);
return fileName;
}
};
@@ -68,9 +67,9 @@
final String cachedFileLocation) {
return new JSBundleLoader() {
@Override
- public String loadScript(CatalystInstanceImpl instance) {
+ public String loadScript(JSBundleLoaderDelegate delegate) {
try {
- instance.loadScriptFromFile(cachedFileLocation, sourceURL, false);
+ delegate.loadScriptFromFile(cachedFileLocation, sourceURL, false);
return sourceURL;
} catch (Exception e) {
throw DebugServerException.makeGeneric(e.getMessage(), e);
@@ -90,9 +89,9 @@
final NativeDeltaClient nativeDeltaClient) {
return new JSBundleLoader() {
@Override
- public String loadScript(CatalystInstanceImpl instance) {
+ public String loadScript(JSBundleLoaderDelegate delegate) {
try {
- instance.loadScriptFromDeltaBundle(sourceURL, nativeDeltaClient, false);
+ delegate.loadScriptFromDeltaBundle(sourceURL, nativeDeltaClient, false);
return sourceURL;
} catch (Exception e) {
throw DebugServerException.makeGeneric(e.getMessage(), e);
@@ -110,13 +109,13 @@
final String realSourceURL) {
return new JSBundleLoader() {
@Override
- public String loadScript(CatalystInstanceImpl instance) {
- instance.setSourceURLs(realSourceURL, proxySourceURL);
+ public String loadScript(JSBundleLoaderDelegate delegate) {
+ delegate.setSourceURLs(realSourceURL, proxySourceURL);
return realSourceURL;
}
};
}
/** Loads the script, returning the URL of the source it loaded. */
- public abstract String loadScript(CatalystInstanceImpl instance);
+ public abstract String loadScript(JSBundleLoaderDelegate delegate);
}

ReactAndroid/src/main/java/com/facebook/react/bridge/JSCJavaScriptExecutorFactory.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -24,4 +24,9 @@
jscConfig.putString("DeviceIdentity", mDeviceName);
return new JSCJavaScriptExecutor(jscConfig);
}
+
+ @Override
+ public String toString() {
+ return "JSCExecutor";
+ }
}

ReactAndroid/src/main/java/com/facebook/react/bridge/JSCJavaScriptExecutor.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/JSIModuleHolder.java

@@ -1,3 +1,10 @@
+/**
+ * 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.bridge;
public class JSIModuleHolder {

ReactAndroid/src/main/java/com/facebook/react/bridge/JSIModule.java

@@ -1,3 +1,10 @@
+/**
+ * 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.bridge;
/**

ReactAndroid/src/main/java/com/facebook/react/bridge/JSIModulePackage.java

@@ -1,3 +1,10 @@
+/**
+ * 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.bridge;
import java.util.List;

ReactAndroid/src/main/java/com/facebook/react/bridge/JSIModuleProvider.java

@@ -1,3 +1,10 @@
+/**
+ * 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.bridge;
public interface JSIModuleProvider<T extends JSIModule> {

ReactAndroid/src/main/java/com/facebook/react/bridge/JSIModuleRegistry.java

@@ -1,3 +1,10 @@
+/**
+ * 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.bridge;
import com.facebook.infer.annotation.Assertions;

ReactAndroid/src/main/java/com/facebook/react/bridge/JSIModuleSpec.java

@@ -1,3 +1,10 @@
+/**
+ * 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.bridge;
/**

ReactAndroid/src/main/java/com/facebook/react/bridge/JSInstance.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -15,7 +15,7 @@
public interface JSInstance {
void invokeCallback(
int callbackID,
- NativeArray arguments);
+ NativeArrayInterface arguments);
// TODO if this interface survives refactoring, think about adding
// callFunction.
}

ReactAndroid/src/main/java/com/facebook/react/bridge/JsonWriterHelper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/JsonWriter.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/LifecycleEventListener.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/MemoryPressure.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/MemoryPressureListener.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/ModuleHolder.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -15,6 +15,7 @@
import com.facebook.infer.annotation.Assertions;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.module.model.ReactModuleInfo;
+import com.facebook.react.turbomodule.core.interfaces.TurboModule;
import com.facebook.systrace.SystraceMessage;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.Nullable;
@@ -24,11 +25,12 @@
/**
* Holder to enable us to lazy create native modules.
*
- * This works by taking a provider instead of an instance, when it is first required we'll create
+ * <p>This works by taking a provider instead of an instance, when it is first required we'll create
* and initialize it. Initialization currently always happens on the UI thread but this is due to
* change for performance reasons.
*
- * Lifecycle events via a {@link LifecycleEventListener} will still always happen on the UI thread.
+ * <p>Lifecycle events via a {@link LifecycleEventListener} will still always happen on the UI
+ * thread.
*/
@DoNotStrip
public class ModuleHolder {
@@ -38,9 +40,7 @@
private final int mInstanceKey = sInstanceKeyCounter.getAndIncrement();
private final String mName;
- private final boolean mCanOverrideExistingModule;
- private final boolean mHasConstants;
- private final boolean mIsCxxModule;
+ private final ReactModuleInfo mReactModuleInfo;
private @Nullable Provider<? extends NativeModule> mProvider;
// Outside of the constructur, these should only be checked or set when synchronized on this
@@ -53,10 +53,8 @@
public ModuleHolder(ReactModuleInfo moduleInfo, Provider<? extends NativeModule> provider) {
mName = moduleInfo.name();
- mCanOverrideExistingModule = moduleInfo.canOverrideExistingModule();
- mHasConstants = moduleInfo.hasConstants();
mProvider = provider;
- mIsCxxModule = moduleInfo.isCxxModule();
+ mReactModuleInfo = moduleInfo;
if (moduleInfo.needsEagerInit()) {
mModule = create();
}
@@ -64,9 +62,17 @@
public ModuleHolder(NativeModule nativeModule) {
mName = nativeModule.getName();
- mCanOverrideExistingModule = nativeModule.canOverrideExistingModule();
- mHasConstants = true;
- mIsCxxModule = CxxModuleWrapper.class.isAssignableFrom(nativeModule.getClass());
+ mReactModuleInfo =
+ new ReactModuleInfo(
+ nativeModule.getName(),
+ nativeModule.getClass().getSimpleName(),
+ nativeModule.canOverrideExistingModule(),
+ true,
+ true,
+ CxxModuleWrapper.class.isAssignableFrom(nativeModule.getClass()),
+ TurboModule.class.isAssignableFrom(nativeModule.getClass())
+ );
+
mModule = nativeModule;
PrinterHolder.getPrinter()
.logMessage(ReactDebugOverlayTags.NATIVE_MODULE, "NativeModule init: %s", mName);
@@ -109,14 +115,24 @@
}
public boolean getCanOverrideExistingModule() {
- return mCanOverrideExistingModule;
+ return mReactModuleInfo.canOverrideExistingModule();
}
public boolean getHasConstants() {
- return mHasConstants;
+ return mReactModuleInfo.hasConstants();
+ }
+
+ public boolean isTurboModule() {
+ return mReactModuleInfo.isTurboModule();
}
- public boolean isCxxModule() {return mIsCxxModule; }
+ public boolean isCxxModule() {
+ return mReactModuleInfo.isCxxModule();
+ }
+
+ public String getClassName() {
+ return mReactModuleInfo.className();
+ }
@DoNotStrip
public NativeModule getModule() {
@@ -125,7 +141,8 @@
synchronized (this) {
if (mModule != null) {
return mModule;
- // if mModule has not been set, and no one is creating it. Then this thread should call create
+ // if mModule has not been set, and no one is creating it. Then this thread should call
+ // create
} else if (!mIsCreating) {
shouldCreate = true;
mIsCreating = true;
@@ -172,7 +189,7 @@
module = assertNotNull(mProvider).get();
mProvider = null;
boolean shouldInitializeNow = false;
- synchronized(this) {
+ synchronized (this) {
mModule = module;
if (mInitializable && !mIsInitializing) {
shouldInitializeNow = true;
@@ -182,7 +199,7 @@
doInitialize(module);
}
} finally {
- ReactMarker.logMarker(CREATE_MODULE_END, mInstanceKey);
+ ReactMarker.logMarker(CREATE_MODULE_END, mName ,mInstanceKey);
SystraceMessage.endSection(TRACE_TAG_REACT_JAVA_BRIDGE).flush();
}
return module;
@@ -204,14 +221,15 @@
}
if (shouldInitialize) {
module.initialize();
- // Once finished, set flags accordingly, but we don't expect anyone to wait for this to finish
+ // Once finished, set flags accordingly, but we don't expect anyone to wait for this to
+ // finish
// So no need to notify other threads
synchronized (this) {
mIsInitializing = false;
}
}
} finally {
- ReactMarker.logMarker(ReactMarkerConstants.INITIALIZE_MODULE_END, mInstanceKey);
+ ReactMarker.logMarker(ReactMarkerConstants.INITIALIZE_MODULE_END, mName, mInstanceKey);
SystraceMessage.endSection(TRACE_TAG_REACT_JAVA_BRIDGE).flush();
}
}

ReactAndroid/src/main/java/com/facebook/react/bridge/ModuleSpec.java

@@ -1,73 +1,45 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
+ * <p>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.bridge;
-import com.facebook.react.common.build.ReactBuildConfig;
-import java.lang.reflect.Constructor;
+import com.facebook.common.logging.FLog;
+import com.facebook.react.module.annotations.ReactModule;
import javax.annotation.Nullable;
import javax.inject.Provider;
/**
- * A specification for a native module. This exists so that we don't have to pay the cost
- * for creation until/if the module is used.
- *
- * If your module either has a default constructor or one taking ReactApplicationContext you can use
- * {@link #simple(Class)} or {@link #simple(Class, ReactApplicationContext)}} methods.
+ * A specification for a native module. This exists so that we don't have to pay the cost for
+ * creation until/if the module is used.
*/
public class ModuleSpec {
- private static final Class[] EMPTY_SIGNATURE = {};
- private static final Class[] CONTEXT_SIGNATURE = { ReactApplicationContext.class };
+ private static final String TAG = "ModuleSpec";
private final @Nullable Class<? extends NativeModule> mType;
private final Provider<? extends NativeModule> mProvider;
- private final String mClassName;
-
- /**
- * Simple spec for modules with a default constructor.
- */
- public static ModuleSpec simple(final Class<? extends NativeModule> type) {
- return new ModuleSpec(type, new ConstructorProvider(type, EMPTY_SIGNATURE) {
- @Override
- public NativeModule get() {
- try {
- return getConstructor(type, EMPTY_SIGNATURE).newInstance();
- } catch (Exception e) {
- throw new RuntimeException("ModuleSpec with class: " + type.getName(), e);
- }
- }
- });
- }
-
- /**
- * Simple spec for modules with a constructor taking ReactApplicationContext.
- */
- public static ModuleSpec simple(
- final Class<? extends NativeModule> type,
- final ReactApplicationContext context) {
- return new ModuleSpec(type, new ConstructorProvider(type, CONTEXT_SIGNATURE) {
- @Override
- public NativeModule get() {
- try {
- return getConstructor(type, CONTEXT_SIGNATURE).newInstance(context);
- } catch (Exception e) {
- throw new RuntimeException("ModuleSpec with class: " + type.getName(), e);
- }
- }
- });
- }
+ private final String mName;
public static ModuleSpec viewManagerSpec(Provider<? extends NativeModule> provider) {
- return new ModuleSpec(null, provider);
+ return new ModuleSpec(provider);
}
public static ModuleSpec nativeModuleSpec(
Class<? extends NativeModule> type, Provider<? extends NativeModule> provider) {
- return new ModuleSpec(provider, type.getName());
+ ReactModule annotation = type.getAnnotation(ReactModule.class);
+ if (annotation == null) {
+ FLog.w(
+ TAG,
+ "Could not find @ReactModule annotation on "
+ + type.getName()
+ + ". So creating the module eagerly to get the name. Consider adding an annotation to make this Lazy");
+ NativeModule nativeModule = provider.get();
+ return new ModuleSpec(provider, nativeModule.getName());
+ } else {
+ return new ModuleSpec(provider, annotation.name());
+ }
}
public static ModuleSpec nativeModuleSpec(
@@ -75,50 +47,32 @@
return new ModuleSpec(provider, className);
}
- private ModuleSpec(
- @Nullable Class<? extends NativeModule> type, Provider<? extends NativeModule> provider) {
- mType = type;
+ /**
+ * Called by View Managers
+ *
+ * @param provider
+ */
+ private ModuleSpec(Provider<? extends NativeModule> provider) {
+ mType = null;
mProvider = provider;
- mClassName = type == null ? null : type.getName();
+ mName = null;
}
- public ModuleSpec(Provider<? extends NativeModule> provider, String name) {
+ private ModuleSpec(Provider<? extends NativeModule> provider, String name) {
mType = null;
mProvider = provider;
- mClassName = name;
+ mName = name;
}
public @Nullable Class<? extends NativeModule> getType() {
return mType;
}
- public String getClassName(){return mClassName;}
+ public String getName() {
+ return mName;
+ }
public Provider<? extends NativeModule> getProvider() {
return mProvider;
}
-
- private static abstract class ConstructorProvider implements Provider<NativeModule> {
- protected @Nullable Constructor<? extends NativeModule> mConstructor;
-
- public ConstructorProvider(Class<? extends NativeModule> type, Class[] signature) {
- if (ReactBuildConfig.DEBUG) {
- try {
- mConstructor = getConstructor(type, signature);
- } catch (NoSuchMethodException e) {
- throw new IllegalArgumentException("No such constructor", e);
- }
- }
- }
-
- protected Constructor<? extends NativeModule> getConstructor(
- Class<? extends NativeModule> mType,
- Class[] signature) throws NoSuchMethodException {
- if (mConstructor != null) {
- return mConstructor;
- } else {
- return mType.getConstructor(signature);
- }
- }
- }
}

ReactAndroid/src/main/java/com/facebook/react/bridge/NativeArgumentsParseException.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/NativeArrayInterface.java

@@ -0,0 +1,13 @@
+/**
+ * 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.bridge;
+
+public interface NativeArrayInterface {
+ @Override
+ String toString();
+}

ReactAndroid/src/main/java/com/facebook/react/bridge/NativeArray.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -14,7 +14,7 @@
* Base class for an array whose members are stored in native code (C++).
*/
@DoNotStrip
-public abstract class NativeArray {
+public abstract class NativeArray implements NativeArrayInterface{
static {
ReactBridge.staticInit();
}

ReactAndroid/src/main/java/com/facebook/react/bridge/NativeDeltaClient.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2018-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/NativeMap.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleCallExceptionHandler.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,6 +9,8 @@
import com.facebook.proguard.annotations.DoNotStrip;
+import javax.annotation.Nonnull;
+
/**
* A native module whose API can be provided to JS catalyst instances. {@link NativeModule}s whose
@@ -20,7 +22,7 @@
@DoNotStrip
public interface NativeModule {
interface NativeMethod {
- void invoke(JSInstance jsInstance, ReadableNativeArray parameters);
+ void invoke(JSInstance jsInstance, ReadableArray parameters);
String getType();
}
@@ -28,7 +30,7 @@
* @return the name of this module. This will be the name used to {@code require()} this module
* from javascript.
*/
- String getName();
+ @Nonnull String getName();
/**
* This is called at the end of {@link CatalystApplicationFragment#createCatalystInstance()}

ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java

@@ -1,37 +1,32 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
+ * <p>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.bridge;
import com.facebook.infer.annotation.Assertions;
+import com.facebook.react.module.annotations.ReactModule;
import com.facebook.systrace.Systrace;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
-/**
- * A set of Java APIs to expose to a particular JavaScript instance.
- */
+/** A set of Java APIs to expose to a particular JavaScript instance. */
public class NativeModuleRegistry {
private final ReactApplicationContext mReactApplicationContext;
private final Map<String, ModuleHolder> mModules;
public NativeModuleRegistry(
- ReactApplicationContext reactApplicationContext,
- Map<String, ModuleHolder> modules) {
+ ReactApplicationContext reactApplicationContext, Map<String, ModuleHolder> modules) {
mReactApplicationContext = reactApplicationContext;
mModules = modules;
}
- /**
- * Private getters for combining NativeModuleRegistrys
- */
+ /** Private getters for combining NativeModuleRegistrys */
private Map<String, ModuleHolder> getModuleMap() {
return mModules;
}
@@ -40,14 +35,11 @@
return mReactApplicationContext;
}
- /* package */ Collection<JavaModuleWrapper> getJavaModules(
- JSInstance jsInstance) {
+ /* package */ Collection<JavaModuleWrapper> getJavaModules(JSInstance jsInstance) {
ArrayList<JavaModuleWrapper> javaModules = new ArrayList<>();
for (Map.Entry<String, ModuleHolder> entry : mModules.entrySet()) {
- String type = entry.getKey();
if (!entry.getValue().isCxxModule()) {
- //if (!CxxModuleWrapperBase.class.isAssignableFrom(entry.getValue().getModule().getClass())) {
- javaModules.add(new JavaModuleWrapper(jsInstance, type, entry.getValue()));
+ javaModules.add(new JavaModuleWrapper(jsInstance, entry.getValue()));
}
}
return javaModules;
@@ -68,7 +60,8 @@
*/
/* package */ void registerModules(NativeModuleRegistry newRegister) {
- Assertions.assertCondition(mReactApplicationContext.equals(newRegister.getReactApplicationContext()),
+ Assertions.assertCondition(
+ mReactApplicationContext.equals(newRegister.getReactApplicationContext()),
"Extending native modules with non-matching application contexts.");
Map<String, ModuleHolder> newModules = newRegister.getModuleMap();
@@ -85,8 +78,7 @@
/* package */ void notifyJSInstanceDestroy() {
mReactApplicationContext.assertOnNativeModulesQueueThread();
Systrace.beginSection(
- Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
- "NativeModuleRegistry_notifyJSInstanceDestroy");
+ Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "NativeModuleRegistry_notifyJSInstanceDestroy");
try {
for (ModuleHolder module : mModules.values()) {
module.destroy();
@@ -97,14 +89,14 @@
}
/* package */ void notifyJSInstanceInitialized() {
- mReactApplicationContext.assertOnNativeModulesQueueThread("From version React Native v0.44, " +
- "native modules are explicitly not initialized on the UI thread. See " +
- "https://github.com/facebook/react-native/wiki/Breaking-Changes#d4611211-reactnativeandroidbreaking-move-nativemodule-initialization-off-ui-thread---aaachiuuu " +
- " for more details.");
+ mReactApplicationContext.assertOnNativeModulesQueueThread(
+ "From version React Native v0.44, "
+ + "native modules are explicitly not initialized on the UI thread. See "
+ + "https://github.com/facebook/react-native/wiki/Breaking-Changes#d4611211-reactnativeandroidbreaking-move-nativemodule-initialization-off-ui-thread---aaachiuuu "
+ + " for more details.");
ReactMarker.logMarker(ReactMarkerConstants.NATIVE_MODULE_INITIALIZE_START);
Systrace.beginSection(
- Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
- "NativeModuleRegistry_notifyJSInstanceInitialized");
+ Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "NativeModuleRegistry_notifyJSInstanceInitialized");
try {
for (ModuleHolder module : mModules.values()) {
module.markInitializable();
@@ -117,22 +109,43 @@
public void onBatchComplete() {
// The only native module that uses the onBatchComplete is the UI Manager. Hence, instead of
- // iterating over all the modules for find this one instance, and then calling it, we short-circuit
+ // iterating over all the modules for find this one instance, and then calling it, we
+ // short-circuit
// the search, and simply call OnBatchComplete on the UI Manager.
// With Fabric, UIManager would no longer be a NativeModule, so this call would simply go away
- ModuleHolder moduleHolder = mModules.get("com.facebook.react.uimanager.UIManagerModule");
+ ModuleHolder moduleHolder = mModules.get("UIManager");
if (moduleHolder != null && moduleHolder.hasInstance()) {
((OnBatchCompleteListener) moduleHolder.getModule()).onBatchComplete();
}
}
public <T extends NativeModule> boolean hasModule(Class<T> moduleInterface) {
- return mModules.containsKey(moduleInterface.getName());
+ String name = moduleInterface.getAnnotation(ReactModule.class).name();
+ return mModules.containsKey(name);
}
public <T extends NativeModule> T getModule(Class<T> moduleInterface) {
- return (T) Assertions.assertNotNull(
- mModules.get(moduleInterface.getName()), moduleInterface.getSimpleName()).getModule();
+ ReactModule annotation = moduleInterface.getAnnotation(ReactModule.class);
+ if (annotation == null) {
+ throw new IllegalArgumentException(
+ "Could not find @ReactModule annotation in class " + moduleInterface.getName());
+ }
+ return (T)
+ Assertions.assertNotNull(
+ mModules.get(annotation.name()),
+ annotation.name()
+ + " could not be found. Is it defined in "
+ + moduleInterface.getName())
+ .getModule();
+ }
+
+ public boolean hasModule(String name) {
+ return mModules.containsKey(name);
+ }
+
+ public NativeModule getModule(String name) {
+ return Assertions.assertNotNull(
+ mModules.get(name), "Could not find module with name " + name).getModule();
}
public List<NativeModule> getAllModules() {

ReactAndroid/src/main/java/com/facebook/react/bridge/NoSuchKeyException.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/NotThreadSafeBridgeIdleDebugListener.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/ObjectAlreadyConsumedException.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/OnBatchCompleteListener.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/PerformanceCounter.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/PromiseImpl.java

@@ -1,71 +1,246 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
*/
-/**
- * Implementation of two javascript functions that can be used to resolve or reject a js promise.
- */
package com.facebook.react.bridge;
+import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+/*
+ * Implementation of {@link Promise} that represents a JavaScript Promise which can be passed to the
+ * native module as a method parameter.
+ *
+ * Methods annotated with {@link ReactMethod} that use a {@link Promise} as the last parameter
+ * will be marked as "promise" and will return a promise when invoked from JavaScript.
+ */
public class PromiseImpl implements Promise {
-
- private static final String DEFAULT_ERROR = "EUNSPECIFIED";
-
- private @Nullable Callback mResolve;
- private @Nullable Callback mReject;
+ // Number of stack frames to parse and return to mReject.invoke
+ // for ERROR_MAP_KEY_NATIVE_STACK
+ private static final int ERROR_STACK_FRAME_LIMIT = 10;
+
+ private static final String ERROR_DEFAULT_CODE = "EUNSPECIFIED";
+ private static final String ERROR_DEFAULT_MESSAGE = "Error not specified.";
+
+ // Keys for mReject's WritableMap
+ private static final String ERROR_MAP_KEY_CODE = "code";
+ private static final String ERROR_MAP_KEY_MESSAGE = "message";
+ private static final String ERROR_MAP_KEY_USER_INFO = "userInfo";
+ private static final String ERROR_MAP_KEY_NATIVE_STACK = "nativeStackAndroid";
+
+ // Keys for ERROR_MAP_KEY_NATIVE_STACK's StackFrame maps
+ private static final String STACK_FRAME_KEY_FILE = "file";
+ private static final String STACK_FRAME_KEY_LINE_NUMBER = "lineNumber";
+ private static final String STACK_FRAME_KEY_METHOD_NAME = "methodName";
+
+ private @Nullable
+ Callback mResolve;
+ private @Nullable
+ Callback mReject;
public PromiseImpl(@Nullable Callback resolve, @Nullable Callback reject) {
mResolve = resolve;
mReject = reject;
}
+ /**
+ * Successfully resolve the Promise with an optional value.
+ *
+ * @param value Object
+ */
@Override
public void resolve(Object value) {
if (mResolve != null) {
mResolve.invoke(value);
+ mResolve = null;
+ mReject = null;
}
}
+ /**
+ * Report an error without an exception using a custom code and error message.
+ *
+ * @param code String
+ * @param message String
+ */
@Override
public void reject(String code, String message) {
- reject(code, message, /*Throwable*/null);
+ reject(code, message, /*Throwable*/null, /*WritableMap*/null);
}
+ /**
+ * Report an exception with a custom code.
+ *
+ * @param code String
+ * @param throwable Throwable
+ */
@Override
- @Deprecated
- public void reject(String message) {
- reject(DEFAULT_ERROR, message, /*Throwable*/null);
+ public void reject(String code, Throwable throwable) {
+ reject(code, /*Message*/null, throwable, /*WritableMap*/null);
}
+ /**
+ * Report an exception with a custom code and error message.
+ *
+ * @param code String
+ * @param message String
+ * @param throwable Throwable
+ */
@Override
- public void reject(String code, Throwable e) {
- reject(code, e.getMessage(), e);
+ public void reject(String code, String message, Throwable throwable) {
+ reject(code, message, throwable, /*WritableMap*/null);
}
+ /**
+ * Report an exception, with default error code.
+ * Useful in catch-all scenarios where it's unclear why the error occurred.
+ *
+ * @param throwable Throwable
+ */
@Override
- public void reject(Throwable e) {
- reject(DEFAULT_ERROR, e.getMessage(), e);
+ public void reject(Throwable throwable) {
+ reject(/*Code*/null, /*Message*/null, throwable, /*WritableMap*/null);
}
+ /* ---------------------------
+ * With userInfo WritableMap
+ * --------------------------- */
+
+ /**
+ * Report an exception, with default error code, with userInfo.
+ * Useful in catch-all scenarios where it's unclear why the error occurred.
+ *
+ * @param throwable Throwable
+ * @param userInfo WritableMap
+ */
@Override
- public void reject(String code, String message, @Nullable Throwable e) {
- if (mReject != null) {
- if (code == null) {
- code = DEFAULT_ERROR;
+ public void reject(Throwable throwable, WritableMap userInfo) {
+ reject(/*Code*/null, /*Message*/null, throwable, userInfo);
+ }
+
+ /**
+ * Reject with a code and userInfo WritableMap.
+ *
+ * @param code String
+ * @param userInfo WritableMap
+ */
+ @Override
+ public void reject(String code, @Nonnull WritableMap userInfo) {
+ reject(code, /*Message*/null, /*Throwable*/null, userInfo);
+ }
+
+ /**
+ * Report an exception with a custom code and userInfo.
+ *
+ * @param code String
+ * @param throwable Throwable
+ * @param userInfo WritableMap
+ */
+ @Override
+ public void reject(String code, Throwable throwable, WritableMap userInfo) {
+ reject(code, /*Message*/null, throwable, userInfo);
+ }
+
+ /**
+ * Report an error with a custom code, error message and userInfo,
+ * an error not caused by an exception.
+ *
+ * @param code String
+ * @param message String
+ * @param userInfo WritableMap
+ */
+ @Override
+ public void reject(String code, String message, @Nonnull WritableMap userInfo) {
+ reject(code, message, /*Throwable*/null, userInfo);
+ }
+
+ /**
+ * Report an exception with a custom code, error message and userInfo.
+ *
+ * @param code String
+ * @param message String
+ * @param throwable Throwable
+ * @param userInfo WritableMap
+ */
+ @Override
+ public void reject(
+ @Nullable String code,
+ @Nullable String message,
+ @Nullable Throwable throwable,
+ @Nullable WritableMap userInfo
+ ) {
+ if (mReject == null) {
+ mResolve = null;
+ return;
}
- // The JavaScript side expects a map with at least the error message.
- // It is possible to expose all kind of information. It will be available on the JS
- // error instance.
+
WritableNativeMap errorInfo = new WritableNativeMap();
- errorInfo.putString("code", code);
- errorInfo.putString("message", message);
- // TODO(8850038): add the stack trace info in, need to figure out way to serialize that
+
+ if (code == null) {
+ errorInfo.putString(ERROR_MAP_KEY_CODE, ERROR_DEFAULT_CODE);
+ } else {
+ errorInfo.putString(ERROR_MAP_KEY_CODE, code);
+ }
+
+ // Use the custom message if provided otherwise use the throwable message.
+ if (message != null) {
+ errorInfo.putString(ERROR_MAP_KEY_MESSAGE, message);
+ } else if (throwable != null) {
+ errorInfo.putString(ERROR_MAP_KEY_MESSAGE, throwable.getMessage());
+ } else {
+ // The JavaScript side expects a map with at least an error message.
+ // /Libraries/BatchedBridge/NativeModules.js -> createErrorFromErrorData
+ // TYPE: (errorData: { message: string })
+ errorInfo.putString(ERROR_MAP_KEY_MESSAGE, ERROR_DEFAULT_MESSAGE);
+ }
+
+ // For consistency with iOS ensure userInfo key exists, even if we null it.
+ // iOS: /React/Base/RCTUtils.m -> RCTJSErrorFromCodeMessageAndNSError
+ if (userInfo != null) {
+ errorInfo.putMap(ERROR_MAP_KEY_USER_INFO, userInfo);
+ } else {
+ errorInfo.putNull(ERROR_MAP_KEY_USER_INFO);
+ }
+
+ // Attach a nativeStackAndroid array if a throwable was passed
+ // this matches iOS behavior - iOS adds a `nativeStackIOS` property
+ // iOS: /React/Base/RCTUtils.m -> RCTJSErrorFromCodeMessageAndNSError
+ if (throwable != null) {
+ StackTraceElement[] stackTrace = throwable.getStackTrace();
+ WritableNativeArray nativeStackAndroid = new WritableNativeArray();
+
+ // Build an an Array of StackFrames to match JavaScript:
+ // iOS: /Libraries/Core/Devtools/parseErrorStack.js -> StackFrame
+ for (int i = 0; i < stackTrace.length && i < ERROR_STACK_FRAME_LIMIT; i++) {
+ StackTraceElement frame = stackTrace[i];
+ WritableMap frameMap = new WritableNativeMap();
+ // NOTE: no column number exists StackTraceElement
+ frameMap.putString(STACK_FRAME_KEY_FILE, frame.getFileName());
+ frameMap.putInt(STACK_FRAME_KEY_LINE_NUMBER, frame.getLineNumber());
+ frameMap.putString(STACK_FRAME_KEY_METHOD_NAME, frame.getMethodName());
+ nativeStackAndroid.pushMap(frameMap);
+ }
+
+ errorInfo.putArray(ERROR_MAP_KEY_NATIVE_STACK, nativeStackAndroid);
+ } else {
+ errorInfo.putArray(ERROR_MAP_KEY_NATIVE_STACK, new WritableNativeArray());
+ }
+
mReject.invoke(errorInfo);
+ mResolve = null;
+ mReject = null;
}
+
+ /* ------------
+ * Deprecated
+ * ------------ */
+
+ @Override
+ @Deprecated
+ public void reject(String message) {
+ reject(/*Code*/null, message, /*Throwable*/null, /*WritableMap*/null);
}
}

ReactAndroid/src/main/java/com/facebook/react/bridge/Promise.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,48 +7,119 @@
package com.facebook.react.bridge;
+import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-/**
+/*
* Interface that represents a JavaScript Promise which can be passed to the native module as a
* method parameter.
*
- * Methods annotated with {@link ReactMethod} that use {@link Promise} as type of the last parameter
+ * Methods annotated with {@link ReactMethod} that use a {@link Promise} as the last parameter
* will be marked as "promise" and will return a promise when invoked from JavaScript.
*/
public interface Promise {
/**
- * Successfully resolve the Promise.
+ * Successfully resolve the Promise with an optional value.
+ *
+ * @param value Object
*/
void resolve(@Nullable Object value);
/**
- * Report an error which wasn't caused by an exception.
+ * Report an error without an exception using a custom code and error message.
+ *
+ * @param code String
+ * @param message String
*/
void reject(String code, String message);
/**
- * Report an exception.
+ * Report an exception with a custom code.
+ *
+ * @param code String
+ * @param throwable Throwable
+ */
+ void reject(String code, Throwable throwable);
+
+ /**
+ * Report an exception with a custom code and error message.
+ *
+ * @param code String
+ * @param message String
+ * @param throwable Throwable
+ */
+ void reject(String code, String message, Throwable throwable);
+
+
+ /**
+ * Report an exception, with default error code.
+ * Useful in catch-all scenarios where it's unclear why the error occurred.
+ *
+ * @param throwable Throwable
+ */
+ void reject(Throwable throwable);
+
+ /* ---------------------------
+ * With userInfo WritableMap
+ * --------------------------- */
+
+ /**
+ * Report an exception, with default error code, with userInfo.
+ * Useful in catch-all scenarios where it's unclear why the error occurred.
+ *
+ * @param throwable Throwable
+ * @param userInfo WritableMap
+ */
+ void reject(Throwable throwable, WritableMap userInfo);
+
+ /**
+ * Reject with a code and userInfo WritableMap.
+ *
+ * @param code String
+ * @param userInfo WritableMap
+ */
+ void reject(String code, @Nonnull WritableMap userInfo);
+
+ /**
+ * Report an exception with a custom code and userInfo.
+ *
+ * @param code String
+ * @param throwable Throwable
+ * @param userInfo WritableMap
*/
- void reject(String code, Throwable e);
+ void reject(String code, Throwable throwable, WritableMap userInfo);
/**
- * Report an exception with a custom error message.
+ * Report an error with a custom code, error message and userInfo,
+ * an error not caused by an exception.
+ *
+ * @param code String
+ * @param message String
+ * @param userInfo WritableMap
*/
- void reject(String code, String message, Throwable e);
+ void reject(String code, String message, @Nonnull WritableMap userInfo);
+
+ /**
+ * Report an exception with a custom code, error message and userInfo.
+ *
+ * @param code String
+ * @param message String
+ * @param throwable Throwable
+ * @param userInfo WritableMap
+ */
+ void reject(String code, String message, Throwable throwable, WritableMap userInfo);
+
+ /* ------------
+ * Deprecated
+ * ------------ */
/**
* Report an error which wasn't caused by an exception.
+ *
* @deprecated Prefer passing a module-specific error code to JS.
* Using this method will pass the error code "EUNSPECIFIED".
*/
@Deprecated
void reject(String message);
-
- /**
- * Report an exception, with default error code.
- * Useful in catch-all scenarios where it's unclear why the error occurred.
- */
- void reject(Throwable reason);
}

ReactAndroid/src/main/java/com/facebook/react/bridge/ProxyJavaScriptExecutor.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,10 +7,9 @@
package com.facebook.react.bridge;
-import javax.annotation.Nullable;
-
import com.facebook.jni.HybridData;
import com.facebook.proguard.annotations.DoNotStrip;
+import javax.annotation.Nullable;
/**
* JavaScript executor that delegates JS calls processed by native code back to a java version

ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadHandler.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,9 +10,10 @@
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
+import android.os.SystemClock;
import android.os.Looper;
import android.os.Process;
-
+import android.util.Pair;
import com.facebook.common.logging.FLog;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.bridge.AssertionException;
@@ -31,15 +32,25 @@
private final Looper mLooper;
private final MessageQueueThreadHandler mHandler;
private final String mAssertionErrorMessage;
+ private MessageQueueThreadPerfStats mPerfStats;
private volatile boolean mIsFinished = false;
private MessageQueueThreadImpl(
String name,
Looper looper,
QueueThreadExceptionHandler exceptionHandler) {
+ this(name, looper, exceptionHandler, null);
+ }
+
+ private MessageQueueThreadImpl(
+ String name,
+ Looper looper,
+ QueueThreadExceptionHandler exceptionHandler,
+ MessageQueueThreadPerfStats stats) {
mName = name;
mLooper = looper;
mHandler = new MessageQueueThreadHandler(looper, exceptionHandler);
+ mPerfStats = stats;
mAssertionErrorMessage = "Expected to be called from the '" + getName() + "' thread!";
}
@@ -126,6 +137,31 @@
}
}
+ @DoNotStrip
+ @Override
+ public MessageQueueThreadPerfStats getPerfStats() {
+ return mPerfStats;
+ }
+
+ @DoNotStrip
+ @Override
+ public void resetPerfStats() {
+ assignToPerfStats(mPerfStats, -1, -1);
+ runOnQueue(new Runnable() {
+ @Override
+ public void run() {
+ long wallTime = SystemClock.uptimeMillis();
+ long cpuTime = SystemClock.currentThreadTimeMillis();
+ assignToPerfStats(mPerfStats, wallTime, cpuTime);
+ }
+ });
+ }
+
+ private static void assignToPerfStats(MessageQueueThreadPerfStats stats, long wall, long cpu) {
+ stats.wallTime = wall;
+ stats.cpuTime = cpu;
+ }
+
public Looper getLooper() {
return mLooper;
}
@@ -180,21 +216,25 @@
final String name,
long stackSize,
QueueThreadExceptionHandler exceptionHandler) {
- final SimpleSettableFuture<Looper> looperFuture = new SimpleSettableFuture<>();
+ final SimpleSettableFuture<Pair<Looper, MessageQueueThreadPerfStats>> dataFuture = new SimpleSettableFuture<>();
+ long startTimeMillis;
Thread bgThread = new Thread(null,
new Runnable() {
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
Looper.prepare();
-
- looperFuture.set(Looper.myLooper());
+ MessageQueueThreadPerfStats stats = new MessageQueueThreadPerfStats();
+ long wallTime = SystemClock.uptimeMillis();
+ long cpuTime = SystemClock.currentThreadTimeMillis();
+ assignToPerfStats(stats, wallTime, cpuTime);
+ dataFuture.set(new Pair<>(Looper.myLooper(), stats));
Looper.loop();
}
}, "mqt_" + name, stackSize);
bgThread.start();
- Looper myLooper = looperFuture.getOrThrow();
- return new MessageQueueThreadImpl(name, myLooper, exceptionHandler);
+ Pair<Looper, MessageQueueThreadPerfStats> pair = dataFuture.getOrThrow();
+ return new MessageQueueThreadImpl(name, pair.first, exceptionHandler, pair.second);
}
}

ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThread.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -58,4 +58,18 @@
*/
@DoNotStrip
void quitSynchronous();
+
+ /**
+ * Returns the perf counters taken when the framework was started. This
+ * method is intended to be used for instrumentation purposes.
+ */
+ @DoNotStrip
+ MessageQueueThreadPerfStats getPerfStats();
+
+ /**
+ * Resets the perf counters. This is useful if the RN threads are being re-used.
+ * This method is intended to be used for instrumentation purposes.
+ */
+ @DoNotStrip
+ void resetPerfStats();
}

ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadPerfStats.java

@@ -0,0 +1,16 @@
+/**
+ * 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.bridge.queue;
+
+/**
+ * This class holds perf counters' values at the beginning of an RN startup.
+ */
+public class MessageQueueThreadPerfStats {
+ public long wallTime;
+ public long cpuTime;
+}

ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadSpec.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/queue/NativeRunnableDeprecated.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/queue/NativeRunnable.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/queue/QueueThreadExceptionHandler.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/queue/ReactQueueConfigurationImpl.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/queue/ReactQueueConfiguration.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/queue/ReactQueueConfigurationSpec.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/ReactApplicationContext.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/ReactBridge.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,16 +7,38 @@
package com.facebook.react.bridge;
+import static com.facebook.systrace.Systrace.TRACE_TAG_REACT_JAVA_BRIDGE;
+
+import android.os.SystemClock;
import com.facebook.soloader.SoLoader;
+import com.facebook.systrace.Systrace;
public class ReactBridge {
+ private static volatile long sLoadStartTime = 0;
+ private static volatile long sLoadEndTime = 0;
+
private static boolean sDidInit = false;
- public static void staticInit() {
- // No locking required here, worst case we'll call into SoLoader twice
- // which will do its own locking internally
- if (!sDidInit) {
- SoLoader.loadLibrary("reactnativejni");
+
+ public synchronized static void staticInit() {
+ if (sDidInit) {
+ return;
+ }
sDidInit = true;
+
+ sLoadStartTime = SystemClock.uptimeMillis();
+ Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "ReactBridge.staticInit::load:reactnativejni");
+ ReactMarker.logMarker(ReactMarkerConstants.LOAD_REACT_NATIVE_SO_FILE_START);
+ SoLoader.loadLibrary("reactnativejni");
+ ReactMarker.logMarker(ReactMarkerConstants.LOAD_REACT_NATIVE_SO_FILE_END);
+ Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
+ sLoadEndTime = SystemClock.uptimeMillis();
}
+
+ public static long getLoadStartTime() {
+ return sLoadStartTime;
+ }
+
+ public static long getLoadEndTime() {
+ return sLoadEndTime;
}
}

ReactAndroid/src/main/java/com/facebook/react/bridge/ReactCallback.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContextBaseJavaModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,6 +7,7 @@
package com.facebook.react.bridge;
+import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import android.app.Activity;
@@ -19,7 +20,7 @@
private final ReactApplicationContext mReactApplicationContext;
- public ReactContextBaseJavaModule(ReactApplicationContext reactContext) {
+ public ReactContextBaseJavaModule(@Nonnull ReactApplicationContext reactContext) {
mReactApplicationContext = reactContext;
}

ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -70,6 +70,15 @@
mJSMessageQueueThread = queueConfig.getJSQueueThread();
}
+ public void resetPerfStats() {
+ if (mNativeModulesMessageQueueThread != null) {
+ mNativeModulesMessageQueueThread.resetPerfStats();
+ }
+ if (mJSMessageQueueThread != null) {
+ mJSMessageQueueThread.resetPerfStats();
+ }
+ }
+
public void setNativeModuleCallExceptionHandler(
@Nullable NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;

ReactAndroid/src/main/java/com/facebook/react/bridge/ReactMarkerConstants.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -25,6 +25,7 @@
NATIVE_MODULE_INITIALIZE_END,
SETUP_REACT_CONTEXT_START,
SETUP_REACT_CONTEXT_END,
+ CHANGE_THREAD_PRIORITY,
CREATE_UI_MANAGER_MODULE_START,
CREATE_UI_MANAGER_MODULE_END,
CREATE_VIEW_MANAGERS_START,
@@ -87,4 +88,12 @@
CREATE_MC_MODULE_GET_METADATA_END,
REGISTER_JS_SEGMENT_START,
REGISTER_JS_SEGMENT_STOP,
+ VM_INIT,
+ ON_FRAGMENT_CREATE,
+ JAVASCRIPT_EXECUTOR_FACTORY_INJECT_START,
+ JAVASCRIPT_EXECUTOR_FACTORY_INJECT_END,
+ LOAD_REACT_NATIVE_SO_FILE_START,
+ LOAD_REACT_NATIVE_SO_FILE_END,
+ LOAD_REACT_NATIVE_FABRIC_SO_FILE_START,
+ LOAD_REACT_NATIVE_FABRIC_SO_FILE_END,
}

ReactAndroid/src/main/java/com/facebook/react/bridge/ReactMarker.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/ReactMethod.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/ReactModuleWithSpec.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/reactnative.pro

@@ -1,3 +1,8 @@
+# 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.
+
-keepnames class * extends com.facebook.react.bridge.JavaScriptModule { *; }
-keepnames class * extends com.facebook.react.bridge.CxxModuleWrapper {*; }
-keepclassmembers class * extends com.facebook.react.bridge.NativeModule {

ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableArray.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,6 +9,9 @@
import java.util.ArrayList;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
/**
* Interface for an array that allows typed access to its members. Used to pass parameters from JS
* to Java.
@@ -20,11 +23,11 @@
boolean getBoolean(int index);
double getDouble(int index);
int getInt(int index);
- String getString(int index);
- ReadableArray getArray(int index);
- ReadableMap getMap(int index);
- Dynamic getDynamic(int index);
- ReadableType getType(int index);
- ArrayList<Object> toArrayList();
+ @Nullable String getString(int index);
+ @Nullable ReadableArray getArray(int index);
+ @Nullable ReadableMap getMap(int index);
+ @Nonnull Dynamic getDynamic(int index);
+ @Nonnull ReadableType getType(int index);
+ @Nonnull ArrayList<Object> toArrayList();
}

ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableMap.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,23 +9,26 @@
import java.util.HashMap;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
/**
* Interface for a map that allows typed access to its members. Used to pass parameters from JS to
* Java.
*/
public interface ReadableMap {
- boolean hasKey(String name);
- boolean isNull(String name);
- boolean getBoolean(String name);
- double getDouble(String name);
- int getInt(String name);
- String getString(String name);
- ReadableArray getArray(String name);
- ReadableMap getMap(String name);
- Dynamic getDynamic(String name);
- ReadableType getType(String name);
- ReadableMapKeySetIterator keySetIterator();
- HashMap<String, Object> toHashMap();
+ boolean hasKey(@Nonnull String name);
+ boolean isNull(@Nonnull String name);
+ boolean getBoolean(@Nonnull String name);
+ double getDouble(@Nonnull String name);
+ int getInt(@Nonnull String name);
+ @Nullable String getString(@Nonnull String name);
+ @Nullable ReadableArray getArray(@Nonnull String name);
+ @Nullable ReadableMap getMap(@Nonnull String name);
+ @Nonnull Dynamic getDynamic(@Nonnull String name);
+ @Nonnull ReadableType getType(@Nonnull String name);
+ @Nonnull ReadableMapKeySetIterator keySetIterator();
+ @Nonnull HashMap<String, Object> toHashMap();
}

ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableMapKeySetIterator.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableNativeArray.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,12 +7,14 @@
package com.facebook.react.bridge;
+import com.facebook.infer.annotation.Assertions;
import com.facebook.jni.HybridData;
import com.facebook.proguard.annotations.DoNotStrip;
-
+import com.facebook.react.config.ReactFeatureFlags;
import java.util.ArrayList;
import java.util.Arrays;
-import com.facebook.infer.annotation.Assertions;
+
+import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
@@ -34,9 +36,8 @@
private @Nullable ReadableType[] mLocalTypeArray;
private static int jniPassCounter = 0;
- private static boolean mUseNativeAccessor = false;
public static void setUseNativeAccessor(boolean useNativeAccessor) {
- mUseNativeAccessor = useNativeAccessor;
+ ReactFeatureFlags.useArrayNativeAccessor = useNativeAccessor;
}
public static int getJNIPassCounter() {
return jniPassCounter;
@@ -77,7 +78,7 @@
@Override
public int size() {
- if (mUseNativeAccessor) {
+ if (ReactFeatureFlags.useArrayNativeAccessor) {
jniPassCounter++;
return sizeNative();
}
@@ -87,7 +88,7 @@
@Override
public boolean isNull(int index) {
- if (mUseNativeAccessor) {
+ if (ReactFeatureFlags.useArrayNativeAccessor) {
jniPassCounter++;
return isNullNative(index);
}
@@ -97,7 +98,7 @@
@Override
public boolean getBoolean(int index) {
- if (mUseNativeAccessor) {
+ if (ReactFeatureFlags.useArrayNativeAccessor) {
jniPassCounter++;
return getBooleanNative(index);
}
@@ -107,7 +108,7 @@
@Override
public double getDouble(int index) {
- if (mUseNativeAccessor) {
+ if (ReactFeatureFlags.useArrayNativeAccessor) {
jniPassCounter++;
return getDoubleNative(index);
}
@@ -117,7 +118,7 @@
@Override
public int getInt(int index) {
- if (mUseNativeAccessor) {
+ if (ReactFeatureFlags.useArrayNativeAccessor) {
jniPassCounter++;
return getIntNative(index);
}
@@ -126,8 +127,8 @@
private native int getIntNative(int index);
@Override
- public String getString(int index) {
- if (mUseNativeAccessor) {
+ public @Nullable String getString(int index) {
+ if (ReactFeatureFlags.useArrayNativeAccessor) {
jniPassCounter++;
return getStringNative(index);
}
@@ -136,8 +137,8 @@
private native String getStringNative(int index);
@Override
- public ReadableNativeArray getArray(int index) {
- if (mUseNativeAccessor) {
+ public @Nullable ReadableNativeArray getArray(int index) {
+ if (ReactFeatureFlags.useArrayNativeAccessor) {
jniPassCounter++;
return getArrayNative(index);
}
@@ -146,8 +147,8 @@
private native ReadableNativeArray getArrayNative(int index);
@Override
- public ReadableNativeMap getMap(int index) {
- if (mUseNativeAccessor) {
+ public @Nullable ReadableNativeMap getMap(int index) {
+ if (ReactFeatureFlags.useArrayNativeAccessor) {
jniPassCounter++;
return getMapNative(index);
}
@@ -156,8 +157,8 @@
private native ReadableNativeMap getMapNative(int index);
@Override
- public ReadableType getType(int index) {
- if (mUseNativeAccessor) {
+ public @Nonnull ReadableType getType(int index) {
+ if (ReactFeatureFlags.useArrayNativeAccessor) {
jniPassCounter++;
return getTypeNative(index);
}
@@ -167,12 +168,12 @@
private native ReadableType getTypeNative(int index);
@Override
- public Dynamic getDynamic(int index) {
+ public @Nonnull Dynamic getDynamic(int index) {
return DynamicFromArray.create(this, index);
}
@Override
- public ArrayList<Object> toArrayList() {
+ public @Nonnull ArrayList<Object> toArrayList() {
ArrayList<Object> arrayList = new ArrayList<>();
for (int i = 0; i < this.size(); i++) {

ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableNativeMap.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,13 +7,14 @@
package com.facebook.react.bridge;
+import com.facebook.infer.annotation.Assertions;
import com.facebook.jni.HybridData;
import com.facebook.proguard.annotations.DoNotStrip;
-
+import com.facebook.react.config.ReactFeatureFlags;
import java.util.HashMap;
import java.util.Iterator;
-import com.facebook.infer.annotation.Assertions;
+import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
@@ -33,10 +34,9 @@
private @Nullable String[] mKeys;
private @Nullable HashMap<String,Object> mLocalMap;
private @Nullable HashMap<String,ReadableType> mLocalTypeMap;
- private static boolean mUseNativeAccessor;
private static int mJniCallCounter;
public static void setUseNativeAccessor(boolean useNativeAccessor) {
- mUseNativeAccessor = useNativeAccessor;
+ ReactFeatureFlags.useMapNativeAccessor = useNativeAccessor;
}
public static int getJNIPassCounter() {
return mJniCallCounter;
@@ -56,8 +56,9 @@
if (mLocalMap == null) {
Object[] values = Assertions.assertNotNull(importValues());
mJniCallCounter++;
- mLocalMap = new HashMap<>();
- for(int i = 0; i< mKeys.length; i++) {
+ int length = mKeys.length;
+ mLocalMap = new HashMap<>(length);
+ for(int i = 0; i< length; i++) {
mLocalMap.put(mKeys[i], values[i]);
}
}
@@ -67,7 +68,7 @@
private native String[] importKeys();
private native Object[] importValues();
- private HashMap<String,ReadableType> getLocalTypeMap() {
+ private @Nonnull HashMap<String,ReadableType> getLocalTypeMap() {
// Fast and non-blocking return for common case
if (mLocalTypeMap != null) {
return mLocalTypeMap;
@@ -82,8 +83,9 @@
if (mLocalTypeMap == null) {
Object[] types = Assertions.assertNotNull(importTypes());
mJniCallCounter++;
- mLocalTypeMap = new HashMap<>();
- for(int i = 0; i< mKeys.length; i++) {
+ int length = mKeys.length;
+ mLocalTypeMap = new HashMap<>(length);
+ for(int i = 0; i< length; i++) {
mLocalTypeMap.put(mKeys[i], (ReadableType) types[i]);
}
}
@@ -93,8 +95,8 @@
private native Object[] importTypes();
@Override
- public boolean hasKey(String name) {
- if (mUseNativeAccessor) {
+ public boolean hasKey(@Nonnull String name) {
+ if (ReactFeatureFlags.useMapNativeAccessor) {
mJniCallCounter++;
return hasKeyNative(name);
}
@@ -103,8 +105,8 @@
private native boolean hasKeyNative(String name);
@Override
- public boolean isNull(String name) {
- if (mUseNativeAccessor) {
+ public boolean isNull(@Nonnull String name) {
+ if (ReactFeatureFlags.useMapNativeAccessor) {
mJniCallCounter++;
return isNullNative(name);
}
@@ -113,9 +115,9 @@
}
throw new NoSuchKeyException(name);
}
- private native boolean isNullNative(String name);
+ private native boolean isNullNative(@Nonnull String name);
- private Object getValue(String name) {
+ private @Nonnull Object getValue(@Nonnull String name) {
if (hasKey(name) && !(isNull(name))) {
return Assertions.assertNotNull(getLocalMap().get(name));
}
@@ -150,8 +152,8 @@
}
@Override
- public boolean getBoolean(String name) {
- if (mUseNativeAccessor) {
+ public boolean getBoolean(@Nonnull String name) {
+ if (ReactFeatureFlags.useMapNativeAccessor) {
mJniCallCounter++;
return getBooleanNative(name);
}
@@ -160,8 +162,8 @@
private native boolean getBooleanNative(String name);
@Override
- public double getDouble(String name) {
- if (mUseNativeAccessor) {
+ public double getDouble(@Nonnull String name) {
+ if (ReactFeatureFlags.useMapNativeAccessor) {
mJniCallCounter++;
return getDoubleNative(name);
}
@@ -170,8 +172,8 @@
private native double getDoubleNative(String name);
@Override
- public int getInt(String name) {
- if (mUseNativeAccessor) {
+ public int getInt(@Nonnull String name) {
+ if (ReactFeatureFlags.useMapNativeAccessor) {
mJniCallCounter++;
return getIntNative(name);
}
@@ -182,8 +184,8 @@
private native int getIntNative(String name);
@Override
- public @Nullable String getString(String name) {
- if (mUseNativeAccessor) {
+ public @Nullable String getString(@Nonnull String name) {
+ if (ReactFeatureFlags.useMapNativeAccessor) {
mJniCallCounter++;
return getStringNative(name);
}
@@ -192,8 +194,8 @@
private native String getStringNative(String name);
@Override
- public @Nullable ReadableArray getArray(String name) {
- if (mUseNativeAccessor) {
+ public @Nullable ReadableArray getArray(@Nonnull String name) {
+ if (ReactFeatureFlags.useMapNativeAccessor) {
mJniCallCounter++;
return getArrayNative(name);
}
@@ -202,8 +204,8 @@
private native ReadableNativeArray getArrayNative(String name);
@Override
- public @Nullable ReadableNativeMap getMap(String name) {
- if (mUseNativeAccessor) {
+ public @Nullable ReadableNativeMap getMap(@Nonnull String name) {
+ if (ReactFeatureFlags.useMapNativeAccessor) {
mJniCallCounter++;
return getMapNative(name);
}
@@ -212,8 +214,8 @@
private native ReadableNativeMap getMapNative(String name);
@Override
- public ReadableType getType(String name) {
- if (mUseNativeAccessor) {
+ public @Nonnull ReadableType getType(@Nonnull String name) {
+ if (ReactFeatureFlags.useMapNativeAccessor) {
mJniCallCounter++;
return getTypeNative(name);
}
@@ -225,18 +227,18 @@
private native ReadableType getTypeNative(String name);
@Override
- public Dynamic getDynamic(String name) {
+ public @Nonnull Dynamic getDynamic(@Nonnull String name) {
return DynamicFromMap.create(this, name);
}
@Override
- public ReadableMapKeySetIterator keySetIterator() {
+ public @Nonnull ReadableMapKeySetIterator keySetIterator() {
return new ReadableNativeMapKeySetIterator(this);
}
@Override
- public HashMap<String, Object> toHashMap() {
- if (mUseNativeAccessor) {
+ public @Nonnull HashMap<String, Object> toHashMap() {
+ if (ReactFeatureFlags.useMapNativeAccessor) {
ReadableMapKeySetIterator iterator = keySetIterator();
HashMap<String, Object> hashMap = new HashMap<>();

ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableType.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/SoftAssertions.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/Systrace.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/UIManager.java

@@ -1,5 +1,13 @@
+/**
+ * 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.bridge;
+import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.common.MeasureSpecProvider;
import com.facebook.react.uimanager.common.SizeMonitoringFrameLayout;
@@ -10,7 +18,12 @@
/**
* Registers a new root view.
*/
- <T extends SizeMonitoringFrameLayout & MeasureSpecProvider> int addRootView(final T rootView);
+ <T extends SizeMonitoringFrameLayout & MeasureSpecProvider> int addRootView(final T rootView, WritableMap initialProps, @Nullable String initialUITemplate);
+
+ /**
+ * Unregisters a new root view.
+ */
+ void removeRootView(int reactRootTag);
/**
* Updates the layout specs of the RootShadowNode based on the Measure specs received by

ReactAndroid/src/main/java/com/facebook/react/bridge/UiThreadUtil.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/UnexpectedNativeTypeException.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/bridge/WritableArray.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,6 +7,9 @@
package com.facebook.react.bridge;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
/**
* Interface for a mutable array. Used to pass arguments from Java to JS.
*/
@@ -16,7 +19,7 @@
void pushBoolean(boolean value);
void pushDouble(double value);
void pushInt(int value);
- void pushString(String value);
- void pushArray(WritableArray array);
- void pushMap(WritableMap map);
+ void pushString(@Nullable String value);
+ void pushArray(@Nullable WritableArray array);
+ void pushMap(@Nullable WritableMap map);
}

ReactAndroid/src/main/java/com/facebook/react/bridge/WritableMap.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,18 +7,21 @@
package com.facebook.react.bridge;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
/**
* Interface for a mutable map. Used to pass arguments from Java to JS.
*/
public interface WritableMap extends ReadableMap {
- void putNull(String key);
- void putBoolean(String key, boolean value);
- void putDouble(String key, double value);
- void putInt(String key, int value);
- void putString(String key, String value);
- void putArray(String key, WritableArray value);
- void putMap(String key, WritableMap value);
+ void putNull(@Nonnull String key);
+ void putBoolean(@Nonnull String key, boolean value);
+ void putDouble(@Nonnull String key, double value);
+ void putInt(@Nonnull String key, int value);
+ void putString(@Nonnull String key, @Nullable String value);
+ void putArray(@Nonnull String key, @Nullable WritableArray value);
+ void putMap(@Nonnull String key, @Nullable WritableMap value);
- void merge(ReadableMap source);
+ void merge(@Nonnull ReadableMap source);
}

ReactAndroid/src/main/java/com/facebook/react/bridge/WritableNativeArray.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,6 +11,9 @@
import com.facebook.jni.HybridData;
import com.facebook.proguard.annotations.DoNotStrip;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
/**
* Implementation of a write-only array stored in native memory. Use
* {@link Arguments#createArray()} if you need to stub out creating this class in a test.
@@ -35,11 +38,11 @@
@Override
public native void pushInt(int value);
@Override
- public native void pushString(String value);
+ public native void pushString(@Nullable String value);
// Note: this consumes the map so do not reuse it.
@Override
- public void pushArray(WritableArray array) {
+ public void pushArray(@Nullable WritableArray array) {
Assertions.assertCondition(
array == null || array instanceof WritableNativeArray, "Illegal type provided");
pushNativeArray((WritableNativeArray) array);
@@ -47,7 +50,7 @@
// Note: this consumes the map so do not reuse it.
@Override
- public void pushMap(WritableMap map) {
+ public void pushMap(@Nullable WritableMap map) {
Assertions.assertCondition(
map == null || map instanceof WritableNativeMap, "Illegal type provided");
pushNativeMap((WritableNativeMap) map);

ReactAndroid/src/main/java/com/facebook/react/bridge/WritableNativeMap.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,10 +7,15 @@
package com.facebook.react.bridge;
+import android.support.annotation.NonNull;
+
import com.facebook.jni.HybridData;
import com.facebook.infer.annotation.Assertions;
import com.facebook.proguard.annotations.DoNotStrip;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
/**
* Implementation of a write-only map stored in native memory. Use
* {@link Arguments#createMap()} if you need to stub out creating this class in a test.
@@ -23,19 +28,19 @@
}
@Override
- public native void putBoolean(String key, boolean value);
+ public native void putBoolean(@Nonnull String key, boolean value);
@Override
- public native void putDouble(String key, double value);
+ public native void putDouble(@Nonnull String key, double value);
@Override
- public native void putInt(String key, int value);
+ public native void putInt(@Nonnull String key, int value);
@Override
- public native void putString(String key, String value);
+ public native void putString(@Nonnull String key, @Nullable String value);
@Override
- public native void putNull(String key);
+ public native void putNull(@NonNull String key);
// Note: this consumes the map so do not reuse it.
@Override
- public void putMap(String key, WritableMap value) {
+ public void putMap(@Nonnull String key, @Nullable WritableMap value) {
Assertions.assertCondition(
value == null || value instanceof WritableNativeMap, "Illegal type provided");
putNativeMap(key, (WritableNativeMap) value);
@@ -43,7 +48,7 @@
// Note: this consumes the map so do not reuse it.
@Override
- public void putArray(String key, WritableArray value) {
+ public void putArray(@Nonnull String key, @Nullable WritableArray value) {
Assertions.assertCondition(
value == null || value instanceof WritableNativeArray, "Illegal type provided");
putNativeArray(key, (WritableNativeArray) value);
@@ -51,7 +56,7 @@
// Note: this **DOES NOT** consume the source map
@Override
- public void merge(ReadableMap source) {
+ public void merge(@Nonnull ReadableMap source) {
Assertions.assertCondition(source instanceof ReadableNativeMap, "Illegal type provided");
mergeNativeMap((ReadableNativeMap) source);
}

ReactAndroid/src/main/java/com/facebook/react/BUCK

@@ -4,6 +4,7 @@
name = "react",
srcs = glob(["*.java"]),
provided_deps = [
+ react_native_dep("third-party/android/support/v7/appcompat-orig:appcompat"),
react_native_dep("third-party/android/support/v4:lib-support-v4"),
],
visibility = [
@@ -21,6 +22,7 @@
react_native_target("java/com/facebook/react/common:common"),
react_native_target("java/com/facebook/react/devsupport:devsupport"),
react_native_target("java/com/facebook/react/devsupport:interfaces"),
+ react_native_target("java/com/facebook/react/jscexecutor:jscexecutor"),
react_native_target("java/com/facebook/react/jstasks:jstasks"),
react_native_target("java/com/facebook/react/module/annotations:annotations"),
react_native_target("java/com/facebook/react/module/model:model"),
@@ -33,7 +35,9 @@
react_native_target("java/com/facebook/react/modules/systeminfo:systeminfo"),
react_native_target("java/com/facebook/react/modules/toast:toast"),
react_native_target("java/com/facebook/react/uimanager:uimanager"),
+ react_native_target("java/com/facebook/react/module/annotations:annotations"),
react_native_target("java/com/facebook/react/views/imagehelper:imagehelper"),
+ react_native_target("java/com/facebook/react/config:config"),
],
exported_deps = [
react_native_target("java/com/facebook/react/packagerconnection:packagerconnection"),

ReactAndroid/src/main/java/com/facebook/react/common/annotations/VisibleForTesting.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/common/ArrayUtils.java

@@ -1,3 +1,10 @@
+/**
+ * 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.common;
import java.util.Arrays;

ReactAndroid/src/main/java/com/facebook/react/common/build/ReactBuildConfig.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/common/ClearableSynchronizedPool.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/common/DebugServerException.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/common/JavascriptException.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/common/LifecycleState.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/common/LongArray.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/common/MapBuilder.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/common/network/OkHttpCallUtil.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/common/ReactConstants.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/common/ShakeDetector.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/common/SingleThreadAsserter.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/common/StandardCharsets.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2017-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/common/SystemClock.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/CompositeReactPackage.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc. and its affiliates.
*
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
* directory of this source tree.
@@ -28,7 +28,7 @@
private final List<ReactPackage> mChildReactPackages = new ArrayList<>();
/**
- * The order in which packages are passed matters. It may happen that a NativeModule or or a
+ * The order in which packages are passed matters. It may happen that a NativeModule or a
* ViewManager exists in two or more ReactPackages. In that case the latter will win i.e. the
* latter will overwrite the former. This re-occurrence is detected by comparing a name of a
* module.

ReactAndroid/src/main/java/com/facebook/react/config/BUCK

@@ -0,0 +1,11 @@
+load("//tools/build_defs/oss:rn_defs.bzl", "rn_android_library")
+
+rn_android_library(
+ name = "config",
+ srcs = glob(["**/*.java"]),
+ visibility = [
+ "PUBLIC",
+ ],
+ deps = [
+ ],
+)

ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java

@@ -0,0 +1,40 @@
+/**
+ * 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.config;
+
+/**
+ * Hi there, traveller! This configuration class is not meant to be used by end-users of RN. It
+ * contains mainly flags for features that are either under active development and not ready for
+ * public consumption, or for use in experiments.
+ *
+ * These values are safe defaults and should not require manual changes.
+ */
+public class ReactFeatureFlags {
+
+ /**
+ * Whether we should load a specific view manager immediately or when it is accessed by JS
+ */
+ public static boolean lazilyLoadViewManagers = false;
+
+ /**
+ * Reduce the number of Java-JS interops while accessing native arrays
+ */
+ public static boolean useArrayNativeAccessor = false;
+
+ /**
+ * Reduce the number of Java-JS interops while accessing native maps
+ */
+ public static boolean useMapNativeAccessor = false;
+
+ /**
+ * Should this application use TurboModules. If yes, then any module that inherits
+ * {@link com.facebook.react.turbomodule.core.interfaces.TurboModule} will NOT be passed in to
+ * C++ CatalystInstanceImpl
+ */
+ public static boolean useTurboModules = false;
+}

ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java

@@ -1,10 +1,9 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
+ * <p>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;
import static com.facebook.react.bridge.ReactMarkerConstants.CREATE_UI_MANAGER_MODULE_END;
@@ -12,17 +11,18 @@
import static com.facebook.react.bridge.ReactMarkerConstants.PROCESS_CORE_REACT_PACKAGE_END;
import static com.facebook.react.bridge.ReactMarkerConstants.PROCESS_CORE_REACT_PACKAGE_START;
-import com.facebook.react.bridge.ModuleSpec;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactMarker;
+import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.module.annotations.ReactModuleList;
+import com.facebook.react.module.model.ReactModuleInfo;
import com.facebook.react.module.model.ReactModuleInfoProvider;
-import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.facebook.react.modules.core.ExceptionsManagerModule;
-import com.facebook.react.modules.core.HeadlessJsTaskSupportModule;
import com.facebook.react.modules.core.Timing;
+import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
+import com.facebook.react.modules.core.HeadlessJsTaskSupportModule;
import com.facebook.react.modules.debug.SourceCodeModule;
import com.facebook.react.modules.deviceinfo.DeviceInfoModule;
import com.facebook.react.modules.systeminfo.AndroidInfoModule;
@@ -30,15 +30,21 @@
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.ViewManager;
import com.facebook.systrace.Systrace;
-import java.util.Arrays;
-import java.util.List;
+
+import java.util.Collections;
import javax.annotation.Nullable;
-import javax.inject.Provider;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static com.facebook.react.bridge.ReactMarkerConstants.*;
/**
* This is the basic module to support React Native. The debug modules are now in DebugCorePackage.
*/
@ReactModuleList(
+ // WARNING: If you modify this list, ensure that the list below in method
+ // getReactModuleInfoByInitialization is also updated
nativeModules = {
AndroidInfoModule.class,
DeviceEventManagerModule.class,
@@ -48,9 +54,8 @@
SourceCodeModule.class,
Timing.class,
UIManagerModule.class,
- }
-)
-/* package */ class CoreModulesPackage extends LazyReactPackage implements ReactPackageLogger {
+ })
+/* package */ class CoreModulesPackage extends TurboReactPackage implements ReactPackageLogger {
private final ReactInstanceManager mReactInstanceManager;
private final DefaultHardwareBackBtnHandler mHardwareBackBtnHandler;
@@ -69,79 +74,86 @@
mMinTimeLeftInFrameForNonBatchedOperationMs = minTimeLeftInFrameForNonBatchedOperationMs;
}
+ /**
+ * This method is overridden, since OSS does not run the annotation processor to generate {@link
+ * CoreModulesPackage$$ReactModuleInfoProvider} class. Here we check if it exists. If it does not
+ * exist, we generate one manually in {@link
+ * CoreModulesPackage#getReactModuleInfoByInitialization()} and return that instead.
+ */
@Override
- public List<ModuleSpec> getNativeModules(final ReactApplicationContext reactContext) {
- return Arrays.asList(
- ModuleSpec.nativeModuleSpec(
+ public ReactModuleInfoProvider getReactModuleInfoProvider() {
+ try {
+ Class<?> reactModuleInfoProviderClass =
+ Class.forName("com.facebook.react.CoreModulesPackage$$ReactModuleInfoProvider");
+ return (ReactModuleInfoProvider) reactModuleInfoProviderClass.newInstance();
+ } catch (ClassNotFoundException e) {
+ // In OSS case, the annotation processor does not run. We fall back on creating this byhand
+ Class<? extends NativeModule>[] moduleList =
+ new Class[] {
AndroidInfoModule.class,
- new Provider<NativeModule>() {
- @Override
- public NativeModule get() {
- return new AndroidInfoModule(reactContext);
- }
- }),
- ModuleSpec.nativeModuleSpec(
DeviceEventManagerModule.class,
- new Provider<NativeModule>() {
- @Override
- public NativeModule get() {
- return new DeviceEventManagerModule(reactContext, mHardwareBackBtnHandler);
- }
- }),
- ModuleSpec.nativeModuleSpec(
+ DeviceInfoModule.class,
ExceptionsManagerModule.class,
- new Provider<NativeModule>() {
- @Override
- public NativeModule get() {
- return new ExceptionsManagerModule(mReactInstanceManager.getDevSupportManager());
- }
- }),
- ModuleSpec.nativeModuleSpec(
HeadlessJsTaskSupportModule.class,
- new Provider<NativeModule>() {
- @Override
- public NativeModule get() {
- return new HeadlessJsTaskSupportModule(reactContext);
- }
- }),
- ModuleSpec.nativeModuleSpec(
SourceCodeModule.class,
- new Provider<NativeModule>() {
- @Override
- public NativeModule get() {
- return new SourceCodeModule(reactContext);
- }
- }),
- ModuleSpec.nativeModuleSpec(
Timing.class,
- new Provider<NativeModule>() {
- @Override
- public NativeModule get() {
- return new Timing(reactContext, mReactInstanceManager.getDevSupportManager());
+ UIManagerModule.class
+ };
+
+ final Map<String, ReactModuleInfo> reactModuleInfoMap = new HashMap<>();
+ for (Class<? extends NativeModule> moduleClass : moduleList) {
+ ReactModule reactModule = moduleClass.getAnnotation(ReactModule.class);
+
+ reactModuleInfoMap.put(
+ reactModule.name(),
+ new ReactModuleInfo(
+ reactModule.name(),
+ moduleClass.getName(),
+ reactModule.canOverrideExistingModule(),
+ reactModule.needsEagerInit(),
+ reactModule.hasConstants(),
+ reactModule.isCxxModule(),
+ false));
}
- }),
- ModuleSpec.nativeModuleSpec(
- UIManagerModule.class,
- new Provider<NativeModule>() {
+
+ return new ReactModuleInfoProvider() {
@Override
- public NativeModule get() {
- return createUIManager(reactContext);
+ public Map<String, ReactModuleInfo> getReactModuleInfos() {
+ return reactModuleInfoMap;
}
- }),
- ModuleSpec.nativeModuleSpec(
- DeviceInfoModule.class,
- new Provider<NativeModule>() {
- @Override
- public NativeModule get() {
- return new DeviceInfoModule(reactContext);
+ };
+ } catch (InstantiationException e) {
+ throw new RuntimeException(
+ "No ReactModuleInfoProvider for CoreModulesPackage$$ReactModuleInfoProvider", e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(
+ "No ReactModuleInfoProvider for CoreModulesPackage$$ReactModuleInfoProvider", e);
}
- }));
}
@Override
- public ReactModuleInfoProvider getReactModuleInfoProvider() {
- // This has to be done via reflection or we break open source.
- return LazyReactPackage.getReactModuleInfoProviderViaReflection(this);
+ public NativeModule getModule(String name, ReactApplicationContext reactContext) {
+ switch (name) {
+ case AndroidInfoModule.NAME:
+ return new AndroidInfoModule(reactContext);
+ case DeviceEventManagerModule.NAME:
+ return new DeviceEventManagerModule(reactContext, mHardwareBackBtnHandler);
+ case ExceptionsManagerModule.NAME:
+ return new ExceptionsManagerModule(mReactInstanceManager.getDevSupportManager());
+ case HeadlessJsTaskSupportModule.NAME:
+ return new HeadlessJsTaskSupportModule(reactContext);
+ case SourceCodeModule.NAME:
+ return new SourceCodeModule(reactContext);
+ case Timing.NAME:
+ return new Timing(reactContext, mReactInstanceManager.getDevSupportManager());
+ case UIManagerModule.NAME:
+ return createUIManager(reactContext);
+ case DeviceInfoModule.NAME:
+ return new DeviceInfoModule(reactContext);
+ default:
+ throw new IllegalArgumentException(
+ "In CoreModulesPackage, could not find Native module for " + name);
+ }
}
private UIManagerModule createUIManager(final ReactApplicationContext reactContext) {
@@ -149,7 +161,8 @@
Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "createUIManagerModule");
try {
if (mLazyViewManagersEnabled) {
- UIManagerModule.ViewManagerResolver resolver = new UIManagerModule.ViewManagerResolver() {
+ UIManagerModule.ViewManagerResolver resolver =
+ new UIManagerModule.ViewManagerResolver() {
@Override
public @Nullable ViewManager getViewManager(String viewManagerName) {
return mReactInstanceManager.createViewManager(viewManagerName);
@@ -161,9 +175,7 @@
};
return new UIManagerModule(
- reactContext,
- resolver,
- mMinTimeLeftInFrameForNonBatchedOperationMs);
+ reactContext, resolver, mMinTimeLeftInFrameForNonBatchedOperationMs);
} else {
return new UIManagerModule(
reactContext,

ReactAndroid/src/main/java/com/facebook/react/DebugCorePackage.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/devsupport/BUCK

@@ -12,7 +12,6 @@
],
deps = [
react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"),
- react_native_dep("third-party/android/support-annotations:android-support-annotations"),
react_native_dep("third-party/java/infer-annotations:infer-annotations"),
react_native_dep("third-party/java/jsr-305:jsr-305"),
react_native_dep("third-party/java/okhttp:okhttp3"),

ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDeltaClient.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2018-present, Facebook, Inc.
+ * 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.
@@ -25,7 +25,7 @@
public abstract class BundleDeltaClient {
private static final String METRO_DELTA_ID_HEADER = "X-Metro-Delta-ID";
- @Nullable private String mDeltaId;
+ @Nullable private String mRevisionId;
public enum ClientType {
NONE,
@@ -54,39 +54,39 @@
BufferedSource body,
File outputFile) throws IOException;
- final public String extendUrlForDelta(String bundleURL) {
- return mDeltaId != null ? bundleURL + "&deltaBundleId=" + mDeltaId : bundleURL;
+ final public synchronized String extendUrlForDelta(String bundleURL) {
+ return mRevisionId != null ? bundleURL + "&revisionId=" + mRevisionId : bundleURL;
}
- public void reset() {
- mDeltaId = null;
+ public synchronized void reset() {
+ mRevisionId = null;
}
- public Pair<Boolean, NativeDeltaClient> processDelta(
+ public synchronized Pair<Boolean, NativeDeltaClient> processDelta(
Headers headers,
BufferedSource body,
File outputFile) throws IOException {
- mDeltaId = headers.get(METRO_DELTA_ID_HEADER);
+ mRevisionId = headers.get(METRO_DELTA_ID_HEADER);
return processDelta(body, outputFile);
}
private static class BundleDeltaJavaClient extends BundleDeltaClient {
- final LinkedHashMap<Number, byte[]> mPreModules = new LinkedHashMap<Number, byte[]>();
- final LinkedHashMap<Number, byte[]> mDeltaModules = new LinkedHashMap<Number, byte[]>();
- final LinkedHashMap<Number, byte[]> mPostModules = new LinkedHashMap<Number, byte[]>();
+ byte[] mPreCode;
+ byte[] mPostCode;
+ final LinkedHashMap<Number, byte[]> mModules = new LinkedHashMap<Number, byte[]>();
@Override
public boolean canHandle(ClientType type) {
return type == ClientType.DEV_SUPPORT;
}
- public void reset() {
+ public synchronized void reset() {
super.reset();
- mDeltaModules.clear();
- mPreModules.clear();
- mPostModules.clear();
+ mPreCode = null;
+ mPostCode = null;
+ mModules.clear();
}
@Override
@@ -101,11 +100,17 @@
while (jsonReader.hasNext()) {
String name = jsonReader.nextName();
if (name.equals("pre")) {
- numChangedModules += patchDelta(jsonReader, mPreModules);
+ mPreCode = jsonReader.nextString().getBytes();
} else if (name.equals("post")) {
- numChangedModules += patchDelta(jsonReader, mPostModules);
- } else if (name.equals("delta")) {
- numChangedModules += patchDelta(jsonReader, mDeltaModules);
+ mPostCode = jsonReader.nextString().getBytes();
+ } else if (name.equals("modules")) {
+ numChangedModules += setModules(jsonReader, mModules);
+ } else if (name.equals("added")) {
+ numChangedModules += setModules(jsonReader, mModules);
+ } else if (name.equals("modified")) {
+ numChangedModules += setModules(jsonReader, mModules);
+ } else if (name.equals("deleted")) {
+ numChangedModules += removeModules(jsonReader, mModules);
} else {
jsonReader.skipValue();
}
@@ -123,20 +128,16 @@
FileOutputStream fileOutputStream = new FileOutputStream(outputFile);
try {
- for (byte[] code : mPreModules.values()) {
- fileOutputStream.write(code);
+ fileOutputStream.write(mPreCode);
fileOutputStream.write('\n');
- }
- for (byte[] code : mDeltaModules.values()) {
+ for (byte[] code : mModules.values()) {
fileOutputStream.write(code);
fileOutputStream.write('\n');
}
- for (byte[] code : mPostModules.values()) {
- fileOutputStream.write(code);
+ fileOutputStream.write(mPostCode);
fileOutputStream.write('\n');
- }
} finally {
fileOutputStream.flush();
fileOutputStream.close();
@@ -145,7 +146,7 @@
return Pair.create(Boolean.TRUE, null);
}
- private static int patchDelta(JsonReader jsonReader, LinkedHashMap<Number, byte[]> map)
+ private static int setModules(JsonReader jsonReader, LinkedHashMap<Number, byte[]> map)
throws IOException {
jsonReader.beginArray();
@@ -155,14 +156,27 @@
int moduleId = jsonReader.nextInt();
- if (jsonReader.peek() == JsonToken.NULL) {
- jsonReader.skipValue();
- map.remove(moduleId);
- } else {
map.put(moduleId, jsonReader.nextString().getBytes());
+
+ jsonReader.endArray();
+ numModules++;
}
jsonReader.endArray();
+
+ return numModules;
+ }
+
+ private static int removeModules(JsonReader jsonReader, LinkedHashMap<Number, byte[]> map)
+ throws IOException {
+ jsonReader.beginArray();
+
+ int numModules = 0;
+ while (jsonReader.hasNext()) {
+ int moduleId = jsonReader.nextInt();
+
+ map.remove(moduleId);
+
numModules++;
}

ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDownloader.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/devsupport/DebugOverlayController.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/devsupport/DevInternalSettings.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/devsupport/DevLoadingViewController.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,11 +10,9 @@
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
-import android.os.Build;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.widget.PopupWindow;
@@ -31,7 +29,6 @@
/**
* Controller to display loading messages on top of the screen. All methods are thread safe.
*/
-@TargetApi(Build.VERSION_CODES.CUPCAKE)
public class DevLoadingViewController {
private static boolean sEnabled = true;
private final ReactInstanceManagerDevHelper mReactInstanceManagerHelper;

ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,6 +10,7 @@
import android.content.Context;
import android.os.AsyncTask;
import android.os.Handler;
+import android.os.Looper;
import android.widget.Toast;
import com.facebook.common.logging.FLog;
import com.facebook.infer.annotation.Assertions;
@@ -137,7 +138,7 @@
.build();
mBundleDownloader = new BundleDownloader(mClient);
- mRestartOnChangePollingHandler = new Handler();
+ mRestartOnChangePollingHandler = new Handler(Looper.getMainLooper());
mPackageName = packageName;
}

ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSettingsActivity.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -23,6 +23,6 @@
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTitle(getApplication().getResources().getString(R.string.catalyst_settings_title));
- addPreferencesFromResource(R.xml.preferences);
+ addPreferencesFromResource(R.xml.rn_dev_preferences);
}
}

ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerFactory.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,7 +7,6 @@
package com.facebook.react.devsupport;
-import android.annotation.TargetApi;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog;
@@ -95,7 +94,6 @@
* {@code <activity android:name="com.facebook.react.devsupport.DevSettingsActivity"/>}
* {@code <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>}
*/
-@TargetApi(11)
public class DevSupportManagerImpl implements
DevSupportManager,
PackagerCommandListener,

ReactAndroid/src/main/java/com/facebook/react/devsupport/DisabledDevSupportManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/devsupport/DoubleTapReloadRecognizer.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/devsupport/FpsView.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,7 +9,6 @@
import java.util.Locale;
-import android.annotation.TargetApi;
import android.widget.FrameLayout;
import android.widget.TextView;
@@ -26,7 +25,6 @@
*
* NB: Requires API 16 for use of FpsDebugFrameCallback.
*/
-@TargetApi(16)
public class FpsView extends FrameLayout {
private static final int UPDATE_INTERVAL_MS = 500;
@@ -39,7 +37,7 @@
super(reactContext);
inflate(reactContext, R.layout.fps_view, this);
mTextView = (TextView) findViewById(R.id.fps_text);
- mFrameCallback = new FpsDebugFrameCallback(ChoreographerCompat.getInstance(), reactContext);
+ mFrameCallback = new FpsDebugFrameCallback(reactContext);
mFPSMonitorRunnable = new FPSMonitorRunnable();
setCurrentFPS(0, 0, 0, 0);
}

ReactAndroid/src/main/java/com/facebook/react/devsupport/HMRClient.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/devsupport/InspectorPackagerConnection.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/devsupport/interfaces/DevBundleDownloadListener.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/devsupport/interfaces/DevOptionHandler.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/devsupport/interfaces/DevSupportManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/devsupport/interfaces/ErrorCustomizer.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/devsupport/interfaces/PackagerStatusCallback.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/devsupport/interfaces/StackFrame.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/devsupport/JSCHeapCapture.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/devsupport/JSCSamplingProfiler.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/devsupport/JSDebuggerWebSocketClient.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/devsupport/JSDevSupport.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -20,7 +20,7 @@
@ReactModule(name = JSDevSupport.MODULE_NAME)
public class JSDevSupport extends ReactContextBaseJavaModule {
- static final String MODULE_NAME = "JSDevSupport";
+ public static final String MODULE_NAME = "JSDevSupport";
public static final int ERROR_CODE_EXCEPTION = 0;
public static final int ERROR_CODE_VIEW_NOT_FOUND = 1;

ReactAndroid/src/main/java/com/facebook/react/devsupport/JSException.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/devsupport/MultipartStreamReader.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/devsupport/ReactInstanceManagerDevHelper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/devsupport/RedBoxDialog.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/devsupport/RedBoxHandler.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/devsupport/StackTraceHelper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/devsupport/ViewHierarchyUtil.java

@@ -1,3 +1,10 @@
+/**
+ * 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.devsupport;
import android.util.Pair;

ReactAndroid/src/main/java/com/facebook/react/devsupport/WebsocketJavaScriptExecutor.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/devsupport/WindowOverlayCompat.java

@@ -1,3 +1,10 @@
+/**
+ * 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.devsupport;
import android.os.Build;

ReactAndroid/src/main/java/com/facebook/react/EagerModuleProvider.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/fabric/BUCK

@@ -4,7 +4,8 @@
name = "fabric",
srcs = glob([
"*.java",
- "events/*.java",
+ "jsi/*.java",
+ "mounting/**/*.java",
]),
provided_deps = [
react_native_dep("third-party/android/support/v4:lib-support-v4"),
@@ -15,18 +16,23 @@
],
deps = [
YOGA_TARGET,
+ react_native_dep("third-party/java/infer-annotations:infer-annotations"),
react_native_dep("java/com/facebook/systrace:systrace"),
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:react"),
+ react_native_dep("libraries/soloader/java/com/facebook/soloader:soloader"),
react_native_target("java/com/facebook/debug/tags:tags"),
react_native_target("java/com/facebook/debug/holder:holder"),
react_native_target("java/com/facebook/react/bridge:bridge"),
- react_native_target("java/com/facebook/react/uimanager:uimanager"),
- react_native_target("java/com/facebook/react/uimanager/annotations:annotations"),
+ react_native_target("java/com/facebook/react/fabric/jsi/jni:jni"),
+ react_native_target("java/com/facebook/react:react"),
react_native_target("java/com/facebook/react/module/annotations:annotations"),
- react_native_target("java/com/facebook/react/common:common"),
+ react_native_target("java/com/facebook/react/modules/core:core"),
react_native_target("java/com/facebook/react/modules/i18nmanager:i18nmanager"),
+ react_native_target("java/com/facebook/react/common:common"),
+ react_native_target("java/com/facebook/react/uimanager:uimanager"),
+ react_native_target("java/com/facebook/react/views/view:view"),
+ react_native_target("java/com/facebook/react/touch:touch"),
+ ],
+ exported_deps = [
],
)

ReactAndroid/src/main/java/com/facebook/react/fabric/events/FabricEventEmitter.java

@@ -1,183 +0,0 @@
-/**
- * Copyright (c) 2014-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-package com.facebook.react.fabric.events;
-
-import static com.facebook.react.uimanager.events.TouchesHelper.CHANGED_TOUCHES_KEY;
-import static com.facebook.react.uimanager.events.TouchesHelper.TARGET_KEY;
-import static com.facebook.react.uimanager.events.TouchesHelper.TOP_TOUCH_CANCEL_KEY;
-import static com.facebook.react.uimanager.events.TouchesHelper.TOP_TOUCH_END_KEY;
-import static com.facebook.react.uimanager.events.TouchesHelper.TOUCHES_KEY;
-
-import android.annotation.TargetApi;
-import android.os.Build;
-import android.util.Pair;
-import com.facebook.common.logging.FLog;
-import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.ReadableMap;
-import com.facebook.react.bridge.WritableArray;
-import com.facebook.react.bridge.WritableMap;
-import com.facebook.react.bridge.WritableNativeArray;
-import com.facebook.react.bridge.WritableNativeMap;
-import com.facebook.react.fabric.FabricUIManager;
-import com.facebook.react.fabric.Scheduler;
-import com.facebook.react.fabric.Work;
-import com.facebook.react.uimanager.IllegalViewOperationException;
-import com.facebook.react.uimanager.events.RCTEventEmitter;
-import java.io.Closeable;
-import java.util.HashSet;
-import java.util.Set;
-import javax.annotation.Nullable;
-
-@TargetApi(Build.VERSION_CODES.ECLAIR)
-public class FabricEventEmitter implements RCTEventEmitter, Closeable {
-
- private static final String TAG = FabricEventEmitter.class.getSimpleName();
-
- private final FabricUIManager mFabricUIManager;
- private final Scheduler mScheduler;
-
- public FabricEventEmitter(ReactApplicationContext context, FabricUIManager fabricUIManager) {
- mScheduler = new Scheduler(context);
- mFabricUIManager = fabricUIManager;
- }
-
- @Override
- public void receiveEvent(int reactTag, String eventName, @Nullable WritableMap params) {
- try {
- long eventTarget = mFabricUIManager.getEventTarget(reactTag);
- mScheduler.scheduleWork(new FabricUIManagerWork(eventTarget, eventName, params));
- } catch (IllegalViewOperationException e) {
- FLog.e(TAG, "Unable to emmit event for tag " + reactTag, e);
- }
- }
-
- @Override
- public void close() {
- mScheduler.shutdown();
- }
-
- private class FabricUIManagerWork implements Work {
- private final long mEventTarget;
- private final String mEventName;
- private final WritableMap mParams;
-
- public FabricUIManagerWork(long eventTarget, String eventName, @Nullable WritableMap params) {
- mEventTarget = eventTarget;
- mEventName = eventName;
- mParams = params;
- }
-
- @Override
- public void run() {
- try {
- mFabricUIManager.invoke(mEventTarget, mEventName, mParams);
- } catch (Throwable t) {
- FLog.e(TAG, "Error sending event " + mEventName, t);
- //TODO: manage exception properly
- } finally{
- // TODO(dvacca): We need to only release this after all shadow nodes
- // have been released. The easiest way would be to adopt the event
- // emitter approach from the C++ Fabric. For now, we'll just leak.
- // mFabricUIManager.releaseEventTarget(mEventTarget);
- }
- }
- }
-
- @Override
- public void receiveTouches(String eventTopLevelType, WritableArray touches,
- WritableArray changedIndices) {
- Pair<WritableArray, WritableArray> result =
- TOP_TOUCH_END_KEY.equalsIgnoreCase(eventTopLevelType) ||
- TOP_TOUCH_CANCEL_KEY.equalsIgnoreCase(eventTopLevelType)
- ? removeTouchesAtIndices(touches, changedIndices)
- : touchSubsequence(touches, changedIndices);
-
- WritableArray changedTouches = result.first;
- touches = result.second;
-
- for (int jj = 0; jj < changedTouches.size(); jj++) {
- WritableMap touch = getWritableMap(changedTouches.getMap(jj));
- // Touch objects can fulfill the role of `DOM` `Event` objects if we set
- // the `changedTouches`/`touches`. This saves allocations.
- touch.putArray(CHANGED_TOUCHES_KEY, changedTouches);
- touch.putArray(TOUCHES_KEY, touches);
- WritableMap nativeEvent = touch;
- int rootNodeID = 0;
- int target = nativeEvent.getInt(TARGET_KEY);
- if (target < 1) {
- FLog.e(TAG,"A view is reporting that a touch occurred on tag zero.");
- } else {
- rootNodeID = target;
- }
- receiveEvent(rootNodeID, eventTopLevelType, touch);
- }
- }
-
- /**
- * Destroys `touches` by removing touch objects at indices `indices`. This is
- * to maintain compatibility with W3C touch "end" events, where the active
- * touches don't include the set that has just been "ended".
- *
- * This method was originally in ReactNativeRenderer.js
- *
- * TODO: this method is a copy from ReactNativeRenderer.removeTouchesAtIndices and it needs
- * to be rewritten in a more efficient way,
- *
- * @param touches {@link WritableArray} Deserialized touch objects.
- * @param indices {WritableArray} Indices to remove from `touches`.
- * @return {Array<Touch>} Subsequence of removed touch objects.
- */
- private Pair<WritableArray, WritableArray> removeTouchesAtIndices(WritableArray touches, WritableArray indices) {
- WritableArray rippedOut = new WritableNativeArray();
- // use an unsafe downcast to alias to nullable elements,
- // so we can delete and then compact.
- WritableArray tempTouches = new WritableNativeArray();
- Set<Integer> rippedOutIndices = new HashSet<>();
- for (int i = 0; i < indices.size(); i++) {
- int index = indices.getInt(i);
- rippedOut.pushMap(getWritableMap(touches.getMap(index)));
- rippedOutIndices.add(index);
- }
- for (int j = 0 ; j < touches.size() ; j++) {
- if (!rippedOutIndices.contains(j)) {
- tempTouches.pushMap(getWritableMap(touches.getMap(j)));
- }
- }
-
- return new Pair<>(rippedOut, tempTouches);
- }
-
- /**
- * Selects a subsequence of `Touch`es, without destroying `touches`.
- *
- * This method was originally in ReactNativeRenderer.js
- *
- * @param touches {@link WritableArray} Deserialized touch objects.
- * @param changedIndices {@link WritableArray} Indices by which to pull subsequence.
- * @return {Array<Touch>} Subsequence of touch objects.
- */
- private Pair<WritableArray, WritableArray> touchSubsequence(WritableArray touches, WritableArray changedIndices) {
- WritableArray result = new WritableNativeArray();
- for (int i = 0; i < changedIndices.size(); i++) {
- result.pushMap(getWritableMap(touches.getMap(i)));
- }
- return new Pair<>(result, touches);
- }
-
- /**
- * TODO: this is required because the WritableNativeArray.getMap() returns a ReadableMap instead
- * of the original writableMap. this will change in the near future.
- *
- * @param readableMap {@link ReadableMap} source map
- */
- private WritableMap getWritableMap(ReadableMap readableMap) {
- WritableNativeMap map = new WritableNativeMap();
- map.merge(readableMap);
- return map;
- }
-}

ReactAndroid/src/main/java/com/facebook/react/fabric/FabricBinding.java

@@ -1,36 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-package com.facebook.react.fabric;
-
-import com.facebook.react.bridge.JavaScriptContextHolder;
-import com.facebook.react.bridge.NativeMap;
-
-public interface FabricBinding {
-
- void installFabric(JavaScriptContextHolder jsContext, FabricUIManager fabricModule);
-
- void releaseEventTarget(long jsContextNativePointer, long eventTargetPointer);
-
- void releaseEventHandler(long jsContextNativePointer, long eventHandlerPointer);
-
- void dispatchEventToEmptyTarget(
- long jsContextNativePointer,
- long eventHandlerPointer,
- String type,
- NativeMap payload
- );
-
- void dispatchEventToTarget(
- long jsContextNativePointer,
- long eventHandlerPointer,
- long eventTargetPointer,
- String type,
- NativeMap payload
- );
-
-}

ReactAndroid/src/main/java/com/facebook/react/fabric/FabricEventEmitter.java

@@ -0,0 +1,152 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * <p>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.fabric;
+
+import static com.facebook.react.uimanager.events.TouchesHelper.CHANGED_TOUCHES_KEY;
+import static com.facebook.react.uimanager.events.TouchesHelper.TARGET_KEY;
+import static com.facebook.react.uimanager.events.TouchesHelper.TOP_TOUCH_CANCEL_KEY;
+import static com.facebook.react.uimanager.events.TouchesHelper.TOP_TOUCH_END_KEY;
+import static com.facebook.react.uimanager.events.TouchesHelper.TOUCHES_KEY;
+
+import android.util.Pair;
+import com.facebook.common.logging.FLog;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.WritableArray;
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.bridge.WritableNativeArray;
+import com.facebook.react.bridge.WritableNativeMap;
+import com.facebook.react.uimanager.events.RCTEventEmitter;
+import com.facebook.systrace.Systrace;
+import java.util.HashSet;
+import java.util.Set;
+import javax.annotation.Nullable;
+
+public class FabricEventEmitter implements RCTEventEmitter {
+
+ private static final String TAG = FabricEventEmitter.class.getSimpleName();
+
+ private final FabricUIManager mUIManager;
+
+ public FabricEventEmitter(FabricUIManager uiManager) {
+ mUIManager = uiManager;
+ }
+
+ @Override
+ public void receiveEvent(int reactTag, String eventName, @Nullable WritableMap params) {
+ Systrace.beginSection(
+ Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
+ "FabricEventEmitter.receiveEvent('" + eventName + "')");
+ mUIManager.receiveEvent(reactTag, eventName, params);
+ Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+ }
+
+ @Override
+ public void receiveTouches(
+ String eventTopLevelType, WritableArray touches, WritableArray changedIndices) {
+ Pair<WritableArray, WritableArray> result =
+ TOP_TOUCH_END_KEY.equalsIgnoreCase(eventTopLevelType)
+ || TOP_TOUCH_CANCEL_KEY.equalsIgnoreCase(eventTopLevelType)
+ ? removeTouchesAtIndices(touches, changedIndices)
+ : touchSubsequence(touches, changedIndices);
+
+ WritableArray changedTouches = result.first;
+ touches = result.second;
+
+ for (int jj = 0; jj < changedTouches.size(); jj++) {
+ WritableMap touch = getWritableMap(changedTouches.getMap(jj));
+ // Touch objects can fulfill the role of `DOM` `Event` objects if we set
+ // the `changedTouches`/`touches`. This saves allocations.
+
+ touch.putArray(CHANGED_TOUCHES_KEY, copyWritableArray(changedTouches));
+ touch.putArray(TOUCHES_KEY, copyWritableArray(touches));
+ WritableMap nativeEvent = touch;
+ int rootNodeID = 0;
+ int target = nativeEvent.getInt(TARGET_KEY);
+ if (target < 1) {
+ FLog.e(TAG, "A view is reporting that a touch occurred on tag zero.");
+ } else {
+ rootNodeID = target;
+ }
+
+ receiveEvent(rootNodeID, eventTopLevelType, touch);
+ }
+ }
+
+ /** TODO T31905686 optimize this to avoid copying arrays */
+ private WritableArray copyWritableArray(WritableArray array) {
+ WritableNativeArray ret = new WritableNativeArray();
+ for (int i = 0; i < array.size(); i++) {
+ ret.pushMap(getWritableMap(array.getMap(i)));
+ }
+ return ret;
+ }
+
+ /**
+ * Destroys `touches` by removing touch objects at indices `indices`. This is to maintain
+ * compatibility with W3C touch "end" events, where the active touches don't include the set that
+ * has just been "ended".
+ *
+ * <p>This method was originally in ReactNativeRenderer.js
+ *
+ * <p>TODO: this method is a copy from ReactNativeRenderer.removeTouchesAtIndices and it needs to
+ * be rewritten in a more efficient way,
+ *
+ * @param touches {@link WritableArray} Deserialized touch objects.
+ * @param indices {WritableArray} Indices to remove from `touches`.
+ * @return {Array<Touch>} Subsequence of removed touch objects.
+ */
+ private Pair<WritableArray, WritableArray> removeTouchesAtIndices(
+ WritableArray touches, WritableArray indices) {
+ WritableArray rippedOut = new WritableNativeArray();
+ // use an unsafe downcast to alias to nullable elements,
+ // so we can delete and then compact.
+ WritableArray tempTouches = new WritableNativeArray();
+ Set<Integer> rippedOutIndices = new HashSet<>();
+ for (int i = 0; i < indices.size(); i++) {
+ int index = indices.getInt(i);
+ rippedOut.pushMap(getWritableMap(touches.getMap(index)));
+ rippedOutIndices.add(index);
+ }
+ for (int j = 0; j < touches.size(); j++) {
+ if (!rippedOutIndices.contains(j)) {
+ tempTouches.pushMap(getWritableMap(touches.getMap(j)));
+ }
+ }
+
+ return new Pair<>(rippedOut, tempTouches);
+ }
+
+ /**
+ * Selects a subsequence of `Touch`es, without destroying `touches`.
+ *
+ * <p>This method was originally in ReactNativeRenderer.js
+ *
+ * @param touches {@link WritableArray} Deserialized touch objects.
+ * @param changedIndices {@link WritableArray} Indices by which to pull subsequence.
+ * @return {Array<Touch>} Subsequence of touch objects.
+ */
+ private Pair<WritableArray, WritableArray> touchSubsequence(
+ WritableArray touches, WritableArray changedIndices) {
+ WritableArray result = new WritableNativeArray();
+ for (int i = 0; i < changedIndices.size(); i++) {
+ result.pushMap(getWritableMap(touches.getMap(changedIndices.getInt(i))));
+ }
+ return new Pair<>(result, touches);
+ }
+
+ /**
+ * TODO: this is required because the WritableNativeArray.getMap() returns a ReadableMap instead
+ * of the original writableMap. this will change in the near future.
+ *
+ * @param readableMap {@link ReadableMap} source map
+ */
+ private WritableMap getWritableMap(ReadableMap readableMap) {
+ WritableNativeMap map = new WritableNativeMap();
+ map.merge(readableMap);
+ return map;
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java

@@ -0,0 +1,119 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+package com.facebook.react.fabric;
+
+import com.facebook.react.bridge.JSIModuleProvider;
+import com.facebook.react.bridge.JavaScriptContextHolder;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.UIManager;
+import com.facebook.react.bridge.queue.MessageQueueThread;
+import com.facebook.react.fabric.jsi.Binding;
+import com.facebook.react.fabric.jsi.ComponentFactoryDelegate;
+import com.facebook.react.fabric.jsi.ComponentRegistry;
+import com.facebook.react.fabric.jsi.EventBeatManager;
+import com.facebook.react.fabric.jsi.EventEmitterWrapper;
+import com.facebook.react.fabric.jsi.FabricSoLoader;
+import com.facebook.react.fabric.mounting.ContextBasedViewPool;
+import com.facebook.react.fabric.mounting.LayoutMetricsConversions;
+import com.facebook.react.fabric.mounting.MountingManager;
+import com.facebook.react.fabric.mounting.ViewPool;
+import com.facebook.react.fabric.mounting.mountitems.BatchMountItem;
+import com.facebook.react.fabric.mounting.mountitems.CreateMountItem;
+import com.facebook.react.fabric.mounting.mountitems.DeleteMountItem;
+import com.facebook.react.fabric.mounting.mountitems.DispatchCommandMountItem;
+import com.facebook.react.fabric.mounting.mountitems.InsertMountItem;
+import com.facebook.react.fabric.mounting.mountitems.MountItem;
+import com.facebook.react.fabric.mounting.mountitems.PreAllocateViewMountItem;
+import com.facebook.react.fabric.mounting.mountitems.RemoveMountItem;
+import com.facebook.react.fabric.mounting.mountitems.UpdateEventEmitterMountItem;
+import com.facebook.react.fabric.mounting.mountitems.UpdateLayoutMountItem;
+import com.facebook.react.fabric.mounting.mountitems.UpdateLocalDataMountItem;
+import com.facebook.react.fabric.mounting.mountitems.UpdatePropsMountItem;
+import com.facebook.react.uimanager.UIManagerModule;
+import com.facebook.react.uimanager.events.EventDispatcher;
+import com.facebook.systrace.Systrace;
+
+public class FabricJSIModuleProvider implements JSIModuleProvider<UIManager> {
+
+ private final JavaScriptContextHolder mJSContext;
+ private final ReactApplicationContext mReactApplicationContext;
+ private final ComponentFactoryDelegate mComponentFactoryDelegate;
+ private final ReactNativeConfig mConfig;
+
+ public FabricJSIModuleProvider(
+ ReactApplicationContext reactApplicationContext,
+ JavaScriptContextHolder jsContext,
+ ComponentFactoryDelegate componentFactoryDelegate,
+ ReactNativeConfig config) {
+ mReactApplicationContext = reactApplicationContext;
+ mJSContext = jsContext;
+ mComponentFactoryDelegate = componentFactoryDelegate;
+ mConfig = config;
+ }
+
+ @Override
+ public UIManager get() {
+ final EventBeatManager eventBeatManager =
+ new EventBeatManager(mJSContext, mReactApplicationContext);
+ final FabricUIManager uiManager = createUIManager(eventBeatManager);
+ Systrace.beginSection(
+ Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "FabricJSIModuleProvider.registerBinding");
+ final Binding binding = new Binding();
+ // TODO T31905686: remove this call
+ loadClasses();
+ MessageQueueThread jsMessageQueueThread =
+ mReactApplicationContext
+ .getCatalystInstance()
+ .getReactQueueConfiguration()
+ .getJSQueueThread();
+ binding.register(mJSContext, uiManager, eventBeatManager, jsMessageQueueThread,
+ mComponentFactoryDelegate, mConfig);
+ Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+ return uiManager;
+ }
+
+ private FabricUIManager createUIManager(EventBeatManager eventBeatManager) {
+ Systrace.beginSection(
+ Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "FabricJSIModuleProvider.createUIManager");
+ UIManagerModule nativeModule = mReactApplicationContext.getNativeModule(UIManagerModule.class);
+ EventDispatcher eventDispatcher = nativeModule.getEventDispatcher();
+ FabricUIManager fabricUIManager =
+ new FabricUIManager(
+ mReactApplicationContext,
+ nativeModule.getViewManagerRegistry_DO_NOT_USE(),
+ eventDispatcher,
+ eventBeatManager);
+
+ Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+ return fabricUIManager;
+ }
+
+ // TODO T31905686: eager load Fabric classes, this is temporary and it will be removed
+ // in the near future
+ private static void loadClasses() {
+ FabricEventEmitter.class.getClass();
+ FabricUIManager.class.getClass();
+ GuardedFrameCallback.class.getClass();
+ BatchMountItem.class.getClass();
+ CreateMountItem.class.getClass();
+ DeleteMountItem.class.getClass();
+ DispatchCommandMountItem.class.getClass();
+ InsertMountItem.class.getClass();
+ MountItem.class.getClass();
+ RemoveMountItem.class.getClass();
+ UpdateEventEmitterMountItem.class.getClass();
+ UpdateLayoutMountItem.class.getClass();
+ UpdateLocalDataMountItem.class.getClass();
+ UpdatePropsMountItem.class.getClass();
+ ContextBasedViewPool.class.getClass();
+ LayoutMetricsConversions.class.getClass();
+ MountingManager.class.getClass();
+ ViewPool.class.getClass();
+ Binding.class.getClass();
+ ComponentFactoryDelegate.class.getClass();
+ ComponentRegistry.class.getClass();
+ EventBeatManager.class.getClass();
+ EventEmitterWrapper.class.getClass();
+ FabricSoLoader.class.getClass();
+ PreAllocateViewMountItem.class.getClass();
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java

@@ -1,158 +0,0 @@
-/**
- * Copyright (c) 2014-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-package com.facebook.react.fabric;
-
-import com.facebook.common.logging.FLog;
-import com.facebook.debug.holder.PrinterHolder;
-import com.facebook.debug.tags.ReactDebugOverlayTags;
-import com.facebook.react.common.ArrayUtils;
-import com.facebook.react.common.build.ReactBuildConfig;
-import com.facebook.react.uimanager.ReactShadowNode;
-import com.facebook.react.uimanager.UIViewOperationQueue;
-import com.facebook.react.uimanager.ViewAtIndex;
-import com.facebook.systrace.Systrace;
-import com.facebook.systrace.SystraceMessage;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-import javax.annotation.Nullable;
-
-public class FabricReconciler {
-
- private static final String TAG = FabricReconciler.class.getSimpleName();
- private static final boolean DEBUG = ReactBuildConfig.DEBUG || PrinterHolder
- .getPrinter().shouldDisplayLogMessage(ReactDebugOverlayTags.FABRIC_RECONCILER);
-
- private UIViewOperationQueue uiViewOperationQueue;
-
- public FabricReconciler(UIViewOperationQueue uiViewOperationQueue) {
- this.uiViewOperationQueue = uiViewOperationQueue;
- }
-
- public void manageChildren(ReactShadowNode previousRootShadowNode, ReactShadowNode newRootShadowNode) {
- SystraceMessage.beginSection(
- Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
- "FabricReconciler.manageChildren")
- .flush();
-
- try {
- List<ReactShadowNode> prevList =
- previousRootShadowNode == null ? null : previousRootShadowNode.getChildrenList();
- manageChildren(newRootShadowNode, prevList, newRootShadowNode.getChildrenList());
- } finally{
- Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
- }
- }
-
- private void manageChildren(
- ReactShadowNode parent,
- @Nullable List<ReactShadowNode> prevList,
- @Nullable List<ReactShadowNode> newList) {
- prevList = prevList == null ? Collections.<ReactShadowNode>emptyList() : prevList;
- newList = newList == null ? Collections.<ReactShadowNode>emptyList() : newList;
-
- // Iterate through each child list and compare each previous and next child. Same nodes
- // implies no change is needed. If the nodes are different but are referencing the same view,
- // the view needs to be updated with new props and children. Otherwise, there has been
- // a change in the children positions.
- int sameReactTagIndex = 0;
- for (; sameReactTagIndex < Math.min(prevList.size(), newList.size()); sameReactTagIndex++) {
- ReactShadowNode prevNode = prevList.get(sameReactTagIndex);
- ReactShadowNode newNode = newList.get(sameReactTagIndex);
- if (prevNode == newNode) {
- continue;
- }
- if (prevNode.getReactTag() != newNode.getReactTag()) {
- break;
- }
- enqueueUpdateProperties(newNode, prevNode);
- manageChildren(prevNode, prevNode.getChildrenList(), newNode.getChildrenList());
- newNode.setOriginalReactShadowNode(null);
- }
- int firstRemovedOrAddedViewIndex = sameReactTagIndex;
-
- // Every ReactShadowNode on the newList that is on the right side of
- // firstRemovedOrAddedViewIndex is defined as an added view.
- // It is more efficient to reorder removing and adding all the views in the right order, instead
- // of calculating the minimum amount of reorder operations.
- Set<Integer> addedTags = new HashSet<>();
- List<ViewAtIndex> viewsToAdd = new LinkedList<>();
- for (int k = firstRemovedOrAddedViewIndex; k < newList.size(); k++) {
- ReactShadowNode newNode = newList.get(k);
- if (newNode.isVirtual()) continue;
- enqueueUpdateProperties(newNode, newNode.getOriginalReactShadowNode());
- viewsToAdd.add(new ViewAtIndex(newNode.getReactTag(), k));
- List previousChildrenList = newNode.getOriginalReactShadowNode() == null ? null : newNode.getOriginalReactShadowNode().getChildrenList();
- manageChildren(newNode, previousChildrenList, newNode.getChildrenList());
- newNode.setOriginalReactShadowNode(null);
- addedTags.add(newNode.getReactTag());
- }
-
- // Every ReactShadowNode on the prevList that is on the right side of
- // firstRemovedOrAddedViewIndex is defined as a removed view.
- // It is more efficient to reorder removing and adding all the views in the right order, instead
- // of calculating the minimum amount of reorder operations.
- // If a View is not re-ordered, then the ReactTag is deleted (ReactShadowNode and native View
- // are released from memory)
- List<Integer> tagsToDelete = new LinkedList<>();
- List<Integer> indicesToRemove = new LinkedList<>();
- for (int j = prevList.size() - 1; j >= firstRemovedOrAddedViewIndex; j--) {
- ReactShadowNode nodeToRemove = prevList.get(j);
- if (nodeToRemove.isVirtual()) continue;
- indicesToRemove.add(0, j);
- if (!addedTags.contains(nodeToRemove.getReactTag())) {
- tagsToDelete.add(nodeToRemove.getReactTag());
- }
- }
-
- // TODO (t27180994): Mutate views synchronously on main thread
- if (!(indicesToRemove.isEmpty() && viewsToAdd.isEmpty() && tagsToDelete.isEmpty())) {
- int[] indicesToRemoveArray = ArrayUtils.copyListToArray(indicesToRemove);
- ViewAtIndex[] viewsToAddArray = viewsToAdd.toArray(new ViewAtIndex[viewsToAdd.size()]);
- int[] tagsToDeleteArray = ArrayUtils.copyListToArray(tagsToDelete);
- if (DEBUG) {
- FLog.d(
- TAG,
- "manageChildren.enqueueManageChildren parent: " + parent.getReactTag() +
- "\n\tIndices2Remove: " + Arrays.toString(indicesToRemoveArray) +
- "\n\tViews2Add: " + Arrays.toString(viewsToAddArray) +
- "\n\tTags2Delete: " + Arrays.toString(tagsToDeleteArray));
- }
- uiViewOperationQueue.enqueueManageChildren(
- parent.getReactTag(), indicesToRemoveArray, viewsToAddArray, tagsToDeleteArray);
- }
- }
-
- private void enqueueUpdateProperties(ReactShadowNode newNode, ReactShadowNode prevNode) {
- int reactTag = newNode.getReactTag();
- if (DEBUG) {
- FLog.d(
- TAG,
- "manageChildren.enqueueUpdateProperties " +
- "\n\ttag: " + reactTag +
- "\n\tviewClass: " + newNode.getViewClass() +
- "\n\tinstanceHandle: " + newNode.getInstanceHandle() +
- "\n\tnewProps: " + newNode.getNewProps());
- }
-
- if (prevNode != null) {
- newNode.updateScreenLayout(prevNode);
- }
-
- if (newNode.getNewProps() != null) {
- uiViewOperationQueue.enqueueUpdateProperties(
- reactTag, newNode.getViewClass(), newNode.getNewProps());
- }
-
- uiViewOperationQueue.enqueueUpdateInstanceHandle(
- reactTag, newNode.getInstanceHandle());
- }
-}

ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java

@@ -1,681 +1,471 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * Copyright (c) 2014-present, Facebook, Inc.
*
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
+ * <p>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.fabric;
-import static android.view.View.MeasureSpec.AT_MOST;
-import static android.view.View.MeasureSpec.EXACTLY;
-import static android.view.View.MeasureSpec.UNSPECIFIED;
+import static com.facebook.infer.annotation.ThreadConfined.UI;
+import static com.facebook.react.fabric.mounting.LayoutMetricsConversions.getMaxSize;
+import static com.facebook.react.fabric.mounting.LayoutMetricsConversions.getMinSize;
+import static com.facebook.react.fabric.mounting.LayoutMetricsConversions.getYogaMeasureMode;
+import static com.facebook.react.fabric.mounting.LayoutMetricsConversions.getYogaSize;
import static com.facebook.react.uimanager.common.UIManagerType.FABRIC;
+import android.annotation.SuppressLint;
import android.os.SystemClock;
-import android.view.View;
+import android.support.annotation.GuardedBy;
+import android.support.annotation.Nullable;
+import android.support.annotation.UiThread;
import com.facebook.common.logging.FLog;
-import com.facebook.debug.holder.PrinterHolder;
-import com.facebook.debug.tags.ReactDebugOverlayTags;
import com.facebook.infer.annotation.Assertions;
+import com.facebook.infer.annotation.ThreadConfined;
import com.facebook.proguard.annotations.DoNotStrip;
-import com.facebook.react.bridge.JavaScriptContextHolder;
+import com.facebook.react.bridge.GuardedRunnable;
+import com.facebook.react.bridge.LifecycleEventListener;
+import com.facebook.react.bridge.NativeMap;
import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableArray;
-import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableNativeMap;
import com.facebook.react.bridge.UIManager;
+import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.bridge.WritableMap;
-import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.common.ReactConstants;
-import com.facebook.react.common.annotations.VisibleForTesting;
-import com.facebook.react.common.build.ReactBuildConfig;
-import com.facebook.react.fabric.events.FabricEventEmitter;
-import com.facebook.react.modules.i18nmanager.I18nUtil;
-import com.facebook.react.uimanager.DisplayMetricsHolder;
-import com.facebook.react.uimanager.NativeViewHierarchyManager;
+import com.facebook.react.fabric.jsi.Binding;
+import com.facebook.react.fabric.jsi.EventBeatManager;
+import com.facebook.react.fabric.jsi.EventEmitterWrapper;
+import com.facebook.react.fabric.jsi.FabricSoLoader;
+import com.facebook.react.fabric.mounting.MountingManager;
+import com.facebook.react.fabric.mounting.mountitems.BatchMountItem;
+import com.facebook.react.fabric.mounting.mountitems.CreateMountItem;
+import com.facebook.react.fabric.mounting.mountitems.DeleteMountItem;
+import com.facebook.react.fabric.mounting.mountitems.DispatchCommandMountItem;
+import com.facebook.react.fabric.mounting.mountitems.InsertMountItem;
+import com.facebook.react.fabric.mounting.mountitems.MountItem;
+import com.facebook.react.fabric.mounting.mountitems.PreAllocateViewMountItem;
+import com.facebook.react.fabric.mounting.mountitems.RemoveMountItem;
+import com.facebook.react.fabric.mounting.mountitems.UpdateEventEmitterMountItem;
+import com.facebook.react.fabric.mounting.mountitems.UpdateLayoutMountItem;
+import com.facebook.react.fabric.mounting.mountitems.UpdateLocalDataMountItem;
+import com.facebook.react.fabric.mounting.mountitems.UpdatePropsMountItem;
+import com.facebook.react.modules.core.ReactChoreographer;
+import com.facebook.react.uimanager.IllegalViewOperationException;
import com.facebook.react.uimanager.ReactRootViewTagGenerator;
-import com.facebook.react.uimanager.ReactShadowNode;
-import com.facebook.react.uimanager.ReactShadowNodeImpl;
-import com.facebook.react.uimanager.ReactStylesDiffMap;
import com.facebook.react.uimanager.ThemedReactContext;
-import com.facebook.react.uimanager.UIViewOperationQueue;
-import com.facebook.react.uimanager.ViewManager;
+import com.facebook.react.uimanager.ViewManagerPropertyUpdater;
import com.facebook.react.uimanager.ViewManagerRegistry;
import com.facebook.react.uimanager.common.MeasureSpecProvider;
import com.facebook.react.uimanager.common.SizeMonitoringFrameLayout;
import com.facebook.react.uimanager.events.EventDispatcher;
import com.facebook.systrace.Systrace;
-import com.facebook.systrace.SystraceMessage;
-import com.facebook.yoga.YogaDirection;
import java.util.ArrayList;
-import java.util.LinkedList;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import javax.annotation.Nullable;
+import java.util.concurrent.ConcurrentHashMap;
-/**
- * This class is responsible to create, clone and update {@link ReactShadowNode} using the Fabric
- * API.
- */
-@SuppressWarnings("unused") // used from JNI
-@DoNotStrip
-public class FabricUIManager implements UIManager, JSHandler {
+@SuppressLint("MissingNativeLoadLibrary")
+public class FabricUIManager implements UIManager, LifecycleEventListener {
private static final String TAG = FabricUIManager.class.getSimpleName();
- private static final boolean DEBUG = ReactBuildConfig.DEBUG || PrinterHolder.getPrinter().shouldDisplayLogMessage(ReactDebugOverlayTags.FABRIC_UI_MANAGER);
- private final RootShadowNodeRegistry mRootShadowNodeRegistry = new RootShadowNodeRegistry();
+ private static final Map<String, String> sComponentNames = new HashMap<>();
+
+ static {
+ FabricSoLoader.staticInit();
+
+ // TODO T31905686: unify component names between JS - Android - iOS - C++
+ sComponentNames.put("View", "RCTView");
+ sComponentNames.put("Image", "RCTImageView");
+ sComponentNames.put("ScrollView", "RCTScrollView");
+ sComponentNames.put("ReactPerformanceLoggerFlag", "ReactPerformanceLoggerFlag");
+ sComponentNames.put("Paragraph", "RCTText");
+ sComponentNames.put("Text", "RCText");
+ sComponentNames.put("RawText", "RCTRawText");
+ sComponentNames.put("ActivityIndicatorView", "AndroidProgressBar");
+ sComponentNames.put("ShimmeringView", "RKShimmeringView");
+ sComponentNames.put("TemplateView", "RCTTemplateView");
+ }
+
+ private Binding mBinding;
private final ReactApplicationContext mReactApplicationContext;
- private final ViewManagerRegistry mViewManagerRegistry;
- private final UIViewOperationQueue mUIViewOperationQueue;
- private final NativeViewHierarchyManager mNativeViewHierarchyManager;
- private final JavaScriptContextHolder mJSContext;
- private volatile int mCurrentBatch = 0;
- private final FabricReconciler mFabricReconciler;
+ private final MountingManager mMountingManager;
private final EventDispatcher mEventDispatcher;
- private FabricBinding mBinding;
- private final FabricEventEmitter mFabricEventEmitter;
- private long mEventHandlerPointer;
- private long mLastCalculateLayoutTime = 0;
+ private final ConcurrentHashMap<Integer, ThemedReactContext> mReactContextForRootTag =
+ new ConcurrentHashMap<>();
+ private final EventBeatManager mEventBeatManager;
+ private final Object mMountItemsLock = new Object();
+ private final Object mPreMountItemsLock = new Object();
+
+ @GuardedBy("mMountItemsLock")
+ private List<MountItem> mMountItems = new ArrayList<>();
+
+ @GuardedBy("mPreMountItemsLock")
+ private List<MountItem> mPreMountItems = new ArrayList<>();
+
+ @ThreadConfined(UI)
+ private final DispatchUIFrameCallback mDispatchUIFrameCallback;
+
+ @ThreadConfined(UI)
+ private boolean mIsMountingEnabled = true;
+ private long mRunStartTime = 0l;
+ private long mBatchedExecutionTime = 0l;
+ private long mNonBatchedExecutionTime = 0l;
+ private long mDispatchViewUpdatesTime = 0l;
+ private long mCommitStartTime = 0l;
+ private long mLayoutTime = 0l;
+ private long mFinishTransactionTime = 0l;
public FabricUIManager(
ReactApplicationContext reactContext,
ViewManagerRegistry viewManagerRegistry,
- JavaScriptContextHolder jsContext,
- EventDispatcher eventDispatcher) {
- DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(reactContext);
+ EventDispatcher eventDispatcher,
+ EventBeatManager eventBeatManager) {
+ mDispatchUIFrameCallback = new DispatchUIFrameCallback(reactContext);
mReactApplicationContext = reactContext;
- mViewManagerRegistry = viewManagerRegistry;
- mNativeViewHierarchyManager = new NativeViewHierarchyManager(viewManagerRegistry);
- mUIViewOperationQueue =
- new UIViewOperationQueue(
- reactContext, mNativeViewHierarchyManager, 0);
- mFabricReconciler = new FabricReconciler(mUIViewOperationQueue);
- mFabricEventEmitter =
- new FabricEventEmitter(mReactApplicationContext, this);
+ mMountingManager = new MountingManager(viewManagerRegistry);
mEventDispatcher = eventDispatcher;
- mJSContext = jsContext;
+ mEventBeatManager = eventBeatManager;
+ mReactApplicationContext.addLifecycleEventListener(this);
}
- public void setBinding(FabricBinding binding) {
- mBinding = binding;
+ @Override
+ public <T extends SizeMonitoringFrameLayout & MeasureSpecProvider> int addRootView(
+ final T rootView, final WritableMap initialProps, final @Nullable String initialUITemplate) {
+ final int rootTag = ReactRootViewTagGenerator.getNextRootViewTag();
+ ThemedReactContext reactContext =
+ new ThemedReactContext(mReactApplicationContext, rootView.getContext());
+ mMountingManager.addRootView(rootTag, rootView);
+ mReactContextForRootTag.put(rootTag, reactContext);
+ mBinding.startSurface(rootTag, (NativeMap) initialProps);
+ updateRootLayoutSpecs(rootTag, rootView.getWidthMeasureSpec(), rootView.getHeightMeasureSpec());
+ if (initialUITemplate != null) {
+ mBinding.renderTemplateToSurface(rootTag, initialUITemplate);
+ }
+ return rootTag;
}
- /** Creates a new {@link ReactShadowNode} */
- @Nullable
+ /** Method called when an event has been dispatched on the C++ side. */
@DoNotStrip
- public ReactShadowNode createNode(
- int reactTag, String viewName, int rootTag, ReadableNativeMap props, long eventTarget) {
- if (DEBUG) {
- FLog.d(TAG, "createNode \n\ttag: " + reactTag +
- "\n\tviewName: " + viewName +
- "\n\trootTag: " + rootTag +
- "\n\tprops: " + props);
+ public void onRequestEventBeat() {
+ mEventDispatcher.dispatchAllEvents();
}
- try {
- ViewManager viewManager = mViewManagerRegistry.get(viewName);
- ReactShadowNode node = viewManager.createShadowNodeInstance(mReactApplicationContext);
- ReactShadowNode rootNode = getRootNode(rootTag);
- node.setRootTag(rootNode.getReactTag());
- node.setViewClassName(viewName);
- node.setInstanceHandle(eventTarget);
- node.setReactTag(reactTag);
- node.setThemedContext(rootNode.getThemedContext());
- ReactStylesDiffMap styles = updateProps(node, props);
+ @Override
+ public void removeRootView(int reactRootTag) {
+ // TODO T31905686: integrate with the unmounting of Fabric React Renderer.
+ mMountingManager.removeRootView(reactRootTag);
+ mReactContextForRootTag.remove(reactRootTag);
+ }
- if (!node.isVirtual()) {
- mUIViewOperationQueue.enqueueCreateView(
- rootNode.getThemedContext(), reactTag, viewName, styles);
+ @DoNotStrip
+ @SuppressWarnings("unused")
+ private MountItem createMountItem(
+ String componentName, int reactRootTag, int reactTag, boolean isVirtual) {
+ String component = sComponentNames.get(componentName);
+ if (component == null) {
+ throw new IllegalArgumentException("Unable to find component with name " + componentName);
}
- return node;
- } catch (Throwable t) {
- handleException(getRootNode(rootTag), t);
- return null;
+ ThemedReactContext reactContext = mReactContextForRootTag.get(reactRootTag);
+ if (reactContext == null) {
+ throw new IllegalArgumentException("Unable to find ReactContext for root: " + reactRootTag);
}
+ return new CreateMountItem(reactContext, component, reactTag, isVirtual);
}
- @VisibleForTesting
- ReactShadowNode getRootNode(int rootTag) {
- return mRootShadowNodeRegistry.getNode(rootTag);
+ @Override
+ public void initialize() {
+ mEventDispatcher.registerEventEmitter(FABRIC, new FabricEventEmitter(this));
+ mEventDispatcher.addBatchEventDispatchedListener(mEventBeatManager);
}
- private ReactStylesDiffMap updateProps(ReactShadowNode node, @Nullable ReadableNativeMap props) {
- ReactStylesDiffMap styles = null;
- if (props != null) {
- styles = new ReactStylesDiffMap(props);
- node.updateProperties(styles);
- }
- return styles;
+ @Override
+ public void onCatalystInstanceDestroy() {
+ mEventDispatcher.removeBatchEventDispatchedListener(mEventBeatManager);
+ mEventDispatcher.unregisterEventEmitter(FABRIC);
+ mBinding.unregister();
+ ViewManagerPropertyUpdater.clear();
}
- /**
- * @return a clone of the {@link ReactShadowNode} received by parameter. The cloned
- * ReactShadowNode will contain a copy of all the internal data of the original node,
- * including its children set (note that the children nodes will not be cloned).
- */
- @Nullable
@DoNotStrip
- public ReactShadowNode cloneNode(ReactShadowNode node) {
- if (DEBUG) {
- FLog.d(TAG, "cloneNode \n\tnode: " + node);
+ private void preallocateView(final int rootTag, final String componentName) {
+ if (UiThreadUtil.isOnUiThread()) {
+ // There is no reason to allocate views ahead of time on the main thread.
+ return;
}
- SystraceMessage.beginSection(
- Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
- "FabricUIManager.cloneNode")
- .flush();
- try {
- ReactShadowNode clone = node.mutableCopy(node.getInstanceHandle());
- assertReactShadowNodeCopy(node, clone);
- return clone;
- } catch (Throwable t) {
- handleException(node, t);
- return null;
- } finally{
- Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+ synchronized (mPreMountItemsLock) {
+ ThemedReactContext context =
+ Assertions.assertNotNull(mReactContextForRootTag.get(rootTag));
+ String component = sComponentNames.get(componentName);
+ Assertions.assertNotNull(component);
+ mPreMountItems.add(new PreAllocateViewMountItem(context, rootTag, component));
}
}
- /**
- * @return a clone of the {@link ReactShadowNode} received by parameter. The cloned
- * ReactShadowNode will contain a copy of all the internal data of the original node, but its
- * children set will be empty.
- */
- @Nullable
@DoNotStrip
- public ReactShadowNode cloneNodeWithNewChildren(ReactShadowNode node) {
- if (DEBUG) {
- FLog.d(TAG, "cloneNodeWithNewChildren \n\tnode: " + node);
- }
- SystraceMessage.beginSection(
- Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
- "FabricUIManager.cloneNodeWithNewChildren")
- .flush();
- try {
- ReactShadowNode clone = node.mutableCopyWithNewChildren(node.getInstanceHandle());
- assertReactShadowNodeCopy(node, clone);
- return clone;
- } catch (Throwable t) {
- handleException(node, t);
- return null;
- } finally{
- Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
- }
+ @SuppressWarnings("unused")
+ private MountItem removeMountItem(int reactTag, int parentReactTag, int index) {
+ return new RemoveMountItem(reactTag, parentReactTag, index);
}
- /**
- * @return a clone of the {@link ReactShadowNode} received by parameter. The cloned
- * ReactShadowNode will contain a copy of all the internal data of the original node, but its
- * props will be overridden with the {@link ReadableMap} received by parameter.
- */
- @Nullable
@DoNotStrip
- public ReactShadowNode cloneNodeWithNewProps(
- ReactShadowNode node, @Nullable ReadableNativeMap newProps) {
- if (DEBUG) {
- FLog.d(TAG, "cloneNodeWithNewProps \n\tnode: " + node + "\n\tprops: " + newProps);
- }
- SystraceMessage.beginSection(
- Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
- "FabricUIManager.cloneNodeWithNewProps")
- .flush();
- try {
- ReactShadowNode clone = node.mutableCopyWithNewProps(node.getInstanceHandle(),
- newProps == null ? null : new ReactStylesDiffMap(newProps));
- assertReactShadowNodeCopy(node, clone);
- return clone;
- } catch (Throwable t) {
- handleException(node, t);
- return null;
- } finally{
- Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
- }
+ @SuppressWarnings("unused")
+ private MountItem insertMountItem(int reactTag, int parentReactTag, int index) {
+ return new InsertMountItem(reactTag, parentReactTag, index);
}
- /**
- * @return a clone of the {@link ReactShadowNode} received by parameter. The cloned
- * ReactShadowNode will contain a copy of all the internal data of the original node, but its
- * props will be overridden with the {@link ReadableMap} received by parameter and its
- * children set will be empty.
- */
- @Nullable
@DoNotStrip
- public ReactShadowNode cloneNodeWithNewChildrenAndProps(
- ReactShadowNode node, ReadableNativeMap newProps) {
- if (DEBUG) {
- FLog.d(TAG, "cloneNodeWithNewChildrenAndProps \n\tnode: " + node + "\n\tnewProps: " + newProps);
- }
- SystraceMessage.beginSection(
- Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
- "FabricUIManager.cloneNodeWithNewChildrenAndProps")
- .flush();
- try {
- ReactShadowNode clone =
- node.mutableCopyWithNewChildrenAndProps(node.getInstanceHandle(),
- newProps == null ? null : new ReactStylesDiffMap(newProps));
- assertReactShadowNodeCopy(node, clone);
- return clone;
- } catch (Throwable t) {
- handleException(node, t);
- return null;
- } finally{
- Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
- }
+ @SuppressWarnings("unused")
+ private MountItem deleteMountItem(int reactTag) {
+ return new DeleteMountItem(reactTag);
}
- private void assertReactShadowNodeCopy(ReactShadowNode source, ReactShadowNode target) {
- Assertions.assertCondition(
- source.getClass().equals(target.getClass()),
- "Found "
- + target.getClass()
- + " class when expecting: "
- + source.getClass()
- + ". Check that "
- + source.getClass()
- + " implements the copy() method correctly.");
- }
-
- /**
- * Appends the child {@link ReactShadowNode} to the children set of the parent {@link
- * ReactShadowNode}.
- */
- @Nullable
@DoNotStrip
- public void appendChild(ReactShadowNode parent, ReactShadowNode child) {
- if (DEBUG) {
- FLog.d(TAG, "appendChild \n\tparent: " + parent + "\n\tchild: " + child);
- }
- SystraceMessage.beginSection(
- Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
- "FabricUIManager.appendChild")
- .flush();
- try {
- // If the child to append was already committed (child.isSealed()),
- // then we add a mutation of it. In the future this will be performed by FabricJS / Fiber.
- //TODO: T27926878 avoid cloning shared child
- if (child.isSealed()) {
- child = child.mutableCopy(child.getInstanceHandle());
- }
- parent.addChildAt(child, parent.getChildCount());
- } catch (Throwable t) {
- handleException(parent, t);
- } finally{
- Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
- }
+ @SuppressWarnings("unused")
+ private MountItem updateLayoutMountItem(int reactTag, int x, int y, int width, int height) {
+ return new UpdateLayoutMountItem(reactTag, x, y, width, height);
}
- /**
- * @return an empty {@link List<ReactShadowNode>} that will be used to append the {@link
- * ReactShadowNode} elements of the root. Typically this List will contain one element.
- */
@DoNotStrip
- public List<ReactShadowNode> createChildSet(int rootTag) {
- if (DEBUG) {
- FLog.d(TAG, "createChildSet rootTag: " + rootTag);
- }
- return new ArrayList<>(1);
+ @SuppressWarnings("unused")
+ private MountItem updatePropsMountItem(int reactTag, ReadableNativeMap map) {
+ return new UpdatePropsMountItem(reactTag, map);
}
- /**
- * Adds the {@link ReactShadowNode} to the {@link List<ReactShadowNode>} received by parameter.
- */
@DoNotStrip
- public void appendChildToSet(List<ReactShadowNode> childList, ReactShadowNode child) {
- childList.add(child);
+ @SuppressWarnings("unused")
+ private MountItem updateLocalDataMountItem(int reactTag, ReadableNativeMap newLocalData) {
+ return new UpdateLocalDataMountItem(reactTag, newLocalData);
}
@DoNotStrip
- public synchronized void completeRoot(int rootTag, @Nullable List<ReactShadowNode> childList) {
- SystraceMessage.beginSection(
- Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
- "FabricUIManager.completeRoot")
- .flush();
- try {
- long startTime = SystemClock.uptimeMillis();
- childList = childList == null ? new LinkedList<ReactShadowNode>() : childList;
- if (DEBUG) {
- FLog.d(TAG, "completeRoot rootTag: " + rootTag + ", childList: " + childList);
- }
- ReactShadowNode currentRootShadowNode = getRootNode(rootTag);
- Assertions.assertNotNull(
- currentRootShadowNode,
- "Root view with tag " + rootTag + " must be added before completeRoot is called");
-
- currentRootShadowNode = calculateDiffingAndCreateNewRootNode(currentRootShadowNode, childList);
-
- if (DEBUG) {
- FLog.d(
- TAG,
- "ReactShadowNodeHierarchy after diffing: " + currentRootShadowNode.getHierarchyInfo());
- }
-
- applyUpdatesRecursive(currentRootShadowNode);
- mUIViewOperationQueue.dispatchViewUpdates(
- mCurrentBatch++, startTime, mLastCalculateLayoutTime);
-
- mRootShadowNodeRegistry.replaceNode(currentRootShadowNode);
- } catch (Exception e) {
- handleException(getRootNode(rootTag), e);
- } finally{
- Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
- }
- }
-
- public void dispatchCommand(int reactTag, int commandId, @Nullable ReadableArray commandArgs) {
- mUIViewOperationQueue.enqueueDispatchCommand(reactTag, commandId, commandArgs);
- }
-
- private void notifyOnBeforeLayoutRecursive(ReactShadowNode node) {
- if (!node.hasUpdates()) {
- return;
- }
- for (int i = 0; i < node.getChildCount(); i++) {
- notifyOnBeforeLayoutRecursive(node.getChildAt(i));
- }
- node.onBeforeLayout();
+ @SuppressWarnings("unused")
+ private MountItem updateEventEmitterMountItem(int reactTag, Object eventEmitter) {
+ return new UpdateEventEmitterMountItem(reactTag, (EventEmitterWrapper) eventEmitter);
}
- private ReactShadowNode calculateDiffingAndCreateNewRootNode(
- ReactShadowNode currentRootShadowNode, List<ReactShadowNode> newChildList) {
- SystraceMessage.beginSection(
- Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
- "FabricUIManager.calculateDiffingAndCreateNewRootNode")
- .flush();
- try {
- ReactShadowNode newRootShadowNode = currentRootShadowNode.mutableCopyWithNewChildren(currentRootShadowNode.getInstanceHandle());
- for (ReactShadowNode child : newChildList) {
- appendChild(newRootShadowNode, child);
- }
-
- if (DEBUG) {
- FLog.d(
- TAG,
- "ReactShadowNodeHierarchy before calculateLayout: " + newRootShadowNode.getHierarchyInfo());
+ @DoNotStrip
+ @SuppressWarnings("unused")
+ private MountItem createBatchMountItem(MountItem[] items, int size) {
+ return new BatchMountItem(items, size);
}
- notifyOnBeforeLayoutRecursive(newRootShadowNode);
-
- calculateLayout(newRootShadowNode);
+ @DoNotStrip
+ @SuppressWarnings("unused")
+ private long measure(
+ String componentName,
+ ReadableNativeMap localData,
+ ReadableNativeMap props,
+ int minWidth,
+ int maxWidth,
+ int minHeight,
+ int maxHeight) {
- if (DEBUG) {
- FLog.d(
- TAG,
- "ReactShadowNodeHierarchy after calculateLayout: " + newRootShadowNode.getHierarchyInfo());
+ return mMountingManager.measure(
+ mReactApplicationContext,
+ componentName,
+ localData,
+ props,
+ getYogaSize(minWidth, maxWidth),
+ getYogaMeasureMode(minWidth, maxWidth),
+ getYogaSize(minHeight, maxHeight),
+ getYogaMeasureMode(minHeight, maxHeight));
}
- mFabricReconciler.manageChildren(currentRootShadowNode, newRootShadowNode);
- return newRootShadowNode;
- } finally{
- Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
- }
- }
+ /**
+ * This method enqueues UI operations directly to the UI thread. This might change in the future
+ * to enforce execution order using {@link ReactChoreographer#CallbackType}.
+ */
+ @DoNotStrip
+ @SuppressWarnings("unused")
+ private void scheduleMountItems(
+ final MountItem mountItems,
+ long commitStartTime,
+ long layoutTime,
+ long finishTransactionStartTime) {
- private void calculateLayout(ReactShadowNode newRootShadowNode) {
- SystraceMessage.beginSection(
- Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
- "FabricUIManager.calculateLayout")
- .flush();
- long startTime = SystemClock.uptimeMillis();
- try {
- newRootShadowNode.calculateLayout();
- } finally{
- mLastCalculateLayoutTime = SystemClock.uptimeMillis() - startTime;
- Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
- }
+ // TODO T31905686: support multithreading
+ mCommitStartTime = commitStartTime;
+ mLayoutTime = layoutTime;
+ mFinishTransactionTime = SystemClock.uptimeMillis() - finishTransactionStartTime;
+ mDispatchViewUpdatesTime = SystemClock.uptimeMillis();
+ synchronized (mMountItemsLock) {
+ mMountItems.add(mountItems);
}
- private void applyUpdatesRecursive(ReactShadowNode node) {
- SystraceMessage.beginSection(
- Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "FabricUIManager.applyUpdatesRecursive")
- .flush();
- try {
- applyUpdatesRecursive(node, 0, 0);
- } finally{
- SystraceMessage.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+ if (UiThreadUtil.isOnUiThread()) {
+ flushMountItems();
}
}
- private void applyUpdatesRecursive(ReactShadowNode node, float absoluteX, float absoluteY) {
- if (!node.hasUpdates()) {
+ @UiThread
+ private void flushMountItems() {
+ if (!mIsMountingEnabled) {
+ FLog.w(
+ ReactConstants.TAG,
+ "Not flushing pending UI operations because of previously thrown Exception");
return;
}
- if (!node.isVirtualAnchor()) {
- for (int i = 0; i < node.getChildCount(); i++) {
- applyUpdatesRecursive(
- node.getChildAt(i),
- absoluteX + node.getLayoutX(),
- absoluteY + node.getLayoutY());
- }
+ try {
+ List<MountItem> preMountItemsToDispatch;
+ synchronized (mPreMountItemsLock) {
+ preMountItemsToDispatch = mPreMountItems;
+ mPreMountItems = new ArrayList<>();
}
- int tag = node.getReactTag();
- if (getRootNode(tag) == null) {
- boolean frameDidChange =
- node.dispatchUpdates(absoluteX, absoluteY, mUIViewOperationQueue, null);
- // Notify JS about layout event if requested
- // and if the position or dimensions actually changed
- // (consistent with iOS and Android Default implementation).
- if (frameDidChange && node.shouldNotifyOnLayout()) {
- mUIViewOperationQueue.enqueueOnLayoutEvent(tag,
- node.getScreenX(),
- node.getScreenY(),
- node.getScreenWidth(),
- node.getScreenHeight());
- }
+ mRunStartTime = SystemClock.uptimeMillis();
+ List<MountItem> mountItemsToDispatch;
+ synchronized (mMountItemsLock) {
+ mountItemsToDispatch = mMountItems;
+ mMountItems = new ArrayList<>();
}
- // Set the reference to the OriginalReactShadowNode to NULL, as the tree is already committed
- // and we do not need to hold references to the previous tree anymore
- node.setOriginalReactShadowNode(null);
- node.markUpdateSeen();
- node.markAsSealed();
+ long nonBatchedExecutionStartTime = SystemClock.uptimeMillis();
+ Systrace.beginSection(
+ Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
+ "FabricUIManager::premountViews (" + preMountItemsToDispatch.size() + " batches)");
+ for (MountItem mountItem : preMountItemsToDispatch) {
+ mountItem.execute(mMountingManager);
}
+ mNonBatchedExecutionTime = SystemClock.uptimeMillis() - nonBatchedExecutionStartTime;
+ Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
- @Override
- @DoNotStrip
- public <T extends SizeMonitoringFrameLayout & MeasureSpecProvider> int addRootView(
- final T rootView) {
-
- SystraceMessage.beginSection(
+ Systrace.beginSection(
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
- "FabricUIManager.addRootView")
- .flush();
- try {
- final int rootTag = ReactRootViewTagGenerator.getNextRootViewTag();
- ThemedReactContext themedRootContext =
- new ThemedReactContext(mReactApplicationContext, rootView.getContext());
+ "FabricUIManager::mountViews (" + mountItemsToDispatch.size() + " batches)");
- ReactShadowNode rootShadowNode = createRootShadowNode(rootTag, themedRootContext);
-
- int widthMeasureSpec = rootView.getWidthMeasureSpec();
- int heightMeasureSpec = rootView.getHeightMeasureSpec();
- updateRootView(rootShadowNode, widthMeasureSpec, heightMeasureSpec);
-
- rootView.setOnSizeChangedListener(
- new SizeMonitoringFrameLayout.OnSizeChangedListener() {
- @Override
- public void onSizeChanged(final int width, final int height, int oldW, int oldH) {
- updateRootSize(rootTag, width, height);
+ long batchedExecutionStartTime = SystemClock.uptimeMillis();
+ for (MountItem mountItem : mountItemsToDispatch) {
+ mountItem.execute(mMountingManager);
}
- });
-
- mRootShadowNodeRegistry.registerNode(rootShadowNode);
- mUIViewOperationQueue.addRootView(rootTag, rootView, themedRootContext);
- return rootTag;
- } finally{
+ mBatchedExecutionTime = SystemClock.uptimeMillis() - batchedExecutionStartTime;
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+ } catch (Exception ex) {
+ FLog.e(ReactConstants.TAG, "Exception thrown when executing UIFrameGuarded", ex);
+ mIsMountingEnabled = false;
+ throw ex;
}
}
- @Override
- @DoNotStrip
- public synchronized void updateRootLayoutSpecs(int rootViewTag, int widthMeasureSpec, int heightMeasureSpec) {
- ReactShadowNode rootNode = getRootNode(rootViewTag);
- if (rootNode == null) {
- FLog.w(ReactConstants.TAG, "Tried to update non-existent root tag: " + rootViewTag);
- return;
- }
-
- ReactShadowNode newRootNode = rootNode.mutableCopy(rootNode.getInstanceHandle());
- updateRootView(newRootNode, widthMeasureSpec, heightMeasureSpec);
- mRootShadowNodeRegistry.replaceNode(newRootNode);
+ public void setBinding(Binding binding) {
+ mBinding = binding;
}
/**
- * Updates the root view size and re-render the RN surface.
- *
- * //TODO: change synchronization to integrate with new #render loop.
+ * Updates the layout metrics of the root view based on the Measure specs received by parameters.
*/
- private synchronized void updateRootSize(int rootTag, int newWidth, int newHeight) {
- ReactShadowNode rootNode = getRootNode(rootTag);
- if (rootNode == null) {
- FLog.w(
- ReactConstants.TAG,
- "Tried to update size of non-existent tag: " + rootTag);
- return;
- }
-
- ReactShadowNode newRootNode = rootNode.mutableCopy(rootNode.getInstanceHandle());
- int newWidthSpec = View.MeasureSpec.makeMeasureSpec(newWidth, View.MeasureSpec.EXACTLY);
- int newHeightSpec = View.MeasureSpec.makeMeasureSpec(newHeight, View.MeasureSpec.EXACTLY);
- updateRootView(newRootNode, newWidthSpec, newHeightSpec);
-
- completeRoot(rootTag, newRootNode.getChildrenList());
- }
-
- public void removeRootView(int rootTag) {
- mRootShadowNodeRegistry.removeNode(rootTag);
- }
-
- private ReactShadowNode createRootShadowNode(int rootTag, ThemedReactContext themedReactContext) {
- ReactShadowNode rootNode = new ReactShadowNodeImpl();
- I18nUtil sharedI18nUtilInstance = I18nUtil.getInstance();
- if (sharedI18nUtilInstance.isRTL(themedReactContext)) {
- rootNode.setLayoutDirection(YogaDirection.RTL);
- }
- rootNode.setViewClassName("Root");
- rootNode.setReactTag(rootTag);
- rootNode.setThemedContext(themedReactContext);
- return rootNode;
- }
+ @Override
+ public void updateRootLayoutSpecs(
+ final int rootTag, final int widthMeasureSpec, final int heightMeasureSpec) {
- /**
- * Updates the styles of the {@link ReactShadowNode} based on the Measure specs received by
- * parameters.
- */
- private void updateRootView(
- ReactShadowNode node, int widthMeasureSpec, int heightMeasureSpec) {
- int widthMode = View.MeasureSpec.getMode(widthMeasureSpec);
- int widthSize = View.MeasureSpec.getSize(widthMeasureSpec);
- switch (widthMode) {
- case EXACTLY:
- node.setStyleWidth(widthSize);
- break;
- case AT_MOST:
- node.setStyleMaxWidth(widthSize);
- break;
- case UNSPECIFIED:
- node.setStyleWidthAuto();
- break;
- }
-
- int heightMode = View.MeasureSpec.getMode(heightMeasureSpec);
- int heightSize = View.MeasureSpec.getSize(heightMeasureSpec);
- switch (heightMode) {
- case EXACTLY:
- node.setStyleHeight(heightSize);
- break;
- case AT_MOST:
- node.setStyleMaxHeight(heightSize);
- break;
- case UNSPECIFIED:
- node.setStyleHeightAuto();
- break;
+ // TODO T31905686: this should not run in a different thread.
+ // This is a workaround because a race condition that happens in core of RN.
+ // We are analyzing this and fixing it as part of another diff.
+ mReactApplicationContext.runOnJSQueueThread(
+ new GuardedRunnable(mReactApplicationContext) {
+ @Override
+ public void runGuarded() {
+ mBinding.setConstraints(
+ rootTag,
+ getMinSize(widthMeasureSpec),
+ getMaxSize(widthMeasureSpec),
+ getMinSize(heightMeasureSpec),
+ getMaxSize(heightMeasureSpec));
}
+ });
}
- private void handleException(ReactShadowNode node, Throwable t) {
- try {
- ThemedReactContext context = node.getThemedContext();
- // TODO move exception management to JNI side, and refactor to avoid wrapping Throwable into
- // a RuntimeException
- context.handleException(new RuntimeException(t));
- } catch (Exception ex) {
- FLog.e(TAG, "Exception while executing a Fabric method", t);
- throw new RuntimeException(ex.getMessage(), t);
- }
+ public void receiveEvent(int reactTag, String eventName, @Nullable WritableMap params) {
+ EventEmitterWrapper eventEmitter = mMountingManager.getEventEmitter(reactTag);
+ if (eventEmitter == null) {
+ // This can happen if the view has disappeared from the screen (because of async events)
+ FLog.d(TAG, "Unable to invoke event: " + eventName + " for reactTag: " + reactTag);
+ return;
}
- @Nullable
- @DoNotStrip
- public long getEventTarget(int reactTag) {
- long instanceHandle = mNativeViewHierarchyManager.getInstanceHandle(reactTag);
- return instanceHandle;
+ eventEmitter.invoke(eventName, params);
}
- @DoNotStrip
- public void registerEventHandler(long eventHandlerPointer) {
- mEventHandlerPointer = eventHandlerPointer;
+ @Override
+ public void onHostResume() {
+ ReactChoreographer.getInstance()
+ .postFrameCallback(ReactChoreographer.CallbackType.DISPATCH_UI, mDispatchUIFrameCallback);
}
- @DoNotStrip
- public void releaseEventTarget(long eventTargetPointer) {
- mBinding.releaseEventTarget(mJSContext.get(), eventTargetPointer);
+ @Override
+ public void onHostPause() {
+ ReactChoreographer.getInstance()
+ .removeFrameCallback(ReactChoreographer.CallbackType.DISPATCH_UI, mDispatchUIFrameCallback);
}
- @DoNotStrip
- public void releaseEventHandler(long eventHandlerPointer) {
- mBinding.releaseEventHandler(mJSContext.get(), eventHandlerPointer);
- }
+ @Override
+ public void onHostDestroy() {}
@Override
- @DoNotStrip
- public void invoke(long eventTarget, String name, WritableMap params) {
- if (DEBUG) {
- FLog.d(
- TAG,
- "Dispatching event for target: " + eventTarget);
- }
- if (params == null) {
- params = new WritableNativeMap();
+ public void dispatchCommand(
+ final int reactTag, final int commandId, final ReadableArray commandArgs) {
+ synchronized (mMountItemsLock) {
+ mMountItems.add(new DispatchCommandMountItem(reactTag, commandId, commandArgs));
}
- mBinding.dispatchEventToTarget(mJSContext.get(), mEventHandlerPointer, eventTarget, name, (WritableNativeMap) params);
}
@Override
public void setJSResponder(int reactTag, boolean blockNativeResponder) {
- // TODO: Do nothing for now
+ // do nothing for now.
}
@Override
public void clearJSResponder() {
- // TODO: Do nothing for now
+ // do nothing for now.
}
@Override
- public void initialize() {
- FabricEventEmitter eventEmitter =
- new FabricEventEmitter(mReactApplicationContext, this);
- mEventDispatcher.registerEventEmitter(FABRIC, mFabricEventEmitter);
+ public void profileNextBatch() {
+ // TODO T31905686: Remove this method and add support for multi-threading performance counters
}
@Override
- public void onCatalystInstanceDestroy() {
- mBinding.releaseEventHandler(mJSContext.get(), mEventHandlerPointer);
- mEventDispatcher.unregisterEventEmitter(FABRIC);
- mFabricEventEmitter.close();
+ public Map<String, Long> getPerformanceCounters() {
+ HashMap<String, Long> performanceCounters = new HashMap<>();
+ performanceCounters.put("CommitStartTime", mCommitStartTime);
+ performanceCounters.put("LayoutTime", mLayoutTime);
+ performanceCounters.put("DispatchViewUpdatesTime", mDispatchViewUpdatesTime);
+ performanceCounters.put("RunStartTime", mRunStartTime);
+ performanceCounters.put("BatchedExecutionTime", mBatchedExecutionTime);
+ performanceCounters.put("NonBatchedExecutionTime", mNonBatchedExecutionTime);
+ performanceCounters.put("FinishFabricTransactionTime", mFinishTransactionTime);
+ return performanceCounters;
}
- @Override
- public void profileNextBatch() {
- mUIViewOperationQueue.profileNextBatch();
+ private class DispatchUIFrameCallback extends GuardedFrameCallback {
+
+ private DispatchUIFrameCallback(ReactContext reactContext) {
+ super(reactContext);
}
@Override
- public Map<String, Long> getPerformanceCounters() {
- // TODO change profiling when enabling multi-thread rendering.
- return mUIViewOperationQueue.getProfiledBatchPerfCounters();
+ public void doFrameGuarded(long frameTimeNanos) {
+ if (!mIsMountingEnabled) {
+ FLog.w(
+ ReactConstants.TAG,
+ "Not flushing pending UI operations because of previously thrown Exception");
+ return;
+ }
+
+ try {
+ flushMountItems();
+ } catch (Exception ex) {
+ FLog.i(ReactConstants.TAG, "Exception thrown when executing UIFrameGuarded", ex);
+ mIsMountingEnabled = false;
+ throw ex;
+ } finally {
+ ReactChoreographer.getInstance()
+ .postFrameCallback(
+ ReactChoreographer.CallbackType.DISPATCH_UI, mDispatchUIFrameCallback);
+ }
+ }
}
}

ReactAndroid/src/main/java/com/facebook/react/fabric/GuardedFrameCallback.java

@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * <p>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.fabric;
+
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.modules.core.ChoreographerCompat;
+
+public abstract class GuardedFrameCallback extends ChoreographerCompat.FrameCallback {
+
+ private final ReactContext mReactContext;
+
+ protected GuardedFrameCallback(ReactContext reactContext) {
+ mReactContext = reactContext;
+ }
+
+ @Override
+ public final void doFrame(long frameTimeNanos) {
+ try {
+ doFrameGuarded(frameTimeNanos);
+ } catch (RuntimeException e) {
+ mReactContext.handleException(e);
+ }
+ }
+
+ /**
+ * Like the standard doFrame but RuntimeExceptions will be caught and passed to {@link
+ * com.facebook.react.bridge.ReactContext#handleException(RuntimeException)}.
+ */
+ protected abstract void doFrameGuarded(long frameTimeNanos);
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/BUCK

@@ -1,24 +0,0 @@
-load("//tools/build_defs/oss:rn_defs.bzl", "react_native_dep", "react_native_target", "rn_android_library")
-
-rn_android_library(
- name = "jsc",
- srcs = glob(["**/*.java"]),
- provided_deps = [
- react_native_dep("third-party/android/support/v4:lib-support-v4"),
- ],
- required_for_source_only_abi = True,
- visibility = [
- "PUBLIC",
- ],
- deps = [
- react_native_dep("libraries/soloader/java/com/facebook/soloader:soloader"),
- react_native_dep("third-party/java/infer-annotations:infer-annotations"),
- react_native_target("java/com/facebook/react/bridge:bridge"),
- react_native_target("java/com/facebook/react/fabric:fabric"),
- react_native_target("java/com/facebook/react/fabric/jsc/jni:jni"),
- ],
- exported_deps = [
- react_native_dep("java/com/facebook/jni:jni"),
- react_native_dep("java/com/facebook/proguard/annotations:annotations"),
- ],
-)

ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/FabricJSCBinding.java

@@ -1,65 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-package com.facebook.react.fabric.jsc;
-
-import com.facebook.jni.HybridData;
-import com.facebook.proguard.annotations.DoNotStrip;
-import com.facebook.react.bridge.JavaScriptContextHolder;
-import com.facebook.react.fabric.FabricBinding;
-import com.facebook.react.fabric.FabricUIManager;
-import com.facebook.react.bridge.NativeMap;
-import com.facebook.soloader.SoLoader;
-
-@DoNotStrip
-public class FabricJSCBinding implements FabricBinding {
-
- static {
- SoLoader.loadLibrary("fabricjscjni");
- }
-
- // used from native
- @SuppressWarnings("unused")
- private final HybridData mHybridData;
-
- private static native HybridData initHybrid();
-
- @Override
- public native void releaseEventTarget(long jsContextNativePointer, long eventTargetPointer);
-
- @Override
- public native void releaseEventHandler(long jsContextNativePointer, long eventHandlerPointer);
-
- @Override
- public native void dispatchEventToEmptyTarget(
- long jsContextNativePointer,
- long eventHandlerPointer,
- String type,
- NativeMap payload
- );
-
- @Override
- public native void dispatchEventToTarget(
- long jsContextNativePointer,
- long eventHandlerPointer,
- long eventTargetPointer,
- String type,
- NativeMap payload
- );
-
- private native void installFabric(long jsContextNativePointer, Object fabricModule);
-
- public FabricJSCBinding() {
- mHybridData = initHybrid();
- }
-
- @Override
- public void installFabric(JavaScriptContextHolder jsContext, FabricUIManager fabricModule) {
- fabricModule.setBinding(this);
- installFabric(jsContext.get(), fabricModule);
- }
-}

ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/BUCK

@@ -1,21 +0,0 @@
-load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "FBJNI_TARGET", "react_native_target", "react_native_xplat_target", "rn_xplat_cxx_library")
-
-rn_xplat_cxx_library(
- name = "jni",
- srcs = glob(["*.cpp"]),
- headers = glob(["*.h"]),
- compiler_flags = [
- "-Wall",
- "-fexceptions",
- "-std=c++1y",
- ],
- platforms = ANDROID,
- soname = "libfabricjscjni.$(ext)",
- visibility = ["PUBLIC"],
- deps = [
- FBJNI_TARGET,
- "xplat//folly:molly",
- react_native_xplat_target("jschelpers:jschelpers"),
- react_native_target("jni/react/jni:jni"),
- ],
-)

ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/FabricJSCBinding.cpp

@@ -1,415 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#include "FabricJSCBinding.h"
-#include <fb/fbjni.h>
-#include <jschelpers/JavaScriptCore.h>
-#include <jschelpers/Unicode.h>
-
-using namespace facebook::jni;
-
-namespace facebook {
-namespace react {
-
-namespace {
-
-bool useCustomJSC = false;
-
-struct JList : public JavaClass<JList> {
- static constexpr auto kJavaDescriptor = "Ljava/util/List;";
-};
-
-struct JShadowNode : public JavaClass<JShadowNode> {
- static constexpr auto kJavaDescriptor = "Lcom/facebook/react/uimanager/ReactShadowNode;";
-};
-
-typedef struct FabricJSCUIManager {
- FabricJSCUIManager(alias_ref<jobject> module, JSClassRef classRef, bool customJSC)
- : wrapperObjectClassRef(classRef)
- , useCustomJSC(customJSC) {
- fabricUiManager = make_global(module);
- JSC_JSClassRetain(useCustomJSC, wrapperObjectClassRef);
- }
- global_ref<jobject> fabricUiManager;
- JSClassRef wrapperObjectClassRef;
- bool useCustomJSC;
-
- ~FabricJSCUIManager() {
- JSC_JSClassRelease(useCustomJSC, wrapperObjectClassRef);
- }
-} FabricJSCUIManager;
-
-jobject makePlainGlobalRef(jobject object) {
- // When storing the global reference we need it to be a plain
- // pointer. That's why we use plain jni instead of fbjni here.
- return Environment::current()->NewGlobalRef(object);
-}
-
-local_ref<JString> JSValueToJString(JSContextRef ctx, JSValueRef value) {
- JSStringRef strRef = JSC_JSValueToStringCopy(ctx, value, NULL);
- const size_t size = JSStringGetMaximumUTF8CStringSize(strRef);
- char buffer[size];
- JSStringGetUTF8CString(strRef, buffer, size);
- JSC_JSStringRelease(ctx, strRef);
- return make_jstring(buffer);
-}
-
-local_ref<JShadowNode> JSValueToJShadowNode(JSContextRef ctx, JSValueRef value) {
- JSObjectRef obj = JSC_JSValueToObject(ctx, value, NULL);
- auto node = static_cast<JShadowNode::javaobject>(JSC_JSObjectGetPrivate(useCustomJSC, obj));
- return make_local(node);
-}
-
-local_ref<JList> JSValueToJList(JSContextRef ctx, JSValueRef value) {
- JSObjectRef obj = JSC_JSValueToObject(ctx, value, NULL);
- auto node = static_cast<JList::javaobject>(JSC_JSObjectGetPrivate(useCustomJSC, obj));
- return make_local(node);
-}
-
-local_ref<ReadableNativeMap::jhybridobject> JSValueToReadableMapViaJSON(JSContextRef ctx, JSValueRef value) {
- JSStringRef jsonRef = JSC_JSValueCreateJSONString(ctx, value, 0, NULL);
- size_t size = JSC_JSStringGetLength(ctx, jsonRef);
- const JSChar* utf16 = JSC_JSStringGetCharactersPtr(ctx, jsonRef);
- std::string json = unicode::utf16toUTF8(utf16, size);
- JSC_JSStringRelease(ctx, jsonRef);
- folly::dynamic dynamicValue = folly::parseJson(json);
- return ReadableNativeMap::newObjectCxxArgs(std::move(dynamicValue));
-}
-
-JSValueRef ReadableMapToJSValueViaJSON(JSContextRef ctx, NativeMap *map) {
- folly::dynamic dynamicValue = map->consume();
- auto json = folly::toJson(dynamicValue);
- JSStringRef jsonRef = JSC_JSStringCreateWithUTF8CString(ctx, json.c_str());
- auto value = JSC_JSValueMakeFromJSONString(ctx, jsonRef);
- JSC_JSStringRelease(ctx, jsonRef);
- return value;
-}
-
-JSValueRef createNode(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
- FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
- alias_ref<jobject> manager = managerWrapper->fabricUiManager;
- JSClassRef classRef = managerWrapper->wrapperObjectClassRef;
-
- static auto createNode =
- jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
- ->getMethod<alias_ref<JShadowNode>(jint, jstring, jint, ReadableNativeMap::javaobject, jlong)>("createNode");
-
- int reactTag = (int)JSC_JSValueToNumber(ctx, arguments[0], NULL);
- auto viewName = JSValueToJString(ctx, arguments[1]);
- int rootTag = (int)JSC_JSValueToNumber(ctx, arguments[2], NULL);
- auto props = JSC_JSValueIsNull(ctx, arguments[3]) ? local_ref<ReadableNativeMap::jhybridobject>(nullptr) :
- JSValueToReadableMapViaJSON(ctx, arguments[3]);;
- auto eventTarget = (void *)arguments[4];
-
- auto node = createNode(manager, reactTag, viewName.get(), rootTag, props.get(), (jlong)eventTarget);
-
- return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(node.get()));
-}
-
-JSValueRef cloneNode(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
- FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
- alias_ref<jobject> manager = managerWrapper->fabricUiManager;
- JSClassRef classRef = managerWrapper->wrapperObjectClassRef;
-
- static auto cloneNode =
- jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
- ->getMethod<alias_ref<JShadowNode>(JShadowNode::javaobject)>("cloneNode");
-
- auto previousNode = JSValueToJShadowNode(ctx, arguments[0]);
- auto newNode = cloneNode(manager, previousNode.get());
-
- return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(newNode.get()));
-}
-
-JSValueRef cloneNodeWithNewChildren(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
- FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
- alias_ref<jobject> manager = managerWrapper->fabricUiManager;
- JSClassRef classRef = managerWrapper->wrapperObjectClassRef;
-
- static auto cloneNodeWithNewChildren =
- jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
- ->getMethod<alias_ref<JShadowNode>(JShadowNode::javaobject)>("cloneNodeWithNewChildren");
-
- auto previousNode = JSValueToJShadowNode(ctx, arguments[0]);
- auto newNode = cloneNodeWithNewChildren(manager, previousNode.get());
-
- return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(newNode.get()));
-}
-
-JSValueRef cloneNodeWithNewProps(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
- FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
- alias_ref<jobject> manager = managerWrapper->fabricUiManager;
- JSClassRef classRef = managerWrapper->wrapperObjectClassRef;
-
- static auto cloneNodeWithNewProps =
- jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
- ->getMethod<alias_ref<JShadowNode>(JShadowNode::javaobject, ReadableNativeMap::javaobject)>("cloneNodeWithNewProps");
-
- auto previousNode = JSValueToJShadowNode(ctx, arguments[0]);
- auto props = JSValueToReadableMapViaJSON(ctx, arguments[1]);
- auto newNode = cloneNodeWithNewProps(manager, previousNode.get(), props.get());
-
- return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(newNode.get()));
-}
-
-JSValueRef cloneNodeWithNewChildrenAndProps(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
- FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
- alias_ref<jobject> manager = managerWrapper->fabricUiManager;
- JSClassRef classRef = managerWrapper->wrapperObjectClassRef;
-
- static auto cloneNodeWithNewChildrenAndProps =
- jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
- ->getMethod<alias_ref<JShadowNode>(JShadowNode::javaobject, ReadableNativeMap::javaobject)>("cloneNodeWithNewChildrenAndProps");
-
- auto previousNode = JSValueToJShadowNode(ctx, arguments[0]);
- auto props = JSValueToReadableMapViaJSON(ctx, arguments[1]);
- auto newNode = cloneNodeWithNewChildrenAndProps(manager, previousNode.get(), props.get());
-
- return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(newNode.get()));
-}
-
-JSValueRef appendChild(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
- FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
- alias_ref<jobject> manager = managerWrapper->fabricUiManager;
-
- static auto appendChild =
- jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
- ->getMethod<void(JShadowNode::javaobject, JShadowNode::javaobject)>("appendChild");
-
- auto parentNode = JSValueToJShadowNode(ctx, arguments[0]);
- auto childNode = JSValueToJShadowNode(ctx, arguments[1]);
-
- appendChild(manager, parentNode.get(), childNode.get());
-
- return JSC_JSValueMakeUndefined(ctx);
-}
-
-JSValueRef createChildSet(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
- FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
- alias_ref<jobject> manager = managerWrapper->fabricUiManager;
- JSClassRef classRef = managerWrapper->wrapperObjectClassRef;
-
- static auto createChildSet =
- jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
- ->getMethod<alias_ref<JList>(jint)>("createChildSet");
-
- int rootTag = (int)JSC_JSValueToNumber(ctx, arguments[0], NULL);
- auto childSet = createChildSet(manager, rootTag);
-
- return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(childSet.get()));
-}
-
-JSValueRef appendChildToSet(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
- FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
- alias_ref<jobject> manager = managerWrapper->fabricUiManager;
-
- static auto appendChildToSet =
- jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
- ->getMethod<void(JList::javaobject, JShadowNode::javaobject)>("appendChildToSet");
-
- auto childSet = JSValueToJList(ctx, arguments[0]);
- auto childNode = JSValueToJShadowNode(ctx, arguments[1]);
-
- appendChildToSet(manager, childSet.get(), childNode.get());
-
- return JSC_JSValueMakeUndefined(ctx);
-}
-
-JSValueRef completeRoot(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
- FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
- alias_ref<jobject> manager = managerWrapper->fabricUiManager;
-
- static auto completeRoot =
- jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
- ->getMethod<void(jint, JList::javaobject)>("completeRoot");
-
- int rootTag = (int)JSC_JSValueToNumber(ctx, arguments[0], NULL);
- auto childSet = JSValueToJList(ctx, arguments[1]);
-
- completeRoot(manager, rootTag, childSet.get());
-
- return JSC_JSValueMakeUndefined(ctx);
-}
-
-JSValueRef registerEventHandler(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
- FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
- alias_ref<jobject> manager = managerWrapper->fabricUiManager;
-
- static auto registerEventHandler =
- jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
- ->getMethod<void(jlong)>("registerEventHandler");
-
- auto eventHandler = arguments[0];
- JSC_JSValueProtect(ctx, eventHandler);
- registerEventHandler(manager, (jlong)eventHandler);
-
- return JSC_JSValueMakeUndefined(ctx);
-}
-
-void finalizeJNIObject(JSObjectRef object) {
- // Release whatever global ref object we're storing here.
- jobject globalRef = (jobject)JSC_JSObjectGetPrivate(useCustomJSC, object);
- Environment::current()->DeleteGlobalRef(globalRef);
-}
-
-void finalizeWrapper(JSObjectRef object) {
- FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, object);
- delete managerWrapper;
-}
-
-void addFabricMethod(
- JSContextRef context,
- jni::alias_ref<jobject> fabricModule,
- JSClassRef nodeClassRef,
- JSObjectRef module,
- const char *name,
- JSObjectCallAsFunctionCallback callback
-) {
- JSClassDefinition definition = kJSClassDefinitionEmpty;
- definition.callAsFunction = callback;
- definition.finalize = finalizeWrapper;
- JSClassRef classRef = JSC_JSClassCreate(useCustomJSC, &definition);
- FabricJSCUIManager *managerWrapper = new FabricJSCUIManager(fabricModule, nodeClassRef, useCustomJSC);
- JSObjectRef functionRef = JSC_JSObjectMake(context, classRef, managerWrapper);
- JSC_JSClassRelease(useCustomJSC, classRef);
-
- JSStringRef nameStr = JSC_JSStringCreateWithUTF8CString(context, name);
- JSC_JSObjectSetProperty(context, module, nameStr, functionRef, kJSPropertyAttributeNone, NULL);
- JSC_JSStringRelease(context, nameStr);
-}
-
-}
-
-jni::local_ref<FabricJSCBinding::jhybriddata> FabricJSCBinding::initHybrid(
- jni::alias_ref<jclass>) {
- return makeCxxInstance();
-}
-
-void FabricJSCBinding::releaseEventTarget(
- jlong jsContextNativePointer,
- jlong eventTargetPointer
-) {
- // This is now a noop.
-}
-
-void FabricJSCBinding::releaseEventHandler(
- jlong jsContextNativePointer,
- jlong eventHandlerPointer
-) {
- JSContextRef context = (JSContextRef)jsContextNativePointer;
- JSValueRef value = (JSValueRef)((void *)eventHandlerPointer);
- // Release this function.
- JSC_JSValueUnprotect(context, value);
-}
-
-void FabricJSCBinding::dispatchEventToEmptyTarget(
- jlong jsContextNativePointer,
- jlong eventHandlerPointer,
- std::string type,
- NativeMap *payloadMap
-) {
- JSContextRef context = (JSContextRef)jsContextNativePointer;
- JSObjectRef eventHandler = (JSObjectRef)((void *)eventHandlerPointer);
- JSValueRef eventTarget = JSC_JSValueMakeNull(context);
-
- JSObjectRef thisArg = (JSObjectRef)JSC_JSValueMakeUndefined(context);
- JSStringRef typeStr = JSC_JSStringCreateWithUTF8CString(context, type.c_str());
- JSValueRef typeRef = JSC_JSValueMakeString(context, typeStr);
- JSC_JSStringRelease(context, typeStr);
- JSValueRef payloadRef = ReadableMapToJSValueViaJSON(context, payloadMap);
- JSValueRef args[] = {eventTarget, typeRef, payloadRef};
- JSValueRef exn;
- JSValueRef result = JSC_JSObjectCallAsFunction(
- context,
- eventHandler,
- thisArg,
- 3,
- args,
- &exn
- );
- if (!result) {
- // TODO: Handle error in exn
- }
-}
-
-void FabricJSCBinding::dispatchEventToTarget(
- jlong jsContextNativePointer,
- jlong eventHandlerPointer,
- jlong eventTargetPointer,
- std::string type,
- NativeMap *payloadMap
-) {
- JSContextRef context = (JSContextRef)jsContextNativePointer;
- JSObjectRef eventHandler = (JSObjectRef)((void *)eventHandlerPointer);
- JSObjectRef eventTarget = (JSObjectRef)((void *)eventTargetPointer);
-
- JSObjectRef thisArg = (JSObjectRef)JSC_JSValueMakeUndefined(context);
- JSStringRef typeStr = JSC_JSStringCreateWithUTF8CString(context, type.c_str());
- JSValueRef typeRef = JSC_JSValueMakeString(context, typeStr);
- JSC_JSStringRelease(context, typeStr);
- JSValueRef payloadRef = ReadableMapToJSValueViaJSON(context, payloadMap);
- JSValueRef args[] = {eventTarget, typeRef, payloadRef};
- JSValueRef exn;
- JSValueRef result = JSC_JSObjectCallAsFunction(
- context,
- eventHandler,
- thisArg,
- 3,
- args,
- &exn
- );
- if (!result) {
- // TODO: Handle error in exn
- }
-}
-
-void FabricJSCBinding::installFabric(jlong jsContextNativePointer,
- jni::alias_ref<jobject> fabricModule) {
- JSContextRef context = (JSContextRef)jsContextNativePointer;
- useCustomJSC = facebook::react::isCustomJSCPtr(context);
-
- JSObjectRef module = JSC_JSObjectMake(context, NULL, NULL);
-
- // Class definition for wrapper objects around nodes and sets
- JSClassDefinition definition = kJSClassDefinitionEmpty;
- definition.finalize = finalizeJNIObject;
- JSClassRef classRef = JSC_JSClassCreate(useCustomJSC, &definition);
-
- addFabricMethod(context, fabricModule, classRef, module, "createNode", createNode);
- addFabricMethod(context, fabricModule, classRef, module, "cloneNode", cloneNode);
- addFabricMethod(context, fabricModule, classRef, module, "cloneNodeWithNewChildren", cloneNodeWithNewChildren);
- addFabricMethod(context, fabricModule, classRef, module, "cloneNodeWithNewProps", cloneNodeWithNewProps);
- addFabricMethod(context, fabricModule, classRef, module, "cloneNodeWithNewChildrenAndProps", cloneNodeWithNewChildrenAndProps);
-
- addFabricMethod(context, fabricModule, classRef, module, "appendChild", appendChild);
- addFabricMethod(context, fabricModule, classRef, module, "createChildSet", createChildSet);
- addFabricMethod(context, fabricModule, classRef, module, "appendChildToSet", appendChildToSet);
- addFabricMethod(context, fabricModule, classRef, module, "completeRoot", completeRoot);
-
- addFabricMethod(context, fabricModule, classRef, module, "registerEventHandler", registerEventHandler);
-
- JSC_JSClassRelease(useCustomJSC, classRef);
-
- JSObjectRef globalObject = JSC_JSContextGetGlobalObject(context);
- JSStringRef globalName = JSC_JSStringCreateWithUTF8CString(context, "nativeFabricUIManager");
- JSC_JSObjectSetProperty(context, globalObject, globalName, module, kJSPropertyAttributeNone, NULL);
- JSC_JSStringRelease(context, globalName);
-}
-
-void FabricJSCBinding::registerNatives() {
- registerHybrid({
- makeNativeMethod("initHybrid", FabricJSCBinding::initHybrid),
- makeNativeMethod("installFabric", FabricJSCBinding::installFabric),
- makeNativeMethod("releaseEventTarget", FabricJSCBinding::releaseEventTarget),
- makeNativeMethod("releaseEventHandler", FabricJSCBinding::releaseEventHandler),
- makeNativeMethod("dispatchEventToEmptyTarget", FabricJSCBinding::dispatchEventToEmptyTarget),
- makeNativeMethod("dispatchEventToTarget", FabricJSCBinding::dispatchEventToTarget),
- });
-}
-
-}
-}

ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/FabricJSCBinding.h

@@ -1,54 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#pragma once
-
-#include <memory>
-#include <fb/fbjni.h>
-#include <react/jni/ReadableNativeMap.h>
-
-namespace facebook {
-namespace react {
-
-class Instance;
-
-class FabricJSCBinding : public jni::HybridClass<FabricJSCBinding> {
-public:
- constexpr static const char *const kJavaDescriptor =
- "Lcom/facebook/react/fabric/jsc/FabricJSCBinding;";
-
- static void registerNatives();
-
-private:
-
- static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jclass>);
-
- void releaseEventTarget(jlong jsContextNativePointer, jlong eventTargetPointer);
-
- void releaseEventHandler(jlong jsContextNativePointer, jlong eventHandlerPointer);
-
- void dispatchEventToEmptyTarget(
- jlong jsContextNativePointer,
- jlong eventHandlerPointer,
- std::string type,
- NativeMap *payload
- );
-
- void dispatchEventToTarget(
- jlong jsContextNativePointer,
- jlong eventHandlerPointer,
- jlong eventTargetPointer,
- std::string type,
- NativeMap *payload
- );
-
- void installFabric(jlong jsContextNativePointer, jni::alias_ref<jobject> fabricModule);
-
-};
-
-}
-}

ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/OnLoad.cpp

@@ -1,17 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#include <fb/fbjni.h>
-#include <fb/xplat_init.h>
-
-#include "FabricJSCBinding.h"
-
-JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
- return facebook::xplat::initialize(vm, [] {
- facebook::react::FabricJSCBinding::registerNatives();
- });
-}

ReactAndroid/src/main/java/com/facebook/react/fabric/JSHandler.java

@@ -1,15 +0,0 @@
-/**
- * Copyright (c) 2014-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-package com.facebook.react.fabric;
-
-import com.facebook.react.bridge.WritableMap;
-
-public interface JSHandler {
-
- void invoke(long instanceHandle, String name, WritableMap params);
-
-}

ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/Binding.java

@@ -0,0 +1,72 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * <p>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.fabric.jsi;
+
+import android.annotation.SuppressLint;
+import com.facebook.jni.HybridData;
+import com.facebook.proguard.annotations.DoNotStrip;
+import com.facebook.react.bridge.JavaScriptContextHolder;
+import com.facebook.react.bridge.NativeMap;
+import com.facebook.react.bridge.queue.MessageQueueThread;
+import com.facebook.react.fabric.ReactNativeConfig;
+import com.facebook.react.fabric.FabricUIManager;
+import com.facebook.react.uimanager.PixelUtil;
+
+@DoNotStrip
+@SuppressLint("MissingNativeLoadLibrary")
+public class Binding {
+
+ static {
+ FabricSoLoader.staticInit();
+ }
+
+ @DoNotStrip private final HybridData mHybridData;
+
+ private static native HybridData initHybrid();
+
+ public Binding() {
+ mHybridData = initHybrid();
+ }
+
+ private native void installFabricUIManager(
+ long jsContextNativePointer,
+ Object uiManager,
+ EventBeatManager eventBeatManager,
+ MessageQueueThread jsMessageQueueThread,
+ ComponentFactoryDelegate componentsRegistry,
+ Object reactNativeConfig);
+
+ public native void startSurface(int surfaceId, NativeMap initialProps);
+
+ public native void renderTemplateToSurface(int surfaceId, String uiTemplate);
+
+ public native void stopSurface(int surfaceId);
+
+ public native void setPixelDensity(float pointScaleFactor);
+
+ public native void setConstraints(
+ int rootTag, float minWidth, float maxWidth, float minHeight, float maxHeight);
+
+ public void register(
+ JavaScriptContextHolder jsContext,
+ FabricUIManager fabricUIManager,
+ EventBeatManager eventBeatManager,
+ MessageQueueThread jsMessageQueueThread,
+ ComponentFactoryDelegate componentFactoryDelegate,
+ ReactNativeConfig reactNativeConfig) {
+ fabricUIManager.setBinding(this);
+ installFabricUIManager(
+ jsContext.get(), fabricUIManager, eventBeatManager, jsMessageQueueThread, componentFactoryDelegate, reactNativeConfig);
+ setPixelDensity(PixelUtil.getDisplayMetricDensity());
+ }
+
+ private native void uninstallFabricUIManager();
+
+ public void unregister() {
+ uninstallFabricUIManager();
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/ComponentFactoryDelegate.java

@@ -0,0 +1,27 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.fabric.jsi;
+
+import com.facebook.jni.HybridData;
+import com.facebook.proguard.annotations.DoNotStrip;
+import com.facebook.soloader.SoLoader;
+import com.facebook.react.fabric.jsi.FabricSoLoader;
+
+@DoNotStrip
+public class ComponentFactoryDelegate {
+
+ static {
+ FabricSoLoader.staticInit();
+ }
+
+ @DoNotStrip
+ private final HybridData mHybridData;
+
+ @DoNotStrip
+ private static native HybridData initHybrid();
+
+ public ComponentFactoryDelegate() {
+ mHybridData = initHybrid();
+ }
+
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/ComponentRegistry.java

@@ -0,0 +1,25 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.fabric.jsi;
+
+import com.facebook.jni.HybridData;
+import com.facebook.proguard.annotations.DoNotStrip;
+import com.facebook.soloader.SoLoader;
+
+@DoNotStrip
+public class ComponentRegistry {
+
+ static {
+ FabricSoLoader.staticInit();
+ }
+
+ private final HybridData mHybridData;
+
+ @DoNotStrip
+ private static native HybridData initHybrid();
+
+ public ComponentRegistry() {
+ mHybridData = initHybrid();
+ }
+
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/EventBeatManager.java

@@ -0,0 +1,61 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * <p>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.fabric.jsi;
+
+import android.annotation.SuppressLint;
+import com.facebook.jni.HybridData;
+import com.facebook.proguard.annotations.DoNotStrip;
+import com.facebook.react.bridge.JavaScriptContextHolder;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.uimanager.events.BatchEventDispatchedListener;
+import com.facebook.react.fabric.jsi.FabricSoLoader;
+
+/**
+ * Class that acts as a proxy between the list of EventBeats registered in C++ and the Android side.
+ */
+@SuppressLint("MissingNativeLoadLibrary")
+public class EventBeatManager implements BatchEventDispatchedListener {
+
+ static {
+ FabricSoLoader.staticInit();
+ }
+
+ @DoNotStrip private final HybridData mHybridData;
+ private final ReactApplicationContext mReactApplicationContext;
+
+ private static native HybridData initHybrid(long jsContext);
+
+ private native void beat();
+
+ public EventBeatManager(
+ JavaScriptContextHolder jsContext, ReactApplicationContext reactApplicationContext) {
+ mHybridData = initHybrid(jsContext.get());
+ mReactApplicationContext = reactApplicationContext;
+ }
+
+ @Override
+ public void onBatchEventDispatched() {
+ dispatchEventsAsync();
+ }
+
+ /**
+ * Induce a beat in the AsyncEventBeat, calling the JNI method {@link #beat()} in the JS thread.
+ */
+ private void dispatchEventsAsync() {
+ if (mReactApplicationContext.isOnJSQueueThread()) {
+ beat();
+ } else {
+ mReactApplicationContext.runOnJSQueueThread(
+ new Runnable() {
+ @Override
+ public void run() {
+ beat();
+ }
+ });
+ }
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/EventEmitterWrapper.java

@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * <p>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.fabric.jsi;
+
+import android.annotation.SuppressLint;
+import android.support.annotation.Nullable;
+import com.facebook.jni.HybridData;
+import com.facebook.proguard.annotations.DoNotStrip;
+import com.facebook.react.bridge.NativeMap;
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.bridge.WritableNativeMap;
+import com.facebook.react.fabric.jsi.FabricSoLoader;
+
+/**
+ * This class holds reference to the C++ EventEmitter object. Instances of this class are created on
+ * the Bindings.cpp, where the pointer to the C++ event emitter is set.
+ */
+@SuppressLint("MissingNativeLoadLibrary")
+public class EventEmitterWrapper {
+
+ static {
+ FabricSoLoader.staticInit();
+ }
+
+ @DoNotStrip private final HybridData mHybridData;
+
+ private static native HybridData initHybrid();
+
+ private EventEmitterWrapper() {
+ mHybridData = initHybrid();
+ }
+
+ private native void invokeEvent(String eventName, NativeMap params);
+
+ /**
+ * Invokes the execution of the C++ EventEmitter.
+ *
+ * @param eventName {@link String} name of the event to execute.
+ * @param params {@link WritableMap} payload of the event
+ */
+ public void invoke(String eventName, @Nullable WritableMap params) {
+ NativeMap payload = params == null ? new WritableNativeMap() : (NativeMap) params;
+ invokeEvent(eventName, payload);
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/FabricSoLoader.java

@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * <p>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.fabric.jsi;
+
+import static com.facebook.systrace.Systrace.TRACE_TAG_REACT_JAVA_BRIDGE;
+
+import com.facebook.react.bridge.ReactMarker;
+import com.facebook.react.bridge.ReactMarkerConstants;
+import com.facebook.soloader.SoLoader;
+import com.facebook.systrace.Systrace;
+
+public class FabricSoLoader {
+ private static boolean sDidInit = false;
+
+ public static void staticInit() {
+ if (sDidInit) {
+ return;
+ }
+ sDidInit = true;
+
+ Systrace.beginSection(
+ Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "FabricSoLoader.staticInit::load:fabricjni");
+ ReactMarker.logMarker(ReactMarkerConstants.LOAD_REACT_NATIVE_SO_FILE_START);
+ SoLoader.loadLibrary("fabricjni");
+ ReactMarker.logMarker(ReactMarkerConstants.LOAD_REACT_NATIVE_SO_FILE_END);
+ Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/AsyncEventBeat.h

@@ -0,0 +1,59 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+// This source code is licensed under the MIT license found in the
+// LICENSE file in the root directory of this source tree.
+
+#pragma once
+
+#include "EventBeatManager.h"
+#include <jsi/jsi.h>
+#include <react/events/EventBeat.h>
+
+namespace facebook {
+namespace react {
+
+namespace {
+
+ class AsyncEventBeat:
+ public EventBeat {
+
+ private:
+ EventBeatManager *eventBeatManager_;
+ jsi::Runtime *runtime_;
+ jni::global_ref<jobject> javaUIManager_;
+
+ public:
+
+ friend class EventBeatManager;
+
+ AsyncEventBeat(EventBeatManager* eventBeatManager, jsi::Runtime *runtime, jni::global_ref<jobject> javaUIManager) {
+ eventBeatManager_ = eventBeatManager;
+ runtime_ = runtime;
+ javaUIManager_ = javaUIManager;
+ eventBeatManager->registerEventBeat(this);
+ }
+
+ ~AsyncEventBeat() {
+ eventBeatManager_->unregisterEventBeat(this);
+ }
+
+ void induce() const override {
+ beat(*runtime_);
+ }
+
+ void request() const override {
+ bool alreadyRequested = isRequested_;
+ EventBeat::request();
+ if (!alreadyRequested) {
+ // Notifies java side that an event will be dispatched (e.g. LayoutEvent)
+ static auto onRequestEventBeat =
+ jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
+ ->getMethod<void()>("onRequestEventBeat");
+ onRequestEventBeat(javaUIManager_);
+ }
+ }
+ };
+
+}
+
+}
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp

@@ -0,0 +1,377 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+// This source code is licensed under the MIT license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include "AsyncEventBeat.h"
+#include "Binding.h"
+#include "EventEmitterWrapper.h"
+#include "ReactNativeConfigHolder.h"
+
+#include <android/log.h>
+#include <fb/fbjni.h>
+#include <jsi/jsi.h>
+#include <jsi/JSIDynamic.h>
+#include <react/components/scrollview/ScrollViewProps.h>
+#include <react/debug/SystraceSection.h>
+#include <react/events/EventEmitter.h>
+#include <react/events/EventBeat.h>
+#include <react/uimanager/ComponentDescriptorFactory.h>
+#include <react/uimanager/ContextContainer.h>
+#include <react/uimanager/primitives.h>
+#include <react/uimanager/Scheduler.h>
+#include <react/uimanager/SchedulerDelegate.h>
+#include <react/uimanager/TimeUtils.h>
+
+using namespace facebook::jni;
+using namespace facebook::jsi;
+
+namespace facebook {
+namespace react {
+
+namespace {
+
+ struct JMountItem : public JavaClass<JMountItem> {
+ static constexpr auto kJavaDescriptor = "Lcom/facebook/react/fabric/mounting/mountitems/MountItem;";
+ };
+
+ static constexpr auto UIManagerJavaDescriptor = "com/facebook/react/fabric/FabricUIManager";
+
+}
+
+jni::local_ref<Binding::jhybriddata> Binding::initHybrid(
+ jni::alias_ref<jclass>) {
+ return makeCxxInstance();
+}
+
+void Binding::startSurface(jint surfaceId, NativeMap *initialProps) {
+ if (scheduler_) {
+ scheduler_->startSurface(surfaceId, "", initialProps->consume());
+ }
+}
+
+void Binding::renderTemplateToSurface(jint surfaceId, jstring uiTemplate) {
+ if (scheduler_) {
+ auto env = Environment::current();
+ const char *nativeString = env->GetStringUTFChars(uiTemplate, JNI_FALSE);
+ scheduler_->renderTemplateToSurface(surfaceId, nativeString);
+ env->ReleaseStringUTFChars(uiTemplate, nativeString);
+ }
+}
+
+void Binding::stopSurface(jint surfaceId){
+ if (scheduler_) {
+ scheduler_->stopSurface(surfaceId);
+ }
+}
+
+void Binding::setConstraints(jint rootTag, jfloat minWidth, jfloat maxWidth, jfloat minHeight, jfloat maxHeight) {
+ if (scheduler_) {
+ auto minimumSize = Size {minWidth / pointScaleFactor_, minHeight / pointScaleFactor_};
+ auto maximumSize = Size {maxWidth / pointScaleFactor_, maxHeight / pointScaleFactor_};
+
+ LayoutContext context;
+ context.pointScaleFactor = { pointScaleFactor_ };
+ LayoutConstraints constraints = {};
+ constraints.minimumSize = minimumSize;
+ constraints.maximumSize = maximumSize;
+
+ scheduler_->constraintSurfaceLayout(rootTag, constraints, context);
+ }
+}
+
+void Binding::installFabricUIManager(jlong jsContextNativePointer, jni::alias_ref<jobject> javaUIManager, EventBeatManager* eventBeatManager, jni::alias_ref<JavaMessageQueueThread::javaobject> jsMessageQueueThread, ComponentFactoryDelegate* componentsRegistry, jni::alias_ref<jobject> reactNativeConfig) {
+ Runtime* runtime = (Runtime*) jsContextNativePointer;
+
+ javaUIManager_ = make_global(javaUIManager);
+
+ SharedContextContainer contextContainer = std::make_shared<ContextContainer>();
+
+ auto sharedJSMessageQueueThread = std::make_shared<JMessageQueueThread> (jsMessageQueueThread);
+ RuntimeExecutor runtimeExecutor = [runtime, sharedJSMessageQueueThread](std::function<void(facebook::jsi::Runtime &runtime)> &&callback) {
+ sharedJSMessageQueueThread->runOnQueue([runtime, callback = std::move(callback)]() {
+ callback(*runtime);
+ });
+ };
+
+ // TODO: T31905686 Create synchronous Event Beat
+ jni::global_ref<jobject> localJavaUIManager = javaUIManager_;
+ EventBeatFactory synchronousBeatFactory = [eventBeatManager, runtime, localJavaUIManager]() mutable {
+ return std::make_unique<AsyncEventBeat>(eventBeatManager, runtime, localJavaUIManager);
+ };
+
+ EventBeatFactory asynchronousBeatFactory = [eventBeatManager, runtime, localJavaUIManager]() mutable {
+ return std::make_unique<AsyncEventBeat>(eventBeatManager, runtime, localJavaUIManager);
+ };
+
+ // TODO: Provide non-empty impl for ReactNativeConfig.
+ std::shared_ptr<const ReactNativeConfig> config = std::make_shared<const ReactNativeConfigHolder>(reactNativeConfig);
+ contextContainer->registerInstance(config, "ReactNativeConfig");
+ contextContainer->registerInstance<EventBeatFactory>(synchronousBeatFactory, "synchronous");
+ contextContainer->registerInstance<EventBeatFactory>(asynchronousBeatFactory, "asynchronous");
+ contextContainer->registerInstance(javaUIManager_, "FabricUIManager");
+ contextContainer->registerInstance(runtimeExecutor, "runtime-executor");
+
+ scheduler_ = std::make_shared<Scheduler>(contextContainer, componentsRegistry->buildRegistryFunction);
+
+ scheduler_->setDelegate(this);
+}
+
+void Binding::uninstallFabricUIManager() {
+ scheduler_ = nullptr;
+ javaUIManager_ = nullptr;
+}
+
+//TODO: this method will be removed when binding for components are code-gen
+local_ref<JString> getPlatformComponentName(const ShadowView &shadowView) {
+ local_ref<JString> componentName;
+ auto newViewProps = std::dynamic_pointer_cast<const ScrollViewProps>(shadowView.props);
+
+ if (newViewProps && newViewProps->yogaStyle.flexDirection == YGFlexDirectionRow) {
+ componentName = make_jstring("AndroidHorizontalScrollView");
+ } else {
+ componentName = make_jstring(shadowView.componentName);
+ }
+ return componentName;
+}
+
+local_ref<JMountItem::javaobject> createCreateMountItem(const jni::global_ref<jobject> &javaUIManager, const ShadowViewMutation &mutation, const Tag rootTag) {
+ static auto createJavaInstruction =
+ jni::findClassStatic(UIManagerJavaDescriptor)
+ ->getMethod<alias_ref<JMountItem>(jstring,jint,jint,jboolean)>("createMountItem");
+
+ auto newChildShadowView = mutation.newChildShadowView;
+
+ local_ref<JString> componentName = getPlatformComponentName(newChildShadowView);
+
+ jboolean isVirtual = newChildShadowView.layoutMetrics == EmptyLayoutMetrics;
+
+ return createJavaInstruction(javaUIManager, componentName.get(), rootTag, newChildShadowView.tag, isVirtual);
+}
+
+local_ref<JMountItem::javaobject> createUpdateEventEmitterMountItem(const jni::global_ref<jobject> &javaUIManager, const ShadowViewMutation &mutation) {
+ if (!mutation.newChildShadowView.eventEmitter) {
+ return nullptr;
+ }
+ SharedEventEmitter eventEmitter = mutation.newChildShadowView.eventEmitter;
+
+ // Do not hold a reference to javaEventEmitter from the C++ side.
+ auto javaEventEmitter = EventEmitterWrapper::newObjectJavaArgs();
+ EventEmitterWrapper* cEventEmitter = cthis(javaEventEmitter);
+ cEventEmitter->eventEmitter = eventEmitter;
+
+ static auto updateEventEmitterInstruction =
+ jni::findClassStatic(UIManagerJavaDescriptor)
+ ->getMethod<alias_ref<JMountItem>(jint, jobject)>("updateEventEmitterMountItem");
+
+ return updateEventEmitterInstruction(javaUIManager, mutation.newChildShadowView.tag, javaEventEmitter.get());
+}
+
+local_ref<JMountItem::javaobject> createUpdatePropsMountItem(const jni::global_ref<jobject> &javaUIManager, const ShadowViewMutation &mutation) {
+ auto shadowView = mutation.newChildShadowView;
+ auto newViewProps = *std::dynamic_pointer_cast<const ViewProps>(shadowView.props);
+
+ // TODO: move props from map to a typed object.
+ auto newProps = shadowView.props->rawProps;
+
+ local_ref<ReadableNativeMap::jhybridobject> readableMap = ReadableNativeMap::newObjectCxxArgs(newProps);
+
+ static auto updatePropsInstruction =
+ jni::findClassStatic(UIManagerJavaDescriptor)
+ ->getMethod<alias_ref<JMountItem>(jint,ReadableNativeMap::javaobject)>("updatePropsMountItem");
+
+ return updatePropsInstruction(javaUIManager,
+ mutation.newChildShadowView.tag,
+ readableMap.get());
+}
+
+local_ref<JMountItem::javaobject> createUpdateLayoutMountItem(const jni::global_ref<jobject> &javaUIManager, const ShadowViewMutation &mutation) {
+ auto oldChildShadowView = mutation.oldChildShadowView;
+ auto newChildShadowView = mutation.newChildShadowView;
+
+ if (newChildShadowView.layoutMetrics != EmptyLayoutMetrics && oldChildShadowView.layoutMetrics != newChildShadowView.layoutMetrics) {
+ static auto updateLayoutInstruction =
+ jni::findClassStatic(UIManagerJavaDescriptor)
+ ->getMethod<alias_ref<JMountItem>(jint, jint, jint, jint, jint)>("updateLayoutMountItem");
+ auto layoutMetrics = newChildShadowView.layoutMetrics;
+ auto pointScaleFactor = layoutMetrics.pointScaleFactor;
+ auto frame = layoutMetrics.frame;
+
+ int x = round(frame.origin.x * pointScaleFactor);
+ int y = round(frame.origin.y * pointScaleFactor);
+ int w = round(frame.size.width * pointScaleFactor);
+ int h = round(frame.size.height * pointScaleFactor);
+ return updateLayoutInstruction(javaUIManager, newChildShadowView.tag, x, y, w, h);
+ }
+
+ return nullptr;
+}
+
+local_ref<JMountItem::javaobject> createInsertMountItem(const jni::global_ref<jobject> &javaUIManager, const ShadowViewMutation &mutation) {
+ static auto insertInstruction =
+ jni::findClassStatic(UIManagerJavaDescriptor)
+ ->getMethod<alias_ref<JMountItem>(jint,jint,jint)>("insertMountItem");
+
+ return insertInstruction(javaUIManager, mutation.newChildShadowView.tag, mutation.parentShadowView.tag, mutation.index);
+}
+
+local_ref<JMountItem::javaobject> createUpdateLocalData(const jni::global_ref<jobject> &javaUIManager, const ShadowViewMutation &mutation) {
+ static auto updateLocalDataInstruction =
+ jni::findClassStatic(UIManagerJavaDescriptor)
+ ->getMethod<alias_ref<JMountItem>(jint, ReadableNativeMap::javaobject)>("updateLocalDataMountItem");
+
+ auto localData = mutation.newChildShadowView.localData;
+
+ folly::dynamic newLocalData = folly::dynamic::object();
+ if (localData) {
+ newLocalData = localData->getDynamic();
+ }
+ local_ref<ReadableNativeMap::jhybridobject> readableMap = ReadableNativeMap::newObjectCxxArgs(newLocalData);
+
+ return updateLocalDataInstruction(javaUIManager, mutation.newChildShadowView.tag, readableMap.get());
+}
+
+local_ref<JMountItem::javaobject> createRemoveMountItem(const jni::global_ref<jobject> &javaUIManager, const ShadowViewMutation &mutation) {
+ static auto removeInstruction =
+ jni::findClassStatic(UIManagerJavaDescriptor)
+ ->getMethod<alias_ref<JMountItem>(jint,jint,jint)>("removeMountItem");
+
+ return removeInstruction(javaUIManager, mutation.oldChildShadowView.tag, mutation.parentShadowView.tag, mutation.index);
+}
+
+local_ref<JMountItem::javaobject> createDeleteMountItem(const jni::global_ref<jobject> &javaUIManager, const ShadowViewMutation &mutation) {
+ static auto deleteInstruction =
+ jni::findClassStatic(UIManagerJavaDescriptor)
+ ->getMethod<alias_ref<JMountItem>(jint)>("deleteMountItem");
+
+ return deleteInstruction(javaUIManager, mutation.oldChildShadowView.tag);
+}
+
+void Binding::schedulerDidFinishTransaction(const Tag rootTag, const ShadowViewMutationList &mutations, const long commitStartTime, const long layoutTime) {
+ SystraceSection s("FabricUIManager::schedulerDidFinishTransaction");
+ std::vector<local_ref<jobject>> queue;
+ // Upper bound estimation of mount items to be delivered to Java side.
+ int size = mutations.size() * 3 + 42;
+
+ long finishTransactionStartTime = getTime();
+
+
+ local_ref<JArrayClass<JMountItem::javaobject>> mountItemsArray = JArrayClass<JMountItem::javaobject>::newArray(size);
+
+ auto mountItems = *(mountItemsArray);
+
+ int position = 0;
+ for (const auto &mutation : mutations) {
+ auto oldChildShadowView = mutation.oldChildShadowView;
+ auto newChildShadowView = mutation.newChildShadowView;
+
+ bool isVirtual = newChildShadowView.layoutMetrics == EmptyLayoutMetrics &&
+ oldChildShadowView.layoutMetrics == EmptyLayoutMetrics;
+
+ switch (mutation.type) {
+ case ShadowViewMutation::Create: {
+ mountItems[position++] = createCreateMountItem(javaUIManager_, mutation, rootTag);
+ break;
+ }
+ case ShadowViewMutation::Remove: {
+ if (!isVirtual) {
+ mountItems[position++] = createRemoveMountItem(javaUIManager_, mutation);
+ }
+ break;
+ }
+ case ShadowViewMutation::Delete: {
+ mountItems[position++] = createDeleteMountItem(javaUIManager_, mutation);
+ break;
+ }
+ case ShadowViewMutation::Update: {
+ if (!isVirtual) {
+ if (mutation.oldChildShadowView.props != mutation.newChildShadowView.props) {
+ mountItems[position++] = createUpdatePropsMountItem(javaUIManager_, mutation);
+ }
+ if (mutation.oldChildShadowView.localData != mutation.newChildShadowView.localData) {
+ mountItems[position++] = createUpdateLocalData(javaUIManager_, mutation);
+ }
+
+ auto updateLayoutMountItem = createUpdateLayoutMountItem(javaUIManager_, mutation);
+ if (updateLayoutMountItem) {
+ mountItems[position++] = updateLayoutMountItem;
+ }
+ }
+
+ if (mutation.oldChildShadowView.eventEmitter != mutation.newChildShadowView.eventEmitter) {
+ auto updateEventEmitterMountItem = createUpdateEventEmitterMountItem(javaUIManager_, mutation);
+ if (updateEventEmitterMountItem) {
+ mountItems[position++] = updateEventEmitterMountItem;
+ }
+ }
+ break;
+ }
+ case ShadowViewMutation::Insert: {
+ if (!isVirtual) {
+ mountItems[position++] = createInsertMountItem(javaUIManager_, mutation);
+
+ mountItems[position++] = createUpdatePropsMountItem(javaUIManager_, mutation);
+
+ auto updateLayoutMountItem = createUpdateLayoutMountItem(javaUIManager_, mutation);
+ if (updateLayoutMountItem) {
+ mountItems[position++] = updateLayoutMountItem;
+ }
+
+ if (mutation.newChildShadowView.localData) {
+ mountItems[position++] = createUpdateLocalData(javaUIManager_, mutation);
+ }
+ }
+
+ auto updateEventEmitterMountItem = createUpdateEventEmitterMountItem(javaUIManager_, mutation);
+ if (updateEventEmitterMountItem) {
+ mountItems[position++] = updateEventEmitterMountItem;
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+
+ static auto createMountItemsBatchContainer =
+ jni::findClassStatic(UIManagerJavaDescriptor)
+ ->getMethod<alias_ref<JMountItem>(jtypeArray<JMountItem::javaobject>,jint)>("createBatchMountItem");
+
+ auto batch = createMountItemsBatchContainer(javaUIManager_, mountItemsArray.get(), position);
+
+ static auto scheduleMountItems =
+ jni::findClassStatic(UIManagerJavaDescriptor)
+ ->getMethod<void(JMountItem::javaobject,jlong,jlong,jlong)>("scheduleMountItems");
+
+ scheduleMountItems(javaUIManager_, batch.get(), commitStartTime, layoutTime, finishTransactionStartTime);
+}
+
+void Binding::setPixelDensity(float pointScaleFactor) {
+ pointScaleFactor_ = pointScaleFactor;
+}
+
+void Binding::schedulerDidRequestPreliminaryViewAllocation(const SurfaceId surfaceId, const ComponentName componentName, bool isLayoutable, const ComponentHandle componentHandle) {
+ if (isLayoutable) {
+ static auto preallocateView =
+ jni::findClassStatic(UIManagerJavaDescriptor)
+ ->getMethod<void(jint,jstring)>("preallocateView");
+
+ preallocateView(javaUIManager_, surfaceId, make_jstring(componentName).get());
+ }
+}
+
+void Binding::registerNatives() {
+ registerHybrid({
+ makeNativeMethod("initHybrid", Binding::initHybrid),
+ makeNativeMethod("installFabricUIManager", Binding::installFabricUIManager),
+ makeNativeMethod("startSurface", Binding::startSurface),
+ makeNativeMethod("renderTemplateToSurface", Binding::renderTemplateToSurface),
+ makeNativeMethod("stopSurface", Binding::stopSurface),
+ makeNativeMethod("setConstraints", Binding::setConstraints),
+ makeNativeMethod("setPixelDensity", Binding::setPixelDensity),
+ makeNativeMethod("uninstallFabricUIManager", Binding::uninstallFabricUIManager)
+ });
+}
+
+}
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.h

@@ -0,0 +1,60 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+// This source code is licensed under the MIT license found in the
+// LICENSE file in the root directory of this source tree.
+
+#pragma once
+
+#include "ComponentFactoryDelegate.h"
+#include "EventBeatManager.h"
+#include <memory>
+#include <fb/fbjni.h>
+#include <react/jni/JMessageQueueThread.h>
+#include <react/jni/ReadableNativeMap.h>
+#include <react/uimanager/Scheduler.h>
+#include <react/uimanager/SchedulerDelegate.h>
+#include <mutex>
+
+namespace facebook {
+namespace react {
+
+class Instance;
+
+class Binding : public jni::HybridClass<Binding>, public SchedulerDelegate {
+public:
+ constexpr static const char *const kJavaDescriptor =
+ "Lcom/facebook/react/fabric/jsi/Binding;";
+
+ static void registerNatives();
+
+ jni::global_ref<jobject> javaUIManager_;
+
+ std::shared_ptr<Scheduler> scheduler_;
+
+ float pointScaleFactor_ = 1;
+
+private:
+
+ void setConstraints(jint rootTag, jfloat minWidth, jfloat maxWidth, jfloat minHeight, jfloat maxHeight);
+
+ static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jclass>);
+
+ void installFabricUIManager(jlong jsContextNativePointer, jni::alias_ref<jobject> javaUIManager, EventBeatManager* eventBeatManager, jni::alias_ref<JavaMessageQueueThread::javaobject> jsMessageQueueThread, ComponentFactoryDelegate* componentsRegistry, jni::alias_ref<jobject> reactNativeConfig);
+
+ void startSurface(jint surfaceId, NativeMap *initialProps);
+
+ void renderTemplateToSurface(jint surfaceId, jstring uiTemplate);
+
+ void stopSurface(jint surfaceId);
+
+ void schedulerDidFinishTransaction(const Tag rootTag, const ShadowViewMutationList &mutations, const long commitStartTime, const long layoutTime);
+
+ void schedulerDidRequestPreliminaryViewAllocation(const SurfaceId surfaceId, const ComponentName componentName, bool isLayoutable, const ComponentHandle componentHandle);
+
+ void setPixelDensity(float pointScaleFactor);
+
+ void uninstallFabricUIManager();
+
+};
+
+}
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/BUCK

@@ -0,0 +1,40 @@
+load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "FBJNI_TARGET", "react_native_target", "react_native_xplat_target", "rn_xplat_cxx_library", "subdir_glob")
+
+rn_xplat_cxx_library(
+ name = "jni",
+ srcs = glob(["*.cpp"]),
+ headers = glob(["*.h"]),
+ header_namespace = "",
+ exported_headers = subdir_glob(
+ [
+ ("", "**/*.h"),
+ ],
+ prefix = "react/fabric",
+ ),
+ compiler_flags = [
+ "-Wall",
+ "-fexceptions",
+ "-std=gnu++1y",
+ "-frtti",
+ ],
+ fbandroid_allow_jni_merging = True,
+ platforms = (ANDROID),
+ preprocessor_flags = [
+ "-DLOG_TAG=\"ReactNative\"",
+ "-DWITH_FBSYSTRACE=1",
+ ],
+ soname = "libfabricjni.$(ext)",
+ visibility = ["PUBLIC"],
+ deps = [
+ react_native_xplat_target("config:config"),
+ react_native_xplat_target("fabric/uimanager:uimanager"),
+ react_native_xplat_target("fabric/components/scrollview:scrollview"),
+ react_native_target("jni/react/jni:jni"),
+ "xplat//fbsystrace:fbsystrace",
+ "xplat//folly:molly",
+ "xplat//jsi:JSIDynamic",
+ "xplat//jsi:jsi",
+ "xplat//third-party/linker_lib:atomic",
+ FBJNI_TARGET,
+ ],
+)

ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/ComponentFactoryDelegate.cpp

@@ -0,0 +1,27 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+// This source code is licensed under the MIT license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include "ComponentFactoryDelegate.h"
+#include <android/log.h>
+#include <react/uimanager/ComponentDescriptorRegistry.h>
+#include <fb/fbjni.h>
+#include <jsi/jsi.h>
+
+using namespace facebook::jsi;
+
+namespace facebook {
+namespace react {
+
+jni::local_ref<ComponentFactoryDelegate::jhybriddata> ComponentFactoryDelegate::initHybrid(
+ jni::alias_ref<jclass>) {
+ return makeCxxInstance();
+}
+
+void ComponentFactoryDelegate::registerNatives() {
+ registerHybrid({
+ makeNativeMethod("initHybrid", ComponentFactoryDelegate::initHybrid),
+ });
+}
+
+}}

ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/ComponentFactoryDelegate.h

@@ -0,0 +1,38 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+// This source code is licensed under the MIT license found in the
+// LICENSE file in the root directory of this source tree.
+
+#pragma once
+
+#include <react/uimanager/ComponentDescriptorRegistry.h>
+#include <react/uimanager/ContextContainer.h>
+#include <react/uimanager/Scheduler.h>
+#include <fb/fbjni.h>
+#include <jsi/jsi.h>
+#include <mutex>
+#include <unordered_set>
+
+using namespace facebook::jsi;
+
+namespace facebook {
+namespace react {
+
+class Instance;
+
+class ComponentFactoryDelegate : public jni::HybridClass<ComponentFactoryDelegate> {
+public:
+ constexpr static const char *const kJavaDescriptor =
+ "Lcom/facebook/react/fabric/jsi/ComponentFactoryDelegate;";
+
+ static void registerNatives();
+
+ ComponentRegistryFactory buildRegistryFunction;
+
+private:
+
+ static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jclass>);
+
+};
+
+}
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/EventBeatManager.cpp

@@ -0,0 +1,47 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+// This source code is licensed under the MIT license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include "EventBeatManager.h"
+#include <fb/fbjni.h>
+using namespace facebook::jni;
+
+namespace facebook {
+namespace react {
+
+EventBeatManager::EventBeatManager(Runtime* runtime, jni::alias_ref<EventBeatManager::jhybriddata> jhybridobject) : runtime_(runtime), jhybridobject_(jhybridobject) { }
+
+jni::local_ref<EventBeatManager::jhybriddata> EventBeatManager::initHybrid(
+ jni::alias_ref<EventBeatManager::jhybriddata> jhybridobject, jlong jsContext) {
+ return makeCxxInstance((Runtime *) jsContext, jhybridobject);
+}
+
+void EventBeatManager::registerEventBeat(EventBeat *eventBeat) const {
+ std::lock_guard<std::mutex> lock(mutex_);
+
+ registeredEventBeats_.insert(eventBeat);
+}
+
+void EventBeatManager::unregisterEventBeat(EventBeat *eventBeat) const {
+ std::lock_guard<std::mutex> lock(mutex_);
+
+ registeredEventBeats_.erase(eventBeat);
+}
+
+void EventBeatManager::beat() {
+ std::lock_guard<std::mutex> lock(mutex_);
+
+ for (const auto eventBeat : registeredEventBeats_) {
+ eventBeat->beat(*runtime_);
+ }
+}
+
+void EventBeatManager::registerNatives() {
+ registerHybrid({
+ makeNativeMethod("initHybrid", EventBeatManager::initHybrid),
+ makeNativeMethod("beat", EventBeatManager::beat),
+ });
+}
+
+}
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/EventBeatManager.h

@@ -0,0 +1,50 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+// This source code is licensed under the MIT license found in the
+// LICENSE file in the root directory of this source tree.
+
+#pragma once
+
+#include <react/events/EventBeat.h>
+#include <fb/fbjni.h>
+#include <jsi/jsi.h>
+#include <mutex>
+#include <unordered_set>
+
+using namespace facebook::jsi;
+
+namespace facebook {
+namespace react {
+
+class Instance;
+
+class EventBeatManager : public jni::HybridClass<EventBeatManager> {
+public:
+ constexpr static const char *const kJavaDescriptor =
+ "Lcom/facebook/react/fabric/jsi/EventBeatManager;";
+
+ static void registerNatives();
+
+ void registerEventBeat(EventBeat *eventBeat) const;
+
+ void unregisterEventBeat(EventBeat *eventBeat) const;
+
+ void beat();
+
+ EventBeatManager(Runtime* runtime, jni::alias_ref<EventBeatManager::jhybriddata> jhybridobject);
+
+private:
+
+ Runtime* runtime_;
+
+ jni::alias_ref<EventBeatManager::jhybriddata> jhybridobject_;
+
+ mutable std::unordered_set<const EventBeat *> registeredEventBeats_ {}; // Protected by `mutex_`
+
+ mutable std::mutex mutex_;
+
+ static jni::local_ref<EventBeatManager::jhybriddata> initHybrid(jni::alias_ref<EventBeatManager::jhybriddata> jhybridobject, jlong jsContext);
+
+};
+
+}
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/EventEmitterWrapper.cpp

@@ -0,0 +1,30 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+// This source code is licensed under the MIT license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include "EventEmitterWrapper.h"
+#include <fb/fbjni.h>
+
+using namespace facebook::jni;
+
+namespace facebook {
+namespace react {
+
+jni::local_ref<EventEmitterWrapper::jhybriddata> EventEmitterWrapper::initHybrid(
+ jni::alias_ref<jclass>) {
+ return makeCxxInstance();
+}
+
+void EventEmitterWrapper::invokeEvent(std::string eventName, NativeMap *payload) {
+ eventEmitter->dispatchEvent(eventName, payload->consume(), EventPriority::AsynchronousBatched);
+}
+
+void EventEmitterWrapper::registerNatives() {
+ registerHybrid({
+ makeNativeMethod("initHybrid", EventEmitterWrapper::initHybrid),
+ makeNativeMethod("invokeEvent", EventEmitterWrapper::invokeEvent),
+ });
+}
+
+}
+}
\ No newline at end of file

ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/EventEmitterWrapper.h

@@ -0,0 +1,34 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+// This source code is licensed under the MIT license found in the
+// LICENSE file in the root directory of this source tree.
+
+#pragma once
+
+#include <fb/fbjni.h>
+#include <react/events/EventEmitter.h>
+#include <react/jni/ReadableNativeMap.h>
+
+namespace facebook {
+namespace react {
+
+class Instance;
+
+class EventEmitterWrapper : public jni::HybridClass<EventEmitterWrapper> {
+public:
+ constexpr static const char *const kJavaDescriptor =
+ "Lcom/facebook/react/fabric/jsi/EventEmitterWrapper;";
+
+ static void registerNatives();
+
+ SharedEventEmitter eventEmitter;
+
+ void invokeEvent(std::string eventName, NativeMap *params);
+
+private:
+
+ static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jclass>);
+
+};
+
+}
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/OnLoad.cpp

@@ -0,0 +1,20 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+// This source code is licensed under the MIT license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <fb/fbjni.h>
+#include <fb/xplat_init.h>
+
+#include "Binding.h"
+#include "EventBeatManager.h"
+#include "EventEmitterWrapper.h"
+
+JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
+ return facebook::xplat::initialize(vm, [] {
+ facebook::react::Binding::registerNatives();
+ facebook::react::EventBeatManager::registerNatives();
+ facebook::react::EventEmitterWrapper::registerNatives();
+ facebook::react::ComponentFactoryDelegate::registerNatives();
+ });
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/ReactNativeConfigHolder.cpp

@@ -0,0 +1,36 @@
+/**
+ * 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.
+ */
+
+#import "ReactNativeConfigHolder.h"
+
+#include <fb/fbjni.h>
+
+using namespace facebook::react;
+
+bool ReactNativeConfigHolder::getBool(const std::string &param) const {
+ static const auto method = facebook::jni::findClassStatic("com/facebook/react/fabric/ReactNativeConfig")
+ ->getMethod<jboolean(jstring)>("getBool");
+ return method(reactNativeConfig_, facebook::jni::make_jstring(param).get());
+}
+
+std::string ReactNativeConfigHolder::getString(const std::string &param) const {
+ static const auto method = facebook::jni::findClassStatic("com/facebook/react/fabric/ReactNativeConfig")
+ ->getMethod<jstring(jstring)>("getString");
+ return method(reactNativeConfig_, facebook::jni::make_jstring(param).get())->toString();
+}
+
+int64_t ReactNativeConfigHolder::getInt64(const std::string &param) const {
+ static const auto method = facebook::jni::findClassStatic("com/facebook/react/fabric/ReactNativeConfig")
+ ->getMethod<jint(jstring)>("getInt64");
+ return method(reactNativeConfig_, facebook::jni::make_jstring(param).get());
+}
+
+double ReactNativeConfigHolder::getDouble(const std::string &param) const {
+ static const auto method = facebook::jni::findClassStatic("com/facebook/react/fabric/ReactNativeConfig")
+ ->getMethod<jdouble(jstring)>("getDouble");
+ return method(reactNativeConfig_, facebook::jni::make_jstring(param).get());
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/ReactNativeConfigHolder.h

@@ -0,0 +1,36 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <fb/fbjni.h>
+#include <react/jni/JMessageQueueThread.h>
+#include <react/jni/ReadableNativeMap.h>
+#include <react/config/ReactNativeConfig.h>
+
+namespace facebook {
+namespace react {
+
+/**
+ * Implementation of ReactNativeConfig that wraps a FabricMobileConfig Java object.
+ */
+class ReactNativeConfigHolder : public ReactNativeConfig {
+public:
+ ReactNativeConfigHolder(jni::alias_ref<jobject> reactNativeConfig) : reactNativeConfig_(reactNativeConfig) {};
+
+ bool getBool(const std::string &param) const override;
+ std::string getString(const std::string &param) const override;
+ int64_t getInt64(const std::string &param) const override;
+ double getDouble(const std::string &param) const override;
+
+private:
+ jni::alias_ref<jobject> reactNativeConfig_;
+};
+
+} // namespace react
+} // namespace facebook

ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/ContextBasedViewPool.java

@@ -0,0 +1,53 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * <p>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.fabric.mounting;
+
+import android.support.annotation.UiThread;
+import android.view.View;
+import com.facebook.react.bridge.UiThreadUtil;
+import com.facebook.react.uimanager.ThemedReactContext;
+import com.facebook.react.uimanager.ViewManagerRegistry;
+import java.util.WeakHashMap;
+
+/** Class that provides pool for views based on {@link ThemedReactContext}. */
+public final class ContextBasedViewPool {
+ private final WeakHashMap<ThemedReactContext, ViewPool> mContextViewPoolHashMap =
+ new WeakHashMap<>();
+ private final ViewManagerRegistry mViewManagerRegistry;
+
+ ContextBasedViewPool(ViewManagerRegistry viewManagerRegistry) {
+ mViewManagerRegistry = viewManagerRegistry;
+ }
+
+ @UiThread
+ void createView(ThemedReactContext context, String componentName) {
+ UiThreadUtil.assertOnUiThread();
+ getViewPool(context).createView(componentName, context);
+ }
+
+ @UiThread
+ View getOrCreateView(String componentName, ThemedReactContext context) {
+ UiThreadUtil.assertOnUiThread();
+ return getViewPool(context).getOrCreateView(componentName, context);
+ }
+
+ @UiThread
+ void returnToPool(ThemedReactContext context, String componentName, View view) {
+ UiThreadUtil.assertOnUiThread();
+ getViewPool(context).returnToPool(componentName, view);
+ }
+
+ @UiThread
+ private ViewPool getViewPool(ThemedReactContext context) {
+ ViewPool pool = mContextViewPoolHashMap.get(context);
+ if (pool == null) {
+ pool = new ViewPool(mViewManagerRegistry);
+ mContextViewPoolHashMap.put(context, pool);
+ }
+ return pool;
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/LayoutMetricsConversions.java

@@ -0,0 +1,57 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * <p>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.fabric.mounting;
+
+import static android.view.View.MeasureSpec.EXACTLY;
+
+import android.view.View;
+import com.facebook.react.uimanager.PixelUtil;
+import com.facebook.yoga.YogaMeasureMode;
+
+public class LayoutMetricsConversions {
+
+ // Represents the Layout constraint mode "undefined" from React side.
+ public static final int REACT_CONSTRAINT_UNDEFINED = -2147483648;
+
+ public static float getMinSize(int viewMeasureSpec) {
+ int mode = View.MeasureSpec.getMode(viewMeasureSpec);
+ int size = View.MeasureSpec.getSize(viewMeasureSpec);
+
+ return mode == EXACTLY ? size : 0f;
+ }
+
+ public static float getMaxSize(int viewMeasureSpec) {
+ int mode = View.MeasureSpec.getMode(viewMeasureSpec);
+ int size = View.MeasureSpec.getSize(viewMeasureSpec);
+
+ return mode == View.MeasureSpec.UNSPECIFIED ? REACT_CONSTRAINT_UNDEFINED : size;
+ }
+
+ public static float getYogaSize(float minSize, float maxSize) {
+ float yogaSize;
+ if (minSize == maxSize) {
+ yogaSize = PixelUtil.toPixelFromDIP(maxSize);
+ } else if (maxSize == REACT_CONSTRAINT_UNDEFINED) {
+ yogaSize = 0;
+ } else {
+ yogaSize = PixelUtil.toPixelFromDIP(maxSize);
+ }
+ return yogaSize;
+ }
+
+ public static YogaMeasureMode getYogaMeasureMode(float minSize, float maxSize) {
+ YogaMeasureMode yogaMeasureMode;
+ if (minSize == maxSize) {
+ yogaMeasureMode = YogaMeasureMode.EXACTLY;
+ } else if (maxSize == REACT_CONSTRAINT_UNDEFINED) {
+ yogaMeasureMode = YogaMeasureMode.UNDEFINED;
+ } else {
+ yogaMeasureMode = YogaMeasureMode.AT_MOST;
+ }
+ return yogaMeasureMode;
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java

@@ -0,0 +1,334 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * <p>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.fabric.mounting;
+
+import android.content.Context;
+import android.support.annotation.AnyThread;
+import android.support.annotation.Nullable;
+import android.support.annotation.UiThread;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import com.facebook.react.fabric.FabricUIManager;
+import com.facebook.react.fabric.jsi.EventEmitterWrapper;
+import com.facebook.react.fabric.mounting.mountitems.MountItem;
+import com.facebook.infer.annotation.Assertions;
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.ReadableNativeMap;
+import com.facebook.react.bridge.SoftAssertions;
+import com.facebook.react.bridge.UiThreadUtil;
+import com.facebook.react.uimanager.IllegalViewOperationException;
+import com.facebook.react.uimanager.ReactStylesDiffMap;
+import com.facebook.react.uimanager.RootView;
+import com.facebook.react.uimanager.RootViewManager;
+import com.facebook.react.uimanager.ThemedReactContext;
+import com.facebook.react.uimanager.ViewGroupManager;
+import com.facebook.react.uimanager.ViewManager;
+import com.facebook.react.uimanager.ViewManagerRegistry;
+import com.facebook.react.uimanager.common.SizeMonitoringFrameLayout;
+import com.facebook.yoga.YogaMeasureMode;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Class responsible for actually dispatching view updates enqueued via {@link
+ * FabricUIManager#scheduleMountItems(int, MountItem[])} on the UI thread.
+ */
+public class MountingManager {
+
+ private final ConcurrentHashMap<Integer, ViewState> mTagToViewState;
+ private final ViewManagerRegistry mViewManagerRegistry;
+ private final RootViewManager mRootViewManager = new RootViewManager();
+ private final ContextBasedViewPool mViewPool;
+
+ public MountingManager(ViewManagerRegistry viewManagerRegistry) {
+ mTagToViewState = new ConcurrentHashMap<>();
+ mViewManagerRegistry = viewManagerRegistry;
+ mViewPool = new ContextBasedViewPool(viewManagerRegistry);
+ }
+
+ @UiThread
+ public void addRootView(int reactRootTag, SizeMonitoringFrameLayout rootView) {
+ if (rootView.getId() != View.NO_ID) {
+ throw new IllegalViewOperationException(
+ "Trying to add a root view with an explicit id already set. React Native uses "
+ + "the id field to track react tags and will overwrite this field. If that is fine, "
+ + "explicitly overwrite the id field to View.NO_ID before calling addRootView.");
+ }
+
+ mTagToViewState.put(
+ reactRootTag, new ViewState(reactRootTag, rootView, mRootViewManager, true));
+ rootView.setId(reactRootTag);
+ }
+
+ /** Releases all references to given native View. */
+ @UiThread
+ private void dropView(View view) {
+ UiThreadUtil.assertOnUiThread();
+
+ int reactTag = view.getId();
+ ViewState state = getViewState(reactTag);
+ ViewManager viewManager = state.mViewManager;
+
+ if (!state.mIsRoot && viewManager != null) {
+ // For non-root views we notify viewmanager with {@link ViewManager#onDropInstance}
+ viewManager.onDropViewInstance(view);
+ }
+ if (view instanceof ViewGroup && viewManager instanceof ViewGroupManager) {
+ ViewGroup viewGroup = (ViewGroup) view;
+ ViewGroupManager<ViewGroup> viewGroupManager = getViewGroupManager(state);
+ for (int i = viewGroupManager.getChildCount(viewGroup) - 1; i >= 0; i--) {
+ View child = viewGroupManager.getChildAt(viewGroup, i);
+ if (mTagToViewState.get(child.getId()) != null) {
+ dropView(child);
+ }
+ viewGroupManager.removeViewAt(viewGroup, i);
+ }
+ }
+
+ mTagToViewState.remove(reactTag);
+ Context context = view.getContext();
+ mViewPool.returnToPool(
+ (ThemedReactContext) context, Assertions.assertNotNull(viewManager).getName(), view);
+ }
+
+ /** Releases all references to react root tag. */
+ @UiThread
+ public void removeRootView(int reactRootTag) {
+ UiThreadUtil.assertOnUiThread();
+ ViewState viewState = mTagToViewState.get(reactRootTag);
+ if (viewState == null || !viewState.mIsRoot) {
+ SoftAssertions.assertUnreachable(
+ "View with tag " + reactRootTag + " is not registered as a root view");
+ }
+ if (viewState.mView != null) {
+ dropView(viewState.mView);
+ }
+ }
+
+ @UiThread
+ public void addViewAt(int parentTag, int tag, int index) {
+ UiThreadUtil.assertOnUiThread();
+ ViewState parentViewState = getViewState(parentTag);
+ final ViewGroup parentView = (ViewGroup) parentViewState.mView;
+ final View view = getViewState(tag).mView;
+ if (view == null) {
+ throw new IllegalStateException("Unable to find view for tag " + tag);
+ }
+ getViewGroupManager(parentViewState).addView(parentView, view, index);
+ }
+
+ private ViewState getViewState(int tag) {
+ ViewState viewState = mTagToViewState.get(tag);
+ if (viewState == null) {
+ throw new IllegalStateException("Unable to find viewState for tag " + tag);
+ }
+ return viewState;
+ }
+
+ public void receiveCommand(int reactTag, int commandId, @Nullable ReadableArray commandArgs) {
+ ViewState viewState = getViewState(reactTag);
+
+ if (viewState.mViewManager == null) {
+ throw new IllegalStateException("Unable to find viewState manager for tag " + reactTag);
+ }
+
+ if (viewState.mView == null) {
+ throw new IllegalStateException("Unable to find viewState view for tag " + reactTag);
+ }
+
+ viewState.mViewManager.receiveCommand(viewState.mView, commandId, commandArgs);
+ }
+
+ @SuppressWarnings("unchecked") // prevents unchecked conversion warn of the <ViewGroup> type
+ private static ViewGroupManager<ViewGroup> getViewGroupManager(ViewState viewState) {
+ if (viewState.mViewManager == null) {
+ throw new IllegalStateException("Unable to find ViewManager");
+ }
+ return (ViewGroupManager<ViewGroup>) viewState.mViewManager;
+ }
+
+ @UiThread
+ public void removeViewAt(int parentTag, int index) {
+ UiThreadUtil.assertOnUiThread();
+ ViewState viewState = getViewState(parentTag);
+ final ViewGroup parentView = (ViewGroup) viewState.mView;
+ if (parentView == null) {
+ throw new IllegalStateException("Unable to find view for tag " + parentTag);
+ }
+
+ getViewGroupManager(viewState).removeViewAt(parentView, index);
+ }
+
+ @UiThread
+ public void createView(
+ ThemedReactContext themedReactContext,
+ String componentName,
+ int reactTag,
+ boolean isVirtual) {
+ UiThreadUtil.assertOnUiThread();
+ View view = null;
+ ViewManager viewManager = null;
+ if (!isVirtual) {
+ viewManager = mViewManagerRegistry.get(componentName);
+ view = mViewPool.getOrCreateView(componentName, themedReactContext);
+ view.setId(reactTag);
+ }
+
+ mTagToViewState.put(reactTag, new ViewState(reactTag, view, viewManager));
+ }
+
+ @UiThread
+ public void updateProps(int reactTag, ReadableMap props) {
+ if (props == null) {
+ return;
+ }
+ UiThreadUtil.assertOnUiThread();
+ ViewState viewState = getViewState(reactTag);
+ viewState.mCurrentProps = new ReactStylesDiffMap(props);
+ View view = viewState.mView;
+
+ if (view == null) {
+ throw new IllegalStateException("Unable to find view for tag " + reactTag);
+ }
+
+ Assertions.assertNotNull(viewState.mViewManager)
+ .updateProperties(view, viewState.mCurrentProps);
+ }
+
+ @UiThread
+ public void updateLayout(int reactTag, int x, int y, int width, int height) {
+ UiThreadUtil.assertOnUiThread();
+
+ ViewState viewState = getViewState(reactTag);
+ // Do not layout Root Views
+ if (viewState.mIsRoot) {
+ return;
+ }
+
+ View viewToUpdate = viewState.mView;
+ if (viewToUpdate == null) {
+ throw new IllegalStateException("Unable to find View for tag: " + reactTag);
+ }
+
+ viewToUpdate.measure(
+ View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
+ View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
+
+ ViewParent parent = viewToUpdate.getParent();
+ if (parent instanceof RootView) {
+ parent.requestLayout();
+ }
+
+ // TODO: T31905686 Check if the parent of the view has to layout the view, or the child has
+ // to lay itself out. see NativeViewHierarchyManager.updateLayout
+ viewToUpdate.layout(x, y, x + width, y + height);
+ }
+
+ @UiThread
+ public void deleteView(int reactTag) {
+ UiThreadUtil.assertOnUiThread();
+ View view = getViewState(reactTag).mView;
+ if (view != null) {
+ dropView(view);
+ } else {
+ mTagToViewState.remove(reactTag);
+ }
+ }
+
+ @UiThread
+ public void updateLocalData(int reactTag, ReadableMap newLocalData) {
+ UiThreadUtil.assertOnUiThread();
+ ViewState viewState = getViewState(reactTag);
+ if (viewState.mCurrentProps == null) {
+ throw new IllegalStateException(
+ "Can not update local data to view without props: " + reactTag);
+ }
+ if (viewState.mCurrentLocalData != null
+ && newLocalData.hasKey("hash")
+ && viewState.mCurrentLocalData.getDouble("hash") == newLocalData.getDouble("hash")
+ && viewState.mCurrentLocalData.toString().equals(newLocalData.toString())) {
+ // TODO: T31905686 implement a proper equality method
+ return;
+ }
+ viewState.mCurrentLocalData = newLocalData;
+
+ ViewManager viewManager = viewState.mViewManager;
+
+ if (viewManager == null) {
+ throw new IllegalStateException("Unable to find ViewManager for tag: " + reactTag);
+ }
+ Object extraData =
+ viewManager.updateLocalData(
+ viewState.mView,
+ viewState.mCurrentProps,
+ new ReactStylesDiffMap(viewState.mCurrentLocalData));
+ if (extraData != null) {
+ viewManager.updateExtraData(viewState.mView, extraData);
+ }
+ }
+
+ @UiThread
+ public void preallocateView(ThemedReactContext reactContext, String componentName) {
+ mViewPool.createView(reactContext, componentName);
+ }
+
+ @UiThread
+ public void updateEventEmitter(int reactTag, EventEmitterWrapper eventEmitter) {
+ UiThreadUtil.assertOnUiThread();
+ ViewState viewState = getViewState(reactTag);
+ viewState.mEventEmitter = eventEmitter;
+ }
+
+ @AnyThread
+ public long measure(
+ ReactContext context,
+ String componentName,
+ ReadableNativeMap localData,
+ ReadableNativeMap props,
+ float width,
+ YogaMeasureMode widthMode,
+ float height,
+ YogaMeasureMode heightMode) {
+
+ return mViewManagerRegistry
+ .get(componentName)
+ .measure(context, localData, props, width, widthMode, height, heightMode);
+ }
+
+ @AnyThread
+ public @Nullable EventEmitterWrapper getEventEmitter(int reactTag) {
+ ViewState viewState = mTagToViewState.get(reactTag);
+ return viewState == null ? null : viewState.mEventEmitter;
+ }
+
+ /**
+ * This class holds view state for react tags. Objects of this class are stored into the {@link
+ * #mTagToViewState}, and they should be updated in the same thread.
+ */
+ private static class ViewState {
+ @Nullable final View mView;
+ final int mReactTag;
+ final boolean mIsRoot;
+ @Nullable final ViewManager mViewManager;
+ public ReactStylesDiffMap mCurrentProps;
+ public ReadableMap mCurrentLocalData;
+ public EventEmitterWrapper mEventEmitter;
+
+ private ViewState(int reactTag, @Nullable View view, @Nullable ViewManager viewManager) {
+ this(reactTag, view, viewManager, false);
+ }
+
+ private ViewState(int reactTag, @Nullable View view, ViewManager viewManager, boolean isRoot) {
+ mReactTag = reactTag;
+ mView = view;
+ mIsRoot = isRoot;
+ mViewManager = viewManager;
+ }
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/BatchMountItem.java

@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * <p>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.fabric.mounting.mountitems;
+
+import com.facebook.proguard.annotations.DoNotStrip;
+import com.facebook.react.fabric.mounting.MountingManager;
+import com.facebook.systrace.Systrace;
+
+/**
+ * This class represents a batch of {@link MountItem}s
+ *
+ * <p>A MountItem batch contains an array of {@link MountItem} and a size. The size determines the
+ * amount of items that needs to be processed in the array.
+ *
+ * <p>The purpose of encapsulating the array of MountItems this way, is to reduce the amount of
+ * allocations in C++
+ */
+@DoNotStrip
+public class BatchMountItem implements MountItem {
+
+ private final MountItem[] mMountItems;
+ private final int mSize;
+
+ public BatchMountItem(MountItem[] items, int size) {
+ if (items == null) {
+ throw new NullPointerException();
+ }
+ if (size < 0 || size > items.length) {
+ throw new IllegalArgumentException(
+ "Invalid size received by parameter size: " + size + " items.size = " + items.length);
+ }
+ mMountItems = items;
+ mSize = size;
+ }
+
+ @Override
+ public void execute(MountingManager mountingManager) {
+ Systrace.beginSection(
+ Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "FabricUIManager::mountViews (" + mSize + " items)");
+
+ for (int mountItemIndex = 0; mountItemIndex < mSize; mountItemIndex++) {
+ MountItem mountItem = mMountItems[mountItemIndex];
+ mountItem.execute(mountingManager);
+ }
+
+ Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/CreateMountItem.java

@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * <p>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.fabric.mounting.mountitems;
+
+import com.facebook.react.fabric.mounting.MountingManager;
+import com.facebook.react.uimanager.ThemedReactContext;
+
+public class CreateMountItem implements MountItem {
+
+ private final String mComponentName;
+ private final int mReactTag;
+ private final ThemedReactContext mThemedReactContext;
+ private final boolean mIsVirtual;
+
+ public CreateMountItem(
+ ThemedReactContext themedReactContext,
+ String componentName,
+ int reactTag,
+ boolean isVirtual) {
+ mReactTag = reactTag;
+ mThemedReactContext = themedReactContext;
+ mComponentName = componentName;
+ mIsVirtual = isVirtual;
+ }
+
+ @Override
+ public void execute(MountingManager mountingManager) {
+ mountingManager.createView(mThemedReactContext, mComponentName, mReactTag, mIsVirtual);
+ }
+
+ public String getComponentName() {
+ return mComponentName;
+ }
+
+ public ThemedReactContext getThemedReactContext() {
+ return mThemedReactContext;
+ }
+
+ @Override
+ public String toString() {
+ return "CreateMountItem [" + mReactTag + "] " + mComponentName;
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/DeleteMountItem.java

@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * <p>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.fabric.mounting.mountitems;
+
+import com.facebook.react.fabric.mounting.MountingManager;
+
+public class DeleteMountItem implements MountItem {
+
+ private int mReactTag;
+
+ public DeleteMountItem(int reactTag) {
+ mReactTag = reactTag;
+ }
+
+ @Override
+ public void execute(MountingManager mountingManager) {
+ mountingManager.deleteView(mReactTag);
+ }
+
+ @Override
+ public String toString() {
+ return "DeleteMountItem [" + mReactTag + "]";
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/DispatchCommandMountItem.java

@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * <p>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.fabric.mounting.mountitems;
+
+import android.support.annotation.Nullable;
+import com.facebook.react.fabric.mounting.MountingManager;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.UiThreadUtil;
+
+public class DispatchCommandMountItem implements MountItem {
+
+ private final int mReactTag;
+ private final int mCommandId;
+ private final @Nullable ReadableArray mCommandArgs;
+
+ public DispatchCommandMountItem(
+ int reactTag, int commandId, @Nullable ReadableArray commandArgs) {
+ mReactTag = reactTag;
+ mCommandId = commandId;
+ mCommandArgs = commandArgs;
+ }
+
+ @Override
+ public void execute(MountingManager mountingManager) {
+ UiThreadUtil.assertOnUiThread();
+ mountingManager.receiveCommand(mReactTag, mCommandId, mCommandArgs);
+ }
+
+ @Override
+ public String toString() {
+ return "DispatchCommandMountItem [" + mReactTag + "] " + mCommandId;
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/InsertMountItem.java

@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * <p>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.fabric.mounting.mountitems;
+
+import com.facebook.react.fabric.mounting.MountingManager;
+
+public class InsertMountItem implements MountItem {
+
+ private int mReactTag;
+ private int mParentReactTag;
+ private int mIndex;
+
+ public InsertMountItem(int reactTag, int parentReactTag, int index) {
+ mReactTag = reactTag;
+ mParentReactTag = parentReactTag;
+ mIndex = index;
+ }
+
+ @Override
+ public void execute(MountingManager mountingManager) {
+ mountingManager.addViewAt(mParentReactTag, mReactTag, mIndex);
+ }
+
+ public int getParentReactTag() {
+ return mParentReactTag;
+ }
+
+ public int getIndex() {
+ return mIndex;
+ }
+
+ @Override
+ public String toString() {
+ return "InsertMountItem ["
+ + mReactTag
+ + "] - parentTag: "
+ + mParentReactTag
+ + " - index: "
+ + mIndex;
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/MountItem.java

@@ -0,0 +1,17 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * <p>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.fabric.mounting.mountitems;
+
+import android.support.annotation.UiThread;
+import com.facebook.react.fabric.mounting.MountingManager;
+
+public interface MountItem {
+
+ /** Execute this {@link MountItem} into the operation queue received by parameter. */
+ @UiThread
+ void execute(MountingManager mountingManager);
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/PreAllocateViewMountItem.java

@@ -0,0 +1,36 @@
+/**
+ * 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.fabric.mounting.mountitems;
+
+import com.facebook.react.fabric.mounting.MountingManager;
+import com.facebook.react.uimanager.ThemedReactContext;
+
+/**
+ * {@link MountItem} that is used to pre-allocate views for JS components.
+ */
+public class PreAllocateViewMountItem implements MountItem {
+
+ private final String mComponent;
+ private final int mRootTag;
+ private final ThemedReactContext mContext;
+
+ public PreAllocateViewMountItem(ThemedReactContext context, int rootTag, String component){
+ mContext = context;
+ mComponent = component;
+ mRootTag = rootTag;
+ }
+
+ @Override
+ public void execute(MountingManager mountingManager) {
+ mountingManager.preallocateView(mContext, mComponent);
+ }
+
+ @Override
+ public String toString() {
+ return "[" + mRootTag + "] - Preallocate " + mComponent;
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/RemoveMountItem.java

@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * <p>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.fabric.mounting.mountitems;
+
+import com.facebook.react.fabric.mounting.MountingManager;
+
+public class RemoveMountItem implements MountItem {
+
+ private int mReactTag;
+ private int mParentReactTag;
+ private int mIndex;
+
+ public RemoveMountItem(int reactTag, int parentReactTag, int index) {
+ mReactTag = reactTag;
+ mParentReactTag = parentReactTag;
+ mIndex = index;
+ }
+
+ @Override
+ public void execute(MountingManager mountingManager) {
+ mountingManager.removeViewAt(mParentReactTag, mIndex);
+ }
+
+ public int getParentReactTag() {
+ return mParentReactTag;
+ }
+
+ public int getIndex() {
+ return mIndex;
+ }
+
+ @Override
+ public String toString() {
+ return "RemoveMountItem ["
+ + mReactTag
+ + "] - parentTag: "
+ + mParentReactTag
+ + " - index: "
+ + mIndex;
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateEventEmitterMountItem.java

@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * <p>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.fabric.mounting.mountitems;
+
+import com.facebook.react.fabric.jsi.EventEmitterWrapper;
+import com.facebook.react.fabric.mounting.MountingManager;
+
+public class UpdateEventEmitterMountItem implements MountItem {
+
+ private final EventEmitterWrapper mEventHandler;
+ private final int mReactTag;
+
+ public UpdateEventEmitterMountItem(int reactTag, EventEmitterWrapper EventHandler) {
+ mReactTag = reactTag;
+ mEventHandler = EventHandler;
+ }
+
+ @Override
+ public void execute(MountingManager mountingManager) {
+ mountingManager.updateEventEmitter(mReactTag, mEventHandler);
+ }
+
+ @Override
+ public String toString() {
+ return "UpdateEventEmitterMountItem [" + mReactTag + "]";
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateLayoutMountItem.java

@@ -0,0 +1,61 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * <p>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.fabric.mounting.mountitems;
+
+import com.facebook.react.fabric.mounting.MountingManager;
+
+public class UpdateLayoutMountItem implements MountItem {
+
+ private final int mReactTag;
+ private final int mX;
+ private final int mY;
+ private final int mWidth;
+ private final int mHeight;
+
+ public UpdateLayoutMountItem(int reactTag, int x, int y, int width, int height) {
+ mReactTag = reactTag;
+ mX = x;
+ mY = y;
+ mWidth = width;
+ mHeight = height;
+ }
+
+ @Override
+ public void execute(MountingManager mountingManager) {
+ mountingManager.updateLayout(mReactTag, mX, mY, mWidth, mHeight);
+ }
+
+ public int getX() {
+ return mX;
+ }
+
+ public int getY() {
+ return mY;
+ }
+
+ public int getHeight() {
+ return mHeight;
+ }
+
+ public int getWidth() {
+ return mWidth;
+ }
+
+ @Override
+ public String toString() {
+ return "UpdateLayoutMountItem ["
+ + mReactTag
+ + "] - x: "
+ + mX
+ + " - y: "
+ + mY
+ + " - height: "
+ + mHeight
+ + " - width: "
+ + mWidth;
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateLocalDataMountItem.java

@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * <p>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.fabric.mounting.mountitems;
+
+import com.facebook.react.fabric.mounting.MountingManager;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.ReadableNativeMap;
+
+public class UpdateLocalDataMountItem implements MountItem {
+
+ private final int mReactTag;
+ private final ReadableMap mNewLocalData;
+
+ public UpdateLocalDataMountItem(int reactTag, ReadableNativeMap newLocalData) {
+ mReactTag = reactTag;
+ mNewLocalData = newLocalData;
+ }
+
+ @Override
+ public void execute(MountingManager mountingManager) {
+ mountingManager.updateLocalData(mReactTag, mNewLocalData);
+ }
+
+ public ReadableMap getNewLocalData() {
+ return mNewLocalData;
+ }
+
+ @Override
+ public String toString() {
+ return "UpdateLocalDataMountItem [" + mReactTag + "] - localData: " + mNewLocalData;
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdatePropsMountItem.java

@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * <p>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.fabric.mounting.mountitems;
+
+import com.facebook.react.fabric.mounting.MountingManager;
+import com.facebook.react.bridge.ReadableMap;
+
+public class UpdatePropsMountItem implements MountItem {
+
+ private final int mReactTag;
+ private final ReadableMap mUpdatedProps;
+
+ public UpdatePropsMountItem(int reactTag, ReadableMap updatedProps) {
+ mReactTag = reactTag;
+ mUpdatedProps = updatedProps;
+ }
+
+ @Override
+ public void execute(MountingManager mountingManager) {
+ mountingManager.updateProps(mReactTag, mUpdatedProps);
+ }
+
+ @Override
+ public String toString() {
+ return "UpdatePropsMountItem [" + mReactTag + "] - props: " + mUpdatedProps;
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/ViewPool.java

@@ -0,0 +1,63 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * <p>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.fabric.mounting;
+
+import android.support.annotation.UiThread;
+import android.view.View;
+import com.facebook.react.common.ClearableSynchronizedPool;
+import com.facebook.react.uimanager.ThemedReactContext;
+import com.facebook.react.uimanager.ViewManager;
+import com.facebook.react.uimanager.ViewManagerRegistry;
+import java.util.HashMap;
+import java.util.Map;
+
+public final class ViewPool {
+ private static final int POOL_SIZE = 512;
+ private final Map<String, ClearableSynchronizedPool<View>> mViewPool = new HashMap<>();
+ private final ViewManagerRegistry mViewManagerRegistry;
+
+ ViewPool(ViewManagerRegistry viewManagerRegistry) {
+ mViewManagerRegistry = viewManagerRegistry;
+ }
+
+ @UiThread
+ void createView(String componentName, ThemedReactContext context) {
+ ClearableSynchronizedPool<View> viewPool = getViewPoolForComponent(componentName);
+ ViewManager viewManager = mViewManagerRegistry.get(componentName);
+ // TODO: T31905686 Integrate / re-implement jsResponder
+ View view = viewManager.createView(context, null);
+ viewPool.release(view);
+ }
+
+ @UiThread
+ View getOrCreateView(String componentName, ThemedReactContext context) {
+ ClearableSynchronizedPool<View> viewPool = getViewPoolForComponent(componentName);
+ View view = viewPool.acquire();
+ if (view == null) {
+ createView(componentName, context);
+ view = viewPool.acquire();
+ }
+ return view;
+ }
+
+ @UiThread
+ void returnToPool(String componentName, View view) {
+ ClearableSynchronizedPool<View> viewPool = mViewPool.get(componentName);
+ if (viewPool != null) {
+ viewPool.release(view);
+ }
+ }
+
+ private ClearableSynchronizedPool<View> getViewPoolForComponent(String componentName) {
+ ClearableSynchronizedPool<View> viewPool = mViewPool.get(componentName);
+ if (viewPool == null) {
+ viewPool = new ClearableSynchronizedPool<>(POOL_SIZE);
+ mViewPool.put(componentName, viewPool);
+ }
+ return viewPool;
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/ReactNativeConfig.java

@@ -0,0 +1,38 @@
+/**
+ * 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.fabric;
+
+// This is a wrapper for the ReactNativeConfig object in C++
+public interface ReactNativeConfig {
+ /**
+ * Get a boolean param by string name. Default should be false.
+ *
+ * @param param The string name of the parameter being requested.
+ */
+ boolean getBool(String param);
+
+ /**
+ * Get an integer param by string name. Default should be 0.
+ *
+ * @param param The string name of the parameter being requested.
+ */
+ int getInt64(String param);
+
+ /**
+ * Get a string param by string name. Default should be "", empty string.
+ *
+ * @param param The string name of the parameter being requested.
+ */
+ String getString(String param);
+
+ /**
+ * Get a double param by string name. Default should be 0.
+ *
+ * @param param The string name of the parameter being requested.
+ */
+ double getDouble(String param);
+}

ReactAndroid/src/main/java/com/facebook/react/fabric/RootShadowNodeRegistry.java

@@ -1,46 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-package com.facebook.react.fabric;
-
-import com.facebook.react.uimanager.ReactShadowNode;
-import java.util.concurrent.ConcurrentHashMap;
-import javax.annotation.concurrent.ThreadSafe;
-
-/**
- * Simple container class to keep track of {@link ReactShadowNode}s that represents the Root
- * Shadow Nodes of a {@link FabricUIManager}.
- */
-@ThreadSafe
-public class RootShadowNodeRegistry {
-
- private final ConcurrentHashMap<Integer, ReactShadowNode> mTagsToRootNodes = new ConcurrentHashMap<>();
-
- /**
- * Registers the {@link ReactShadowNode} received as a parameter as a RootShadowNode.
- */
- public synchronized void registerNode(ReactShadowNode node) {
- mTagsToRootNodes.put(node.getReactTag(), node);
- }
-
- /**
- * Register the {@link ReactShadowNode} received as a parameter as a RootShadowNode, replacing
- * the previous RootShadowNode associated for the {@link ReactShadowNode#getReactTag()}
- */
- public void replaceNode(ReactShadowNode node) {
- mTagsToRootNodes.replace(node.getReactTag(), node);
- }
-
- public void removeNode(Integer tag) {
- mTagsToRootNodes.remove(tag);
- }
-
- public ReactShadowNode getNode(int tag) {
- return mTagsToRootNodes.get(tag);
- }
-
-}

ReactAndroid/src/main/java/com/facebook/react/fabric/Scheduler.java

@@ -1,95 +0,0 @@
-package com.facebook.react.fabric;
-
-import com.facebook.common.logging.FLog;
-import com.facebook.react.bridge.ReactContext;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.LinkedBlockingDeque;
-import java.util.concurrent.RejectedExecutionException;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-
-/**
- * This class allows Native code to schedule work in JS.
- * Work (following JS naming) represents a task that needs to be executed in JS.
- *
- * Four types of work are supported by this class:
- *
- * Synchronous:
- * - Sync work -> flushSync()
- * - Work work -> flushSerial()
- *
- * Asynchronous:
- * - Interactive work (serial): -> scheduleSerial()
- * - Deferred work: -> scheduleWork()
- *
- */
-public class Scheduler {
-
- private static final String TAG = Scheduler.class.getSimpleName();
- // The usage of this executor might change in the near future.
- private final ExecutorService mExecutor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingDeque<Runnable>());
- private final ReactContext mReactContext;
-
- public Scheduler(ReactContext reactContext) {
- mReactContext = reactContext;
- }
-
- /**
- * This method schedules work to be executed with the lowest priority in the JS Thread.
- *
- * The current implementation queues "work"s in an unbounded queue tight to a SingleThreadExecutor.
- * Work objects are going to be submitted one-by-one at the end of the JS Queue Thread.
- *
- * Notice that the current implementation might experience some delays in JS work execution,
- * depending on the size of the JS Queue and the time it takes to execute each work in JS.
- *
- * TODO: This implementation is very likely to change in the near future.
- */
- public void scheduleWork(final Work work) {
- try {
- mExecutor.execute(new Runnable() {
- @Override
- public void run() {
- mReactContext.runOnJSQueueThread(new Runnable() {
- @Override
- public void run() {
- try {
- work.run();
- } catch (Exception ex) {
- FLog.w(TAG, "Exception running work in JS.", ex);
- throw ex;
- }
- }
- });
- }
- });
- } catch (RejectedExecutionException ex) {
- // This can happen if a Work is scheduled when the Scheduler is being shutdown.
- // For now, we log and do not take any action.
- FLog.i(TAG, "Unable to schedule task.");
- }
- }
-
- public void flushSync(Work work) {
- // TODO T26717866 this method needs to be implemented. The current implementation is just for
- // testing purpose.
- }
-
- public void flushSerial(Work work) {
- // TODO T26717866 this method needs to be implemented. The current implementation is just for
- // testing purpose.
- }
-
- public void scheduleSerial(Work work) {
- // TODO T26717866 this method needs to be implemented. The current implementation is just for
- // testing purpose.
- }
-
- /**
- * Shutdowns the {@link Scheduler}. this operation will attempt to stop all "active executing"
- * Works items and it will "halts:" all the Works items waiting to be executed.
- */
- public void shutdown() {
- mExecutor.shutdownNow();
- }
-}

ReactAndroid/src/main/java/com/facebook/react/fabric/Work.java

@@ -1,20 +0,0 @@
-/**
- * Copyright (c) 2014-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-package com.facebook.react.fabric;
-
-/**
- * Interface that represents a task or piece of code that will be executed by {@link Scheduler}
- * This follows React API naming for consistency.
- */
-public interface Work {
-
- void run();
-
-}
-
-

ReactAndroid/src/main/java/com/facebook/react/HeadlessJsTaskService.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -12,6 +12,7 @@
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
+import android.annotation.SuppressLint;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -67,6 +68,7 @@
/**
* Acquire a wake lock to ensure the device doesn't go to sleep while processing background tasks.
*/
+ @SuppressLint("WakelockTimeout")
public static void acquireWakeLockNow(Context context) {
if (sWakeLock == null || !sWakeLock.isHeld()) {
PowerManager powerManager =

ReactAndroid/src/main/java/com/facebook/react/jscexecutor/Android.mk

@@ -0,0 +1,21 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := jscexecutor
+
+LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp)
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
+
+LOCAL_CFLAGS += -fvisibility=hidden -fexceptions -frtti
+
+LOCAL_STATIC_LIBRARIES := libjsi libjsireact
+LOCAL_SHARED_LIBRARIES := libfolly_json libfb libreactnativejni
+
+include $(BUILD_SHARED_LIBRARY)

ReactAndroid/src/main/java/com/facebook/react/jscexecutor/BUCK

@@ -0,0 +1,35 @@
+load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "FBJNI_TARGET", "react_native_dep", "react_native_target", "react_native_xplat_target", "rn_android_library", "rn_xplat_cxx_library")
+
+rn_android_library(
+ name = "jscexecutor",
+ srcs = glob(["*.java"]),
+ visibility = [
+ "PUBLIC",
+ ],
+ deps = [
+ ":jni",
+ react_native_dep("libraries/soloader/java/com/facebook/soloader:soloader"),
+ react_native_target("java/com/facebook/react/bridge:bridge"),
+ ],
+)
+
+rn_xplat_cxx_library(
+ name = "jni",
+ srcs = glob(["*.cpp"]),
+ headers = glob(["*.h"]),
+ header_namespace = "",
+ compiler_flags = ["-fexceptions"],
+ fbandroid_allow_jni_merging = True,
+ platforms = ANDROID,
+ soname = "libjscexecutor.$(ext)",
+ visibility = [
+ react_native_target("java/com/facebook/react/jscexecutor:jscexecutor"),
+ ],
+ deps = [
+ "xplat//folly:molly",
+ FBJNI_TARGET,
+ react_native_target("jni/react/jni:jni"),
+ react_native_xplat_target("jsi:JSCRuntime"),
+ react_native_xplat_target("jsiexecutor:jsiexecutor"),
+ ],
+)

ReactAndroid/src/main/java/com/facebook/react/jscexecutor/JSCExecutorFactory.java

@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+package com.facebook.react.jscexecutor;
+
+import com.facebook.react.bridge.JavaScriptExecutor;
+import com.facebook.react.bridge.JavaScriptExecutorFactory;
+import com.facebook.react.bridge.WritableNativeMap;
+
+public class JSCExecutorFactory implements JavaScriptExecutorFactory {
+ private final String mAppName;
+ private final String mDeviceName;
+
+ public JSCExecutorFactory(String appName, String deviceName) {
+ this.mAppName = appName;
+ this.mDeviceName = deviceName;
+ }
+
+ @Override
+ public JavaScriptExecutor create() throws Exception {
+ WritableNativeMap jscConfig = new WritableNativeMap();
+ jscConfig.putString("OwnerIdentity", "ReactNative");
+ jscConfig.putString("AppIdentity", mAppName);
+ jscConfig.putString("DeviceIdentity", mDeviceName);
+ return new JSCExecutor(jscConfig);
+ }
+
+ @Override
+ public String toString() {
+ return "JSIExecutor+JSCRuntime";
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/jscexecutor/JSCExecutor.java

@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * <p>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.jscexecutor;
+
+import com.facebook.jni.HybridData;
+import com.facebook.proguard.annotations.DoNotStrip;
+import com.facebook.react.bridge.JavaScriptExecutor;
+import com.facebook.react.bridge.ReadableNativeMap;
+import com.facebook.soloader.SoLoader;
+
+@DoNotStrip
+/* package */ class JSCExecutor extends JavaScriptExecutor {
+ static {
+ SoLoader.loadLibrary("jscexecutor");
+ }
+
+ /* package */ JSCExecutor(ReadableNativeMap jscConfig) {
+ super(initHybrid(jscConfig));
+ }
+
+ @Override
+ public String getName() {
+ return "JSCExecutor";
+ }
+
+ private static native HybridData initHybrid(ReadableNativeMap jscConfig);
+}

ReactAndroid/src/main/java/com/facebook/react/jscexecutor/OnLoad.cpp

@@ -0,0 +1,73 @@
+// 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.
+
+#include <fb/fbjni.h>
+#include <folly/Memory.h>
+#include <jsi/JSCRuntime.h>
+#include <jsireact/JSIExecutor.h>
+#include <react/jni/JavaScriptExecutorHolder.h>
+#include <react/jni/JReactMarker.h>
+#include <react/jni/JSLogging.h>
+#include <react/jni/ReadableNativeMap.h>
+
+namespace facebook {
+namespace react {
+
+namespace {
+
+class JSCExecutorFactory : public JSExecutorFactory {
+public:
+ std::unique_ptr<JSExecutor> createJSExecutor(
+ std::shared_ptr<ExecutorDelegate> delegate,
+ std::shared_ptr<MessageQueueThread> jsQueue) override {
+ return folly::make_unique<JSIExecutor>(
+ jsc::makeJSCRuntime(),
+ delegate,
+ [](const std::string& message, unsigned int logLevel) {
+ reactAndroidLoggingHook(message, logLevel);
+ },
+ JSIExecutor::defaultTimeoutInvoker,
+ nullptr);
+ }
+};
+
+}
+
+// This is not like JSCJavaScriptExecutor, which calls JSC directly. This uses
+// JSIExecutor with JSCRuntime.
+class JSCExecutorHolder
+ : public jni::HybridClass<JSCExecutorHolder, JavaScriptExecutorHolder> {
+ public:
+ static constexpr auto kJavaDescriptor = "Lcom/facebook/react/jscexecutor/JSCExecutor;";
+
+ static jni::local_ref<jhybriddata> initHybrid(
+ jni::alias_ref<jclass>, ReadableNativeMap*) {
+ // This is kind of a weird place for stuff, but there's no other
+ // good place for initialization which is specific to JSC on
+ // Android.
+ JReactMarker::setLogPerfMarkerIfNeeded();
+ // TODO mhorowitz T28461666 fill in some missing nice to have glue
+ return makeCxxInstance(folly::make_unique<JSCExecutorFactory>());
+ }
+
+ static void registerNatives() {
+ registerHybrid({
+ makeNativeMethod("initHybrid", JSCExecutorHolder::initHybrid),
+ });
+ }
+
+ private:
+ friend HybridBase;
+ using HybridBase::HybridBase;
+};
+
+} // namespace react
+} // namespace facebook
+
+JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
+ return facebook::jni::initialize(vm, [] {
+ facebook::react::JSCExecutorHolder::registerNatives();
+ });
+}

ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskConfig.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskContext.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskEventListener.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/LazyReactPackage.java

@@ -1,14 +1,15 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
+ * <p>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;
import static com.facebook.systrace.Systrace.TRACE_TAG_REACT_JAVA_BRIDGE;
+import android.support.annotation.NonNull;
+import com.facebook.react.bridge.ModuleHolder;
import com.facebook.react.bridge.ModuleSpec;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
@@ -20,13 +21,14 @@
import com.facebook.systrace.SystraceMessage;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* React package supporting lazy creation of native modules.
*
- * TODO(t11394819): Make this default and deprecate ReactPackage
+ * <p>TODO(t11394819): Make this default and deprecate ReactPackage
*/
public abstract class LazyReactPackage implements ReactPackage {
@@ -34,7 +36,8 @@
LazyReactPackage lazyReactPackage) {
Class<?> reactModuleInfoProviderClass;
try {
- reactModuleInfoProviderClass = Class.forName(
+ reactModuleInfoProviderClass =
+ Class.forName(
lazyReactPackage.getClass().getCanonicalName() + "$$ReactModuleInfoProvider");
} catch (ClassNotFoundException e) {
// In OSS case, when the annotation processor does not run, we fall back to non-lazy mode
@@ -50,30 +53,90 @@
}
if (reactModuleInfoProviderClass == null) {
- throw new RuntimeException("ReactModuleInfoProvider class for " +
- lazyReactPackage.getClass().getCanonicalName() + " not found.");
+ throw new RuntimeException(
+ "ReactModuleInfoProvider class for "
+ + lazyReactPackage.getClass().getCanonicalName()
+ + " not found.");
}
try {
return (ReactModuleInfoProvider) reactModuleInfoProviderClass.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException(
- "Unable to instantiate ReactModuleInfoProvider for " + lazyReactPackage.getClass(),
- e);
+ "Unable to instantiate ReactModuleInfoProvider for " + lazyReactPackage.getClass(), e);
} catch (IllegalAccessException e) {
throw new RuntimeException(
- "Unable to instantiate ReactModuleInfoProvider for " + lazyReactPackage.getClass(),
- e);
+ "Unable to instantiate ReactModuleInfoProvider for " + lazyReactPackage.getClass(), e);
}
}
/**
+ * We return an iterable
+ *
+ * @param reactContext
+ * @return
+ */
+ /* package */
+ Iterable<ModuleHolder> getNativeModuleIterator(final ReactApplicationContext reactContext) {
+ final Map<String, ReactModuleInfo> reactModuleInfoMap =
+ getReactModuleInfoProvider().getReactModuleInfos();
+ final List<ModuleSpec> nativeModules = getNativeModules(reactContext);
+
+ return new Iterable<ModuleHolder>() {
+ @NonNull
+ @Override
+ public Iterator<ModuleHolder> iterator() {
+ return new Iterator<ModuleHolder>() {
+ int position = 0;
+
+ @Override
+ public ModuleHolder next() {
+ ModuleSpec moduleSpec = nativeModules.get(position++);
+ String name = moduleSpec.getName();
+ ReactModuleInfo reactModuleInfo = reactModuleInfoMap.get(name);
+ ModuleHolder moduleHolder;
+ if (reactModuleInfo == null) {
+ NativeModule module;
+ ReactMarker.logMarker(ReactMarkerConstants.CREATE_MODULE_START, name);
+ try {
+ module = moduleSpec.getProvider().get();
+ } finally {
+ ReactMarker.logMarker(ReactMarkerConstants.CREATE_MODULE_END);
+ }
+ moduleHolder = new ModuleHolder(module);
+ } else {
+ moduleHolder = new ModuleHolder(reactModuleInfo, moduleSpec.getProvider());
+ }
+ return moduleHolder;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return position < nativeModules.size();
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("Cannot remove native modules from the list");
+ }
+ };
+ }
+ };
+ }
+
+ /**
* @param reactContext react application context that can be used to create modules
* @return list of module specs that can create the native modules
*/
- public abstract List<ModuleSpec> getNativeModules(
- ReactApplicationContext reactContext);
+ protected abstract List<ModuleSpec> getNativeModules(ReactApplicationContext reactContext);
+ /**
+ * This is only used when a LazyReactPackage is a part of {@link CompositeReactPackage} Once we
+ * deprecate {@link CompositeReactPackage}, this can be removed too
+ *
+ * @param reactContext react application context that can be used to create modules
+ * @return
+ */
@Override
public final List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
@@ -82,9 +145,7 @@
SystraceMessage.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "createNativeModule")
.arg("module", holder.getType())
.flush();
- ReactMarker.logMarker(
- ReactMarkerConstants.CREATE_MODULE_START,
- holder.getClassName());
+ ReactMarker.logMarker(ReactMarkerConstants.CREATE_MODULE_START, holder.getName());
try {
nativeModule = holder.getProvider().get();
} finally {

ReactAndroid/src/main/java/com/facebook/react/MemoryPressureRouter.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/module/annotations/BUCK

@@ -10,6 +10,6 @@
deps = [
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"),
+ react_native_target("java/com/facebook/react/bridge:interfaces"),
],
)

ReactAndroid/src/main/java/com/facebook/react/module/annotations/ReactModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,16 +7,14 @@
package com.facebook.react.module.annotations;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-import com.facebook.react.bridge.BaseJavaModule;
-
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
/**
- * Annotation for use on {@link BaseJavaModule}s to describe properties for that module.
+ * Annotation for use on {@link com.facebook.react.bridge.BaseJavaModule}s to describe properties for that module.
*/
@Retention(RUNTIME)
@Target(TYPE)
@@ -44,4 +42,10 @@
* correct annotation is not included
*/
boolean hasConstants() default true;
+
+ /**
+ * Indicates if a module is a C++ module or a Java Module
+ * @return
+ */
+ boolean isCxxModule() default false;
}

ReactAndroid/src/main/java/com/facebook/react/module/annotations/ReactModuleList.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -26,10 +26,4 @@
* @return List of Native modules in the package.
*/
Class<? extends NativeModule>[] nativeModules();
-
- /**
- * The View Managers in this list should be annotated with {@link ReactModule}.
- * @return List of view manager in the package.
- */
- Class<? extends NativeModule>[] viewManagers() default {};
}

ReactAndroid/src/main/java/com/facebook/react/module/model/ReactModuleInfo.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -16,24 +16,32 @@
private final boolean mNeedsEagerInit;
private final boolean mHasConstants;
private final boolean mIsCxxModule;
+ private String mClassName;
+ private final boolean mIsTurboModule;
public ReactModuleInfo(
String name,
+ String className,
boolean canOverrideExistingModule,
boolean needsEagerInit,
boolean hasConstants,
- boolean isCxxModule) {
+ boolean isCxxModule,
+ boolean isTurboModule) {
mName = name;
+ mClassName = className;
mCanOverrideExistingModule = canOverrideExistingModule;
mNeedsEagerInit = needsEagerInit;
mHasConstants = hasConstants;
mIsCxxModule = isCxxModule;
+ mIsTurboModule = isTurboModule;
}
public String name() {
return mName;
}
+ public String className() {return mClassName;}
+
public boolean canOverrideExistingModule() {
return mCanOverrideExistingModule;
}
@@ -48,4 +56,6 @@
public boolean isCxxModule() {return mIsCxxModule; }
+ public boolean isTurboModule() {return mIsTurboModule; }
+
}

ReactAndroid/src/main/java/com/facebook/react/module/model/ReactModuleInfoProvider.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/module/processing/BUCK

@@ -22,7 +22,7 @@
react_native_dep("third-party/java/javapoet:javapoet"),
react_native_dep("third-party/java/jsr-305:jsr-305"),
react_native_target("java/com/facebook/react/module/annotations:annotations"),
- react_native_target("java/com/facebook/react/bridge:bridge"),
react_native_target("java/com/facebook/react/module/model:model"),
+ react_native_target("java/com/facebook/react/turbomodule/core/interfaces:interfaces"),
],
)

ReactAndroid/src/main/java/com/facebook/react/module/processing/ReactModuleSpecProcessor.java

@@ -1,11 +1,34 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.module.processing;
-import com.facebook.react.bridge.CxxModuleWrapper;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.tools.Diagnostic.Kind.ERROR;
+
+import com.facebook.infer.annotation.SuppressFieldNotInitialized;
+import com.facebook.react.module.annotations.ReactModule;
+import com.facebook.react.module.annotations.ReactModuleList;
+import com.facebook.react.module.model.ReactModuleInfo;
+import com.facebook.react.module.model.ReactModuleInfoProvider;
+import com.facebook.react.turbomodule.core.interfaces.TurboModule;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.JavaFile;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterizedTypeName;
+import com.squareup.javapoet.TypeName;
+import com.squareup.javapoet.TypeSpec;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
@@ -14,7 +37,6 @@
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
-import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
@@ -24,31 +46,6 @@
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.stream.Stream;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import com.facebook.infer.annotation.SuppressFieldNotInitialized;
-import com.facebook.react.module.annotations.ReactModule;
-import com.facebook.react.module.annotations.ReactModuleList;
-import com.facebook.react.module.model.ReactModuleInfo;
-import com.facebook.react.module.model.ReactModuleInfoProvider;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.JavaFile;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.ParameterizedTypeName;
-import com.squareup.javapoet.TypeName;
-import com.squareup.javapoet.TypeSpec;
-
-import static javax.lang.model.element.Modifier.PUBLIC;
-import static javax.tools.Diagnostic.Kind.ERROR;
/**
* Generates a list of ReactModuleInfo for modules annotated with {@link ReactModule} in
@@ -152,14 +149,12 @@
private CodeBlock getCodeBlockForReactModuleInfos(List<String> nativeModules)
throws ReactModuleSpecException {
- CodeBlock.Builder builder = CodeBlock.builder();
+ final CodeBlock.Builder builder = CodeBlock.builder();
if (nativeModules == null || nativeModules.isEmpty()) {
builder.addStatement("return $T.emptyMap()", COLLECTIONS_TYPE);
} else {
builder.addStatement("$T map = new $T()", MAP_TYPE, INSTANTIATED_MAP_TYPE);
- TypeMirror cxxModuleWrapperTypeMirror = mElements.getTypeElement(CxxModuleWrapper.class.getName()).asType();
-
for (String nativeModule : nativeModules) {
String keyString = nativeModule;
@@ -177,6 +172,12 @@
"Did you forget to add the @ReactModule annotation to the native module?");
}
+ boolean isTurboModule = isTurboModuleTypeElement(typeElement);
+ if (!isTurboModule) {
+ TypeMirror nativeModuleSpecTypeMirror = typeElement.getSuperclass();
+ isTurboModule = isTurboModuleTypeElement(mElements.getTypeElement(nativeModuleSpecTypeMirror.toString()));
+ }
+
List<? extends Element> elements = typeElement.getEnclosedElements();
boolean hasConstants = false;
if (elements != null) {
@@ -189,25 +190,36 @@
name -> name.contentEquals("getConstants") || name.contentEquals("getTypedExportedConstants"));
}
- boolean isCxxModule = mTypes.isAssignable(typeElement.asType(), cxxModuleWrapperTypeMirror);
-
String valueString = new StringBuilder()
.append("new ReactModuleInfo(")
.append("\"").append(reactModule.name()).append("\"").append(", ")
+ .append("\"").append(keyString).append("\"").append(", ")
.append(reactModule.canOverrideExistingModule()).append(", ")
.append(reactModule.needsEagerInit()).append(", ")
.append(hasConstants).append(", ")
- .append(isCxxModule)
+ .append(reactModule.isCxxModule()).append(", ")
+ .append(isTurboModule)
.append(")")
.toString();
- builder.addStatement("map.put(\"" + keyString + "\", " + valueString + ")");
+ builder.addStatement("map.put(\"" + reactModule.name() + "\", " + valueString + ")");
}
builder.addStatement("return map");
}
return builder.build();
}
+ /**
+ * A Module is a Turbo Module if it either implements TurboModule or its super class,
+ * typically NativeModuleSpec implements TurboMobile
+ */
+ private boolean isTurboModuleTypeElement(TypeElement typeElement) {
+ if (typeElement == null) {
+ return false;
+ }
+ return typeElement.getInterfaces().stream().anyMatch(el -> el.toString().equals(TurboModule.class.getName()));
+ }
+
private static class ReactModuleSpecException extends Exception {
public final String mMessage;

ReactAndroid/src/main/java/com/facebook/react/modules/accessibilityinfo/AccessibilityInfoModule.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -24,11 +24,13 @@
* Module that monitors and provides information about the state of Touch Exploration service
* on the device. For API >= 19.
*/
-@ReactModule(name = "AccessibilityInfo")
+@ReactModule(name = AccessibilityInfoModule.NAME)
public class AccessibilityInfoModule extends ReactContextBaseJavaModule
implements LifecycleEventListener {
- @TargetApi(19)
+ public static final String NAME = "AccessibilityInfo";
+
+ @TargetApi(Build.VERSION_CODES.KITKAT)
private class ReactTouchExplorationStateChangeListener
implements AccessibilityManager.TouchExplorationStateChangeListener {
@@ -49,7 +51,7 @@
Context appContext = context.getApplicationContext();
mAccessibilityManager = (AccessibilityManager) appContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
mEnabled = mAccessibilityManager.isTouchExplorationEnabled();
- if (Build.VERSION.SDK_INT >= 19) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
mTouchExplorationStateChangeListener = new ReactTouchExplorationStateChangeListener();
}
}
@@ -74,7 +76,7 @@
@Override
public void onHostResume() {
- if (Build.VERSION.SDK_INT >= 19) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
mAccessibilityManager.addTouchExplorationStateChangeListener(
mTouchExplorationStateChangeListener);
}
@@ -83,7 +85,7 @@
@Override
public void onHostPause() {
- if (Build.VERSION.SDK_INT >= 19) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
mAccessibilityManager.removeTouchExplorationStateChangeListener(
mTouchExplorationStateChangeListener);
}

ReactAndroid/src/main/java/com/facebook/react/modules/appregistry/AppRegistry.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -14,9 +14,13 @@
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.common.LifecycleState;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter;
+import java.util.HashMap;
+import java.util.Map;
+
@ReactModule(name = AppStateModule.NAME)
public class AppStateModule extends ReactContextBaseJavaModule
implements LifecycleEventListener {
@@ -26,10 +30,15 @@
public static final String APP_STATE_ACTIVE = "active";
public static final String APP_STATE_BACKGROUND = "background";
- private String mAppState = "uninitialized";
+ private static final String INITIAL_STATE = "initialAppState";
+
+ private String mAppState;
public AppStateModule(ReactApplicationContext reactContext) {
super(reactContext);
+ reactContext.addLifecycleEventListener(this);
+ mAppState = (reactContext.getLifecycleState() == LifecycleState.RESUMED ?
+ APP_STATE_ACTIVE : APP_STATE_BACKGROUND);
}
@Override
@@ -38,8 +47,10 @@
}
@Override
- public void initialize() {
- getReactApplicationContext().addLifecycleEventListener(this);
+ public Map<String, Object> getConstants() {
+ HashMap<String, Object> constants = new HashMap<>();
+ constants.put(INITIAL_STATE, mAppState);
+ return constants;
}
@ReactMethod

ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobProvider.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK

@@ -4,7 +4,6 @@
name = "blob",
srcs = glob(["**/*.java"]),
provided_deps = [
- react_native_dep("third-party/android/support-annotations:android-support-annotations"),
react_native_dep("third-party/android/support/v4:lib-support-v4"),
],
visibility = [

ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/camera/CameraRollManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -20,7 +20,7 @@
import android.os.Environment;
import android.provider.MediaStore;
import android.provider.MediaStore.Images;
-import android.provider.MediaStore.Video;
+import android.provider.MediaStore.MediaColumns;
import android.text.TextUtils;
import com.facebook.common.logging.FLog;
import com.facebook.react.bridge.GuardedAsyncTask;
@@ -47,48 +47,38 @@
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
+import java.net.URLConnection;
// TODO #6015104: rename to something less iOSish
/**
- * {@link NativeModule} that allows JS to interact with the photos on the device (i.e.
+ * {@link NativeModule} that allows JS to interact with the photos and videos on the device (i.e.
* {@link MediaStore.Images}).
*/
@ReactModule(name = CameraRollManager.NAME)
public class CameraRollManager extends ReactContextBaseJavaModule {
- protected static final String NAME = "CameraRollManager";
+ public static final String NAME = "CameraRollManager";
private static final String ERROR_UNABLE_TO_LOAD = "E_UNABLE_TO_LOAD";
private static final String ERROR_UNABLE_TO_LOAD_PERMISSION = "E_UNABLE_TO_LOAD_PERMISSION";
private static final String ERROR_UNABLE_TO_SAVE = "E_UNABLE_TO_SAVE";
+ private static final String ERROR_UNABLE_TO_FILTER = "E_UNABLE_TO_FILTER";
- public static final boolean IS_JELLY_BEAN_OR_LATER =
- Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
+ private static final String ASSET_TYPE_PHOTOS = "Photos";
+ private static final String ASSET_TYPE_VIDEOS = "Videos";
+ private static final String ASSET_TYPE_ALL = "All";
- private static final String[] PROJECTION;
- static {
- if (IS_JELLY_BEAN_OR_LATER) {
- PROJECTION = new String[] {
+ private static final String[] PROJECTION = {
Images.Media._ID,
Images.Media.MIME_TYPE,
Images.Media.BUCKET_DISPLAY_NAME,
Images.Media.DATE_TAKEN,
- Images.Media.WIDTH,
- Images.Media.HEIGHT,
+ MediaStore.MediaColumns.WIDTH,
+ MediaStore.MediaColumns.HEIGHT,
Images.Media.LONGITUDE,
- Images.Media.LATITUDE
+ Images.Media.LATITUDE,
+ MediaStore.MediaColumns.DATA
};
- } else {
- PROJECTION = new String[] {
- Images.Media._ID,
- Images.Media.MIME_TYPE,
- Images.Media.BUCKET_DISPLAY_NAME,
- Images.Media.DATE_TAKEN,
- Images.Media.LONGITUDE,
- Images.Media.LATITUDE
- };
- }
- }
private static final String SELECTION_BUCKET = Images.Media.BUCKET_DISPLAY_NAME + " = ?";
private static final String SELECTION_DATE_TAKEN = Images.Media.DATE_TAKEN + " < ?";
@@ -223,7 +213,7 @@
int first = params.getInt("first");
String after = params.hasKey("after") ? params.getString("after") : null;
String groupName = params.hasKey("groupName") ? params.getString("groupName") : null;
- String assetType = params.hasKey("assetType") ? params.getString("assetType") : null;
+ String assetType = params.hasKey("assetType") ? params.getString("assetType") : ASSET_TYPE_PHOTOS;
ReadableArray mimeTypes = params.hasKey("mimeTypes")
? params.getArray("mimeTypes")
: null;
@@ -231,7 +221,7 @@
throw new JSApplicationIllegalArgumentException("groupTypes is not supported on Android");
}
- new GetPhotosTask(
+ new GetMediaTask(
getReactApplicationContext(),
first,
after,
@@ -242,22 +232,22 @@
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
- private static class GetPhotosTask extends GuardedAsyncTask<Void, Void> {
+ private static class GetMediaTask extends GuardedAsyncTask<Void, Void> {
private final Context mContext;
private final int mFirst;
private final @Nullable String mAfter;
private final @Nullable String mGroupName;
private final @Nullable ReadableArray mMimeTypes;
private final Promise mPromise;
- private final @Nullable String mAssetType;
+ private final String mAssetType;
- private GetPhotosTask(
+ private GetMediaTask(
ReactContext context,
int first,
@Nullable String after,
@Nullable String groupName,
@Nullable ReadableArray mimeTypes,
- @Nullable String assetType,
+ String assetType,
Promise promise) {
super(context);
mContext = context;
@@ -281,6 +271,27 @@
selection.append(" AND " + SELECTION_BUCKET);
selectionArgs.add(mGroupName);
}
+
+ if (mAssetType.equals(ASSET_TYPE_PHOTOS)) {
+ selection.append(" AND " + MediaStore.Files.FileColumns.MEDIA_TYPE + " = "
+ + MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE);
+ } else if (mAssetType.equals(ASSET_TYPE_VIDEOS)) {
+ selection.append(" AND " + MediaStore.Files.FileColumns.MEDIA_TYPE + " = "
+ + MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO);
+ } else if (mAssetType.equals(ASSET_TYPE_ALL)) {
+ selection.append(" AND " + MediaStore.Files.FileColumns.MEDIA_TYPE + " IN ("
+ + MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO + ","
+ + MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE + ")");
+ } else {
+ mPromise.reject(
+ ERROR_UNABLE_TO_FILTER,
+ "Invalid filter option: '" + mAssetType + "'. Expected one of '"
+ + ASSET_TYPE_PHOTOS + "', '" + ASSET_TYPE_VIDEOS + "' or '" + ASSET_TYPE_ALL + "'."
+ );
+ return;
+ }
+
+
if (mMimeTypes != null && mMimeTypes.size() > 0) {
selection.append(" AND " + Images.Media.MIME_TYPE + " IN (");
for (int i = 0; i < mMimeTypes.size(); i++) {
@@ -295,74 +306,70 @@
// setting a limit at all), but it works because this specific ContentProvider is backed by
// an SQLite DB and forwards parameters to it without doing any parsing / validation.
try {
- Uri assetURI =
- mAssetType != null && mAssetType.equals("Videos") ? Video.Media.EXTERNAL_CONTENT_URI :
- Images.Media.EXTERNAL_CONTENT_URI;
-
- Cursor photos = resolver.query(
- assetURI,
+ Cursor media = resolver.query(
+ MediaStore.Files.getContentUri("external"),
PROJECTION,
selection.toString(),
selectionArgs.toArray(new String[selectionArgs.size()]),
Images.Media.DATE_TAKEN + " DESC, " + Images.Media.DATE_MODIFIED + " DESC LIMIT " +
(mFirst + 1)); // set LIMIT to first + 1 so that we know how to populate page_info
- if (photos == null) {
- mPromise.reject(ERROR_UNABLE_TO_LOAD, "Could not get photos");
+ if (media == null) {
+ mPromise.reject(ERROR_UNABLE_TO_LOAD, "Could not get media");
} else {
try {
- putEdges(resolver, photos, response, mFirst, mAssetType);
- putPageInfo(photos, response, mFirst);
+ putEdges(resolver, media, response, mFirst);
+ putPageInfo(media, response, mFirst);
} finally {
- photos.close();
+ media.close();
mPromise.resolve(response);
}
}
} catch (SecurityException e) {
mPromise.reject(
ERROR_UNABLE_TO_LOAD_PERMISSION,
- "Could not get photos: need READ_EXTERNAL_STORAGE permission",
+ "Could not get media: need READ_EXTERNAL_STORAGE permission",
e);
}
}
}
- private static void putPageInfo(Cursor photos, WritableMap response, int limit) {
+ private static void putPageInfo(Cursor media, WritableMap response, int limit) {
WritableMap pageInfo = new WritableNativeMap();
- pageInfo.putBoolean("has_next_page", limit < photos.getCount());
- if (limit < photos.getCount()) {
- photos.moveToPosition(limit - 1);
+ pageInfo.putBoolean("has_next_page", limit < media.getCount());
+ if (limit < media.getCount()) {
+ media.moveToPosition(limit - 1);
pageInfo.putString(
"end_cursor",
- photos.getString(photos.getColumnIndex(Images.Media.DATE_TAKEN)));
+ media.getString(media.getColumnIndex(Images.Media.DATE_TAKEN)));
}
response.putMap("page_info", pageInfo);
}
private static void putEdges(
ContentResolver resolver,
- Cursor photos,
+ Cursor media,
WritableMap response,
- int limit,
- @Nullable String assetType) {
+ int limit) {
WritableArray edges = new WritableNativeArray();
- photos.moveToFirst();
- int idIndex = photos.getColumnIndex(Images.Media._ID);
- int mimeTypeIndex = photos.getColumnIndex(Images.Media.MIME_TYPE);
- int groupNameIndex = photos.getColumnIndex(Images.Media.BUCKET_DISPLAY_NAME);
- int dateTakenIndex = photos.getColumnIndex(Images.Media.DATE_TAKEN);
- int widthIndex = IS_JELLY_BEAN_OR_LATER ? photos.getColumnIndex(Images.Media.WIDTH) : -1;
- int heightIndex = IS_JELLY_BEAN_OR_LATER ? photos.getColumnIndex(Images.Media.HEIGHT) : -1;
- int longitudeIndex = photos.getColumnIndex(Images.Media.LONGITUDE);
- int latitudeIndex = photos.getColumnIndex(Images.Media.LATITUDE);
+ media.moveToFirst();
+ int idIndex = media.getColumnIndex(Images.Media._ID);
+ int mimeTypeIndex = media.getColumnIndex(Images.Media.MIME_TYPE);
+ int groupNameIndex = media.getColumnIndex(Images.Media.BUCKET_DISPLAY_NAME);
+ int dateTakenIndex = media.getColumnIndex(Images.Media.DATE_TAKEN);
+ int widthIndex = media.getColumnIndex(MediaStore.MediaColumns.WIDTH);
+ int heightIndex = media.getColumnIndex(MediaStore.MediaColumns.HEIGHT);
+ int longitudeIndex = media.getColumnIndex(Images.Media.LONGITUDE);
+ int latitudeIndex = media.getColumnIndex(Images.Media.LATITUDE);
+ int dataIndex = media.getColumnIndex(MediaStore.MediaColumns.DATA);
- for (int i = 0; i < limit && !photos.isAfterLast(); i++) {
+ for (int i = 0; i < limit && !media.isAfterLast(); i++) {
WritableMap edge = new WritableNativeMap();
WritableMap node = new WritableNativeMap();
boolean imageInfoSuccess =
- putImageInfo(resolver, photos, node, idIndex, widthIndex, heightIndex, assetType);
+ putImageInfo(resolver, media, node, idIndex, widthIndex, heightIndex, dataIndex);
if (imageInfoSuccess) {
- putBasicNodeInfo(photos, node, mimeTypeIndex, groupNameIndex, dateTakenIndex);
- putLocationInfo(photos, node, longitudeIndex, latitudeIndex);
+ putBasicNodeInfo(media, node, mimeTypeIndex, groupNameIndex, dateTakenIndex);
+ putLocationInfo(media, node, longitudeIndex, latitudeIndex);
edge.putMap("node", node);
edges.pushMap(edge);
@@ -371,48 +378,40 @@
// decrement i in order to correctly reach the limit, if the cursor has enough rows
i--;
}
- photos.moveToNext();
+ media.moveToNext();
}
response.putArray("edges", edges);
}
private static void putBasicNodeInfo(
- Cursor photos,
+ Cursor media,
WritableMap node,
int mimeTypeIndex,
int groupNameIndex,
int dateTakenIndex) {
- node.putString("type", photos.getString(mimeTypeIndex));
- node.putString("group_name", photos.getString(groupNameIndex));
- node.putDouble("timestamp", photos.getLong(dateTakenIndex) / 1000d);
+ node.putString("type", media.getString(mimeTypeIndex));
+ node.putString("group_name", media.getString(groupNameIndex));
+ node.putDouble("timestamp", media.getLong(dateTakenIndex) / 1000d);
}
private static boolean putImageInfo(
ContentResolver resolver,
- Cursor photos,
+ Cursor media,
WritableMap node,
int idIndex,
int widthIndex,
int heightIndex,
- @Nullable String assetType) {
+ int dataIndex) {
WritableMap image = new WritableNativeMap();
- Uri photoUri;
- if (assetType != null && assetType.equals("Videos")) {
- photoUri = Uri.withAppendedPath(Video.Media.EXTERNAL_CONTENT_URI, photos.getString(idIndex));
- } else {
- photoUri = Uri.withAppendedPath(Images.Media.EXTERNAL_CONTENT_URI, photos.getString(idIndex));
- }
+ Uri photoUri = Uri.parse("file://" + media.getString(dataIndex));
image.putString("uri", photoUri.toString());
- float width = -1;
- float height = -1;
- if (IS_JELLY_BEAN_OR_LATER) {
- width = photos.getInt(widthIndex);
- height = photos.getInt(heightIndex);
- }
+ float width = media.getInt(widthIndex);
+ float height = media.getInt(heightIndex);
- if (assetType != null
- && assetType.equals("Videos")
- && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
+ String mimeType = URLConnection.guessContentTypeFromName(photoUri.toString());
+
+ if (mimeType != null
+ && mimeType.startsWith("video")) {
try {
AssetFileDescriptor photoDescriptor = resolver.openAssetFileDescriptor(photoUri, "r");
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
@@ -468,16 +467,17 @@
image.putDouble("width", width);
image.putDouble("height", height);
node.putMap("image", image);
+
return true;
}
private static void putLocationInfo(
- Cursor photos,
+ Cursor media,
WritableMap node,
int longitudeIndex,
int latitudeIndex) {
- double longitude = photos.getDouble(longitudeIndex);
- double latitude = photos.getDouble(latitudeIndex);
+ double longitude = media.getDouble(longitudeIndex);
+ double latitude = media.getDouble(latitudeIndex);
if (longitude > 0 || latitude > 0) {
WritableMap location = new WritableNativeMap();
location.putDouble("longitude", longitude);

ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageEditingManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageStoreManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/ClipboardModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,11 +7,9 @@
package com.facebook.react.modules.clipboard;
-import android.annotation.SuppressLint;
import android.content.ClipboardManager;
import android.content.ClipData;
import android.content.Context;
-import android.os.Build;
import com.facebook.react.bridge.ContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
@@ -21,16 +19,18 @@
/**
* A module that allows JS to get/set clipboard contents.
*/
-@ReactModule(name = "Clipboard")
+@ReactModule(name = ClipboardModule.NAME)
public class ClipboardModule extends ContextBaseJavaModule {
public ClipboardModule(Context context) {
super(context);
}
+ public static final String NAME = "Clipboard";
+
@Override
public String getName() {
- return "Clipboard";
+ return ClipboardModule.NAME;
}
private ClipboardManager getClipboardService() {
@@ -55,16 +55,10 @@
}
}
- @SuppressLint("DeprecatedMethod")
@ReactMethod
public void setString(String text) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
ClipData clipdata = ClipData.newPlainText(null, text);
ClipboardManager clipboard = getClipboardService();
clipboard.setPrimaryClip(clipdata);
- } else {
- ClipboardManager clipboard = getClipboardService();
- clipboard.setText(text);
- }
}
}

ReactAndroid/src/main/java/com/facebook/react/modules/common/ModuleDataCleaner.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/core/ChoreographerCompat.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.
@@ -8,11 +8,9 @@
*/
package com.facebook.react.modules.core;
-import android.annotation.TargetApi;
-import android.os.Build;
import android.os.Handler;
-import android.os.Looper;
import android.view.Choreographer;
+import com.facebook.react.bridge.UiThreadUtil;
/**
* Wrapper class for abstracting away availability of the JellyBean Choreographer. If Choreographer
@@ -21,67 +19,49 @@
public class ChoreographerCompat {
private static final long ONE_FRAME_MILLIS = 17;
- private static final boolean IS_JELLYBEAN_OR_HIGHER =
- Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
- private static final ChoreographerCompat INSTANCE = new ChoreographerCompat();
+ private static ChoreographerCompat sInstance;
private Handler mHandler;
private Choreographer mChoreographer;
public static ChoreographerCompat getInstance() {
- return INSTANCE;
+ UiThreadUtil.assertOnUiThread();
+ if (sInstance == null){
+ sInstance = new ChoreographerCompat();
+ }
+ return sInstance;
}
private ChoreographerCompat() {
- if (IS_JELLYBEAN_OR_HIGHER) {
mChoreographer = getChoreographer();
- } else {
- mHandler = new Handler(Looper.getMainLooper());
- }
}
public void postFrameCallback(FrameCallback callbackWrapper) {
- if (IS_JELLYBEAN_OR_HIGHER) {
choreographerPostFrameCallback(callbackWrapper.getFrameCallback());
- } else {
- mHandler.postDelayed(callbackWrapper.getRunnable(), 0);
- }
}
public void postFrameCallbackDelayed(FrameCallback callbackWrapper, long delayMillis) {
- if (IS_JELLYBEAN_OR_HIGHER) {
choreographerPostFrameCallbackDelayed(callbackWrapper.getFrameCallback(), delayMillis);
- } else {
- mHandler.postDelayed(callbackWrapper.getRunnable(), delayMillis + ONE_FRAME_MILLIS);
- }
}
public void removeFrameCallback(FrameCallback callbackWrapper) {
- if (IS_JELLYBEAN_OR_HIGHER) {
choreographerRemoveFrameCallback(callbackWrapper.getFrameCallback());
- } else {
- mHandler.removeCallbacks(callbackWrapper.getRunnable());
- }
}
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private Choreographer getChoreographer() {
return Choreographer.getInstance();
}
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void choreographerPostFrameCallback(Choreographer.FrameCallback frameCallback) {
mChoreographer.postFrameCallback(frameCallback);
}
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void choreographerPostFrameCallbackDelayed(
Choreographer.FrameCallback frameCallback,
long delayMillis) {
mChoreographer.postFrameCallbackDelayed(frameCallback, delayMillis);
}
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void choreographerRemoveFrameCallback(Choreographer.FrameCallback frameCallback) {
mChoreographer.removeFrameCallback(frameCallback);
}
@@ -96,7 +76,6 @@
private Runnable mRunnable;
private Choreographer.FrameCallback mFrameCallback;
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
Choreographer.FrameCallback getFrameCallback() {
if (mFrameCallback == null) {
mFrameCallback = new Choreographer.FrameCallback() {

ReactAndroid/src/main/java/com/facebook/react/modules/core/DefaultHardwareBackBtnHandler.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/core/DeviceEventManagerModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,6 +7,7 @@
package com.facebook.react.modules.core;
+import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import android.net.Uri;
@@ -23,11 +24,11 @@
/**
* Native module that handles device hardware events like hardware back presses.
*/
-@ReactModule(name = "DeviceEventManager")
+@ReactModule(name = DeviceEventManagerModule.NAME)
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;

ReactAndroid/src/main/java/com/facebook/react/modules/core/ExceptionsManagerModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -20,7 +20,7 @@
@ReactModule(name = ExceptionsManagerModule.NAME)
public class ExceptionsManagerModule extends BaseJavaModule {
- protected static final String NAME = "ExceptionsManager";
+ public static final String NAME = "ExceptionsManager";
private final DevSupportManager mDevSupportManager;

ReactAndroid/src/main/java/com/facebook/react/modules/core/HeadlessJsTaskSupportModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -18,10 +18,10 @@
* Simple native module that allows JS to notify native of having completed some task work, so that
* it can e.g. release any resources, stop timers etc.
*/
-@ReactModule(name = HeadlessJsTaskSupportModule.MODULE_NAME)
+@ReactModule(name = HeadlessJsTaskSupportModule.NAME)
public class HeadlessJsTaskSupportModule extends ReactContextBaseJavaModule {
- protected static final String MODULE_NAME = "HeadlessJsTaskSupport";
+ public static final String NAME = "HeadlessJsTaskSupport";
public HeadlessJsTaskSupportModule(ReactApplicationContext reactContext) {
super(reactContext);
@@ -29,7 +29,7 @@
@Override
public String getName() {
- return MODULE_NAME;
+ return NAME;
}
@ReactMethod

ReactAndroid/src/main/java/com/facebook/react/modules/core/JSTimers.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/core/PermissionAwareActivity.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/core/PermissionListener.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/core/RCTNativeAppEventEmitter.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/core/ReactChoreographer.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,11 +7,12 @@
package com.facebook.react.modules.core;
+import com.facebook.react.bridge.UiThreadUtil;
import java.util.ArrayDeque;
+import javax.annotation.Nullable;
import com.facebook.common.logging.FLog;
import com.facebook.infer.annotation.Assertions;
-import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.common.ReactConstants;
/**
@@ -65,7 +66,6 @@
public static void initialize() {
if (sInstance == null) {
- UiThreadUtil.assertOnUiThread();
sInstance = new ReactChoreographer();
}
}
@@ -75,7 +75,8 @@
return sInstance;
}
- private final ChoreographerCompat mChoreographer;
+ // This needs to be volatile due to double checked locking issue - https://fburl.com/z409owpf
+ private @Nullable volatile ChoreographerCompat mChoreographer;
private final ReactChoreographerDispatcher mReactChoreographerDispatcher;
private final ArrayDeque<ChoreographerCompat.FrameCallback>[] mCallbackQueues;
@@ -83,12 +84,12 @@
private boolean mHasPostedCallback = false;
private ReactChoreographer() {
- mChoreographer = ChoreographerCompat.getInstance();
mReactChoreographerDispatcher = new ReactChoreographerDispatcher();
mCallbackQueues = new ArrayDeque[CallbackType.values().length];
for (int i = 0; i < mCallbackQueues.length; i++) {
mCallbackQueues[i] = new ArrayDeque<>();
}
+ initializeChoreographer(null);
}
public synchronized void postFrameCallback(
@@ -98,9 +99,38 @@
mTotalCallbacks++;
Assertions.assertCondition(mTotalCallbacks > 0);
if (!mHasPostedCallback) {
+ if (mChoreographer == null) {
+ initializeChoreographer(new Runnable(){
+ @Override
+ public void run() {
+ postFrameCallbackOnChoreographer();
+ }
+ });
+ } else {
+ postFrameCallbackOnChoreographer();
+ }
+ }
+ }
+
+ public void postFrameCallbackOnChoreographer() {
mChoreographer.postFrameCallback(mReactChoreographerDispatcher);
mHasPostedCallback = true;
}
+
+ public void initializeChoreographer(@Nullable final Runnable runnable) {
+ UiThreadUtil.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (ReactChoreographer.class) {
+ if (mChoreographer == null) {
+ mChoreographer = ChoreographerCompat.getInstance();
+ }
+ }
+ if (runnable != null) {
+ runnable.run();
+ }
+ }
+ });
}
public synchronized void removeFrameCallback(
@@ -117,7 +147,9 @@
private void maybeRemoveFrameCallback() {
Assertions.assertCondition(mTotalCallbacks >= 0);
if (mTotalCallbacks == 0 && mHasPostedCallback) {
+ if (mChoreographer != null) {
mChoreographer.removeFrameCallback(mReactChoreographerDispatcher);
+ }
mHasPostedCallback = false;
}
}

ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -35,7 +35,7 @@
public final class Timing extends ReactContextBaseJavaModule implements LifecycleEventListener,
HeadlessJsTaskEventListener {
- protected static final String NAME = "Timing";
+ public static final String NAME = "Timing";
// These timing contants should be kept in sync with the ones in `JSTimers.js`.
// The minimum time in milliseconds left in the frame to call idle callbacks.

ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/DatePickerDialogFragment.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -16,12 +16,12 @@
import android.app.DatePickerDialog;
import android.app.DatePickerDialog.OnDateSetListener;
import android.app.Dialog;
-import android.app.DialogFragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.os.Build;
import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
import android.widget.DatePicker;
@SuppressLint("ValidFragment")

ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/DatePickerDialogModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,35 +7,27 @@
package com.facebook.react.modules.datepicker;
-import javax.annotation.Nullable;
-
-import java.util.Map;
-import android.app.Activity;
import android.app.DatePickerDialog.OnDateSetListener;
-import android.app.DialogFragment;
-import android.app.FragmentManager;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentManager;
import android.widget.DatePicker;
-
-import com.facebook.react.bridge.NativeModule;
-import com.facebook.react.bridge.Promise;
-import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.ReactContextBaseJavaModule;
-import com.facebook.react.bridge.ReactMethod;
-import com.facebook.react.bridge.ReadableMap;
-import com.facebook.react.bridge.WritableMap;
-import com.facebook.react.bridge.WritableNativeMap;
+import com.facebook.react.bridge.*;
import com.facebook.react.common.annotations.VisibleForTesting;
import com.facebook.react.module.annotations.ReactModule;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
/**
* {@link NativeModule} that allows JS to show a native date picker dialog and get called back when
* the user selects a date.
*/
-@ReactModule(name = "DatePickerAndroid")
+@ReactModule(name = DatePickerDialogModule.FRAGMENT_TAG)
public class DatePickerDialogModule extends ReactContextBaseJavaModule {
@VisibleForTesting
@@ -56,8 +48,8 @@
}
@Override
- public String getName() {
- return "DatePickerAndroid";
+ public @Nonnull String getName() {
+ return DatePickerDialogModule.FRAGMENT_TAG;
}
private class DatePickerDialogListener implements OnDateSetListener, OnDismissListener {
@@ -120,34 +112,15 @@
*/
@ReactMethod
public void open(@Nullable final ReadableMap options, Promise promise) {
- Activity activity = getCurrentActivity();
+ FragmentActivity activity = (FragmentActivity) getCurrentActivity();
if (activity == null) {
promise.reject(
ERROR_NO_ACTIVITY,
"Tried to open a DatePicker dialog while not attached to an Activity");
return;
}
- // We want to support both android.app.Activity and the pre-Honeycomb FragmentActivity
- // (for apps that use it for legacy reasons). This unfortunately leads to some code duplication.
- if (activity instanceof android.support.v4.app.FragmentActivity) {
- android.support.v4.app.FragmentManager fragmentManager =
- ((android.support.v4.app.FragmentActivity) activity).getSupportFragmentManager();
- android.support.v4.app.DialogFragment oldFragment =
- (android.support.v4.app.DialogFragment) fragmentManager.findFragmentByTag(FRAGMENT_TAG);
- if (oldFragment != null) {
- oldFragment.dismiss();
- }
- SupportDatePickerDialogFragment fragment = new SupportDatePickerDialogFragment();
- if (options != null) {
- final Bundle args = createFragmentArguments(options);
- fragment.setArguments(args);
- }
- final DatePickerDialogListener listener = new DatePickerDialogListener(promise);
- fragment.setOnDismissListener(listener);
- fragment.setOnDateSetListener(listener);
- fragment.show(fragmentManager, FRAGMENT_TAG);
- } else {
- FragmentManager fragmentManager = activity.getFragmentManager();
+
+ FragmentManager fragmentManager = activity.getSupportFragmentManager();
DialogFragment oldFragment = (DialogFragment) fragmentManager.findFragmentByTag(FRAGMENT_TAG);
if (oldFragment != null) {
oldFragment.dismiss();
@@ -162,7 +135,6 @@
fragment.setOnDateSetListener(listener);
fragment.show(fragmentManager, FRAGMENT_TAG);
}
- }
private Bundle createFragmentArguments(ReadableMap options) {
final Bundle args = new Bundle();

ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/DatePickerMode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/DismissableDatePickerDialog.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/SupportDatePickerDialogFragment.java

@@ -1,49 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-package com.facebook.react.modules.datepicker;
-
-import javax.annotation.Nullable;
-
-import android.annotation.SuppressLint;
-import android.app.DatePickerDialog.OnDateSetListener;
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnDismissListener;
-import android.os.Bundle;
-import android.support.v4.app.DialogFragment;
-
-@SuppressLint("ValidFragment")
-public class SupportDatePickerDialogFragment extends DialogFragment {
-
- @Nullable
- private OnDateSetListener mOnDateSetListener;
- @Nullable
- private OnDismissListener mOnDismissListener;
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- final Bundle args = getArguments();
- return DatePickerDialogFragment.createDialog(args, getActivity(), mOnDateSetListener);
- }
-
- @Override
- public void onDismiss(DialogInterface dialog) {
- super.onDismiss(dialog);
- if (mOnDismissListener != null) {
- mOnDismissListener.onDismiss(dialog);
- }
- }
-
- /*package*/ void setOnDateSetListener(@Nullable OnDateSetListener onDateSetListener) {
- mOnDateSetListener = onDateSetListener;
- }
-
- /*package*/ void setOnDismissListener(@Nullable OnDismissListener onDismissListener) {
- mOnDismissListener = onDismissListener;
- }
-}

ReactAndroid/src/main/java/com/facebook/react/modules/debug/AnimationsDebugModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -59,7 +59,6 @@
}
mFrameCallback = new FpsDebugFrameCallback(
- ChoreographerCompat.getInstance(),
getReactApplicationContext());
mFrameCallback.startAndRecordFpsAtEachFrame();
}

ReactAndroid/src/main/java/com/facebook/react/modules/debug/DidJSUpdateUiDuringFrameDetector.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/debug/FpsDebugFrameCallback.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,6 +7,7 @@
package com.facebook.react.modules.debug;
+import com.facebook.react.bridge.UiThreadUtil;
import javax.annotation.Nullable;
import java.util.Map;
@@ -59,7 +60,7 @@
private static final double EXPECTED_FRAME_TIME = 16.9;
- private final ChoreographerCompat mChoreographer;
+ private @Nullable ChoreographerCompat mChoreographer;
private final ReactContext mReactContext;
private final UIManagerModule mUIManagerModule;
private final DidJSUpdateUiDuringFrameDetector mDidJSUpdateUiDuringFrameDetector;
@@ -74,8 +75,7 @@
private boolean mIsRecordingFpsInfoAtEachFrame = false;
private @Nullable TreeMap<Long, FpsInfo> mTimeToFps;
- public FpsDebugFrameCallback(ChoreographerCompat choreographer, ReactContext reactContext) {
- mChoreographer = choreographer;
+ public FpsDebugFrameCallback(ReactContext reactContext) {
mReactContext = reactContext;
mUIManagerModule = reactContext.getNativeModule(UIManagerModule.class);
mDidJSUpdateUiDuringFrameDetector = new DidJSUpdateUiDuringFrameDetector();
@@ -120,16 +120,24 @@
mTimeToFps.put(System.currentTimeMillis(), info);
}
mExpectedNumFramesPrev = expectedNumFrames;
-
+ if (mChoreographer != null) {
mChoreographer.postFrameCallback(this);
}
+ }
public void start() {
mShouldStop = false;
mReactContext.getCatalystInstance().addBridgeIdleDebugListener(
mDidJSUpdateUiDuringFrameDetector);
mUIManagerModule.setViewHierarchyUpdateDebugListener(mDidJSUpdateUiDuringFrameDetector);
- mChoreographer.postFrameCallback(this);
+ final FpsDebugFrameCallback fpsDebugFrameCallback = this;
+ UiThreadUtil.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mChoreographer = ChoreographerCompat.getInstance();
+ mChoreographer.postFrameCallback(fpsDebugFrameCallback);
+ }
+ });
}
public void startAndRecordFpsAtEachFrame() {

ReactAndroid/src/main/java/com/facebook/react/modules/debug/interfaces/DeveloperSettings.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/debug/SourceCodeModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/DeviceInfoModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -24,11 +24,11 @@
/**
* Module that exposes Android Constants to JS.
*/
-@ReactModule(name = DeviceInfoModule.sModuleName)
+@ReactModule(name = DeviceInfoModule.NAME)
public class DeviceInfoModule extends BaseJavaModule implements
LifecycleEventListener {
- static final String sModuleName = "DeviceInfo";
+ public static final String NAME = "DeviceInfo";
private @Nullable ReactApplicationContext mReactApplicationContext;
private float mFontScale;
@@ -47,7 +47,7 @@
@Override
public String getName() {
- return sModuleName;
+ return NAME;
}
@Override

ReactAndroid/src/main/java/com/facebook/react/modules/dialog/AlertFragment.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/dialog/DialogModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,10 +7,6 @@
package com.facebook.react.modules.dialog;
-import javax.annotation.Nullable;
-
-import java.util.Map;
-
import android.app.Activity;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
@@ -29,6 +24,8 @@
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.module.annotations.ReactModule;
+import java.util.Map;
+import javax.annotation.Nullable;
@ReactModule(name = DialogModule.NAME)
public class DialogModule extends ReactContextBaseJavaModule implements LifecycleEventListener {
@@ -36,7 +33,7 @@
/* package */ static final String FRAGMENT_TAG =
"com.facebook.catalyst.react.dialog.DialogModule";
- /* package */ static final String NAME = "DialogManagerAndroid";
+ public static final String NAME = "DialogManagerAndroid";
/* package */ static final String ACTION_BUTTON_CLICKED = "buttonClicked";
/* package */ static final String ACTION_DISMISSED = "dismissed";
@@ -110,13 +107,13 @@
if (isUsingSupportLibrary()) {
SupportAlertFragment oldFragment =
(SupportAlertFragment) mSupportFragmentManager.findFragmentByTag(FRAGMENT_TAG);
- if (oldFragment != null) {
+ if (oldFragment != null && oldFragment.isResumed()) {
oldFragment.dismiss();
}
} else {
AlertFragment oldFragment =
(AlertFragment) mFragmentManager.findFragmentByTag(FRAGMENT_TAG);
- if (oldFragment != null) {
+ if (oldFragment != null && oldFragment.isResumed()) {
oldFragment.dismiss();
}
}
@@ -132,7 +129,7 @@
if (isUsingSupportLibrary()) {
SupportAlertFragment alertFragment = new SupportAlertFragment(actionListener, arguments);
- if (isInForeground) {
+ if (isInForeground && !mSupportFragmentManager.isStateSaved()) {
if (arguments.containsKey(KEY_CANCELABLE)) {
alertFragment.setCancelable(arguments.getBoolean(KEY_CANCELABLE));
}

ReactAndroid/src/main/java/com/facebook/react/modules/dialog/SupportAlertFragment.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/fabric/ReactFabric.java

@@ -1,3 +1,10 @@
+/**
+ * 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.fabric;
import com.facebook.react.bridge.JavaScriptModule;

ReactAndroid/src/main/java/com/facebook/react/modules/fresco/BUCK

@@ -4,7 +4,6 @@
name = "fresco",
srcs = glob(["**/*.java"]),
provided_deps = [
- react_native_dep("third-party/android/support-annotations:android-support-annotations"),
react_native_dep("third-party/android/support/v4:lib-support-v4"),
],
visibility = [

ReactAndroid/src/main/java/com/facebook/react/modules/fresco/FrescoModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -37,10 +37,11 @@
*
* <p>Does not expose any methods to JavaScript code. For initialization and cleanup only.
*/
-@ReactModule(name = "FrescoModule")
+@ReactModule(name = FrescoModule.NAME, needsEagerInit = true)
public class FrescoModule extends ReactContextBaseJavaModule implements
ModuleDataCleaner.Cleanable, LifecycleEventListener {
+ public static final String NAME = "FrescoModule";
private final boolean mClearOnDestroy;
private @Nullable ImagePipelineConfig mConfig;
@@ -114,7 +115,7 @@
@Override
public String getName() {
- return "FrescoModule";
+ return NAME;
}
@Override

ReactAndroid/src/main/java/com/facebook/react/modules/fresco/ReactNetworkImageRequest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/fresco/ReactOkHttpNetworkFetcher.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/fresco/SystraceRequestListener.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/modules/i18nmanager/I18nManagerModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -19,9 +19,11 @@
/**
* {@link NativeModule} that allows JS to set allowRTL and get isRTL status.
*/
-@ReactModule(name = "I18nManager")
+@ReactModule(name = I18nManagerModule.NAME)
public class I18nManagerModule extends ContextBaseJavaModule {
+ public static final String NAME = "I18nManager";
+
private final I18nUtil sharedI18nUtilInstance = I18nUtil.getInstance();
public I18nManagerModule(Context context) {
@@ -30,7 +32,7 @@
@Override
public String getName() {
- return "I18nManager";
+ return NAME;
}
@Override

ReactAndroid/src/main/java/com/facebook/react/modules/i18nmanager/I18nUtil.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/image/ImageLoaderModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -33,13 +33,14 @@
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.module.annotations.ReactModule;
-@ReactModule(name = "ImageLoader")
+@ReactModule(name = ImageLoaderModule.NAME)
public class ImageLoaderModule extends ReactContextBaseJavaModule implements
LifecycleEventListener {
private static final String ERROR_INVALID_URI = "E_INVALID_URI";
private static final String ERROR_PREFETCH_FAILURE = "E_PREFETCH_FAILURE";
private static final String ERROR_GET_SIZE_FAILURE = "E_GET_SIZE_FAILURE";
+ public static final String NAME = "ImageLoader";
private final Object mCallerContext;
private final Object mEnqueuedRequestMonitor = new Object();
@@ -57,7 +58,7 @@
@Override
public String getName() {
- return "ImageLoader";
+ return NAME;
}
/**

ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,6 +10,7 @@
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.net.Uri;
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
@@ -17,21 +18,28 @@
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.ReadableType;
import com.facebook.react.module.annotations.ReactModule;
+import javax.annotation.Nullable;
+
/**
* Intent module. Launch other activities or open URLs.
*/
-@ReactModule(name = "IntentAndroid")
+@ReactModule(name = IntentModule.NAME)
public class IntentModule extends ReactContextBaseJavaModule {
+ public static final String NAME = "IntentAndroid";
+
public IntentModule(ReactApplicationContext reactContext) {
super(reactContext);
}
@Override
public String getName() {
- return "IntentAndroid";
+ return NAME;
}
/**
@@ -131,4 +139,67 @@
"Could not check if URL '" + url + "' can be opened: " + e.getMessage()));
}
}
+
+ /**
+ * Allows to send intents on Android
+ *
+ * For example, you can open the Notification Category screen for a specific application
+ * passing action = 'android.settings.CHANNEL_NOTIFICATION_SETTINGS'
+ * and extras = [
+ * { 'android.provider.extra.APP_PACKAGE': 'your.package.name.here' },
+ * { 'android.provider.extra.CHANNEL_ID': 'your.channel.id.here }
+ * ]
+ *
+ * @param action The general action to be performed
+ * @param extras An array of extras [{ String, String | Number | Boolean }]
+ */
+ @ReactMethod
+ public void sendIntent(String action, @Nullable ReadableArray extras, Promise promise) {
+ if (action == null || action.isEmpty()) {
+ promise.reject(new JSApplicationIllegalArgumentException("Invalid Action: " + action + "."));
+ return;
+ }
+
+ Intent intent = new Intent(action);
+
+ PackageManager packageManager = getReactApplicationContext().getPackageManager();
+ if (intent.resolveActivity(packageManager) == null) {
+ promise.reject(new JSApplicationIllegalArgumentException("Could not launch Intent with action " + action + "."));
+ return;
+ }
+
+ if (extras != null) {
+ for (int i = 0; i < extras.size(); i++) {
+ ReadableMap map = extras.getMap(i);
+ String name = map.keySetIterator().nextKey();
+ ReadableType type = map.getType(name);
+
+ switch (type) {
+ case String: {
+ intent.putExtra(name, map.getString(name));
+ break;
+ }
+ case Number: {
+ // We cannot know from JS if is an Integer or Double
+ // See: https://github.com/facebook/react-native/issues/4141
+ // We might need to find a workaround if this is really an issue
+ Double number = map.getDouble(name);
+ intent.putExtra(name, number);
+ break;
+ }
+ case Boolean: {
+ intent.putExtra(name, map.getBoolean(name));
+ break;
+ }
+ default: {
+ promise.reject(new JSApplicationIllegalArgumentException(
+ "Extra type for " + name + " not supported."));
+ return;
+ }
+ }
+ }
+ }
+
+ getReactApplicationContext().startActivity(intent);
+ }
}

ReactAndroid/src/main/java/com/facebook/react/modules/location/BUCK

@@ -8,6 +8,7 @@
],
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"),

ReactAndroid/src/main/java/com/facebook/react/modules/location/LocationModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,13 +7,17 @@
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;
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;
@@ -31,9 +35,11 @@
/**
* Native module that exposes Geolocation to JS.
*/
-@ReactModule(name = "LocationObserver")
+@SuppressLint("MissingPermission")
+@ReactModule(name = LocationModule.NAME)
public class LocationModule extends ReactContextBaseJavaModule {
+ public static final String NAME = "LocationObserver";
private @Nullable String mWatchedProvider;
private static final float RCT_DEFAULT_LOCATION_ACCURACY = 100;
@@ -66,7 +72,7 @@
@Override
public String getName() {
- return "LocationObserver";
+ return NAME;
}
private static class LocationOptions {
@@ -189,7 +195,7 @@
}
@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)) {
@@ -200,6 +206,11 @@
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;
}
@@ -215,7 +226,7 @@
map.putMap("coords", coords);
map.putDouble("timestamp", location.getTime());
- if (android.os.Build.VERSION.SDK_INT >= 18) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
map.putBoolean("mocked", location.isFromMockProvider());
}

ReactAndroid/src/main/java/com/facebook/react/modules/location/PositionError.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/NetInfoModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,6 +7,7 @@
package com.facebook.react.modules.netinfo;
+import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -30,7 +31,8 @@
/**
* Module that monitors and provides information about the connectivity state of the device.
*/
-@ReactModule(name = "NetInfo")
+@SuppressLint("MissingPermission")
+@ReactModule(name = NetInfoModule.NAME)
public class NetInfoModule extends ReactContextBaseJavaModule
implements LifecycleEventListener {
@@ -59,6 +61,7 @@
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />";
private static final String ERROR_MISSING_PERMISSION = "E_MISSING_PERMISSION";
+ public static final String NAME = "NetInfo";
private final ConnectivityManager mConnectivityManager;
private final ConnectivityBroadcastReceiver mConnectivityBroadcastReceiver;
@@ -96,13 +99,13 @@
@Override
public String getName() {
- return "NetInfo";
+ return NAME;
}
@ReactMethod
public void getCurrentConnectivity(Promise promise) {
if (mNoNetworkPermission) {
- promise.reject(ERROR_MISSING_PERMISSION, MISSING_PERMISSION_MESSAGE, null);
+ promise.reject(ERROR_MISSING_PERMISSION, MISSING_PERMISSION_MESSAGE);
return;
}
promise.resolve(createConnectivityEventMap());
@@ -111,7 +114,7 @@
@ReactMethod
public void isConnectionMetered(Promise promise) {
if (mNoNetworkPermission) {
- promise.reject(ERROR_MISSING_PERMISSION, MISSING_PERMISSION_MESSAGE, null);
+ promise.reject(ERROR_MISSING_PERMISSION, MISSING_PERMISSION_MESSAGE);
return;
}
promise.resolve(ConnectivityManagerCompat.isActiveNetworkMetered(mConnectivityManager));

ReactAndroid/src/main/java/com/facebook/react/modules/network/CookieJarContainer.java

@@ -1,3 +1,10 @@
+/**
+ * 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;
import okhttp3.CookieJar;

ReactAndroid/src/main/java/com/facebook/react/modules/network/ForwardingCookieHandler.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -56,7 +56,10 @@
@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 @@
new GuardedResultAsyncTask<Boolean>(mContext) {
@Override
protected Boolean doInBackgroundGuarded() {
- getCookieManager().removeAllCookie();
+ CookieManager cookieManager = getCookieManager();
+ if (cookieManager != null) {
+ cookieManager.removeAllCookie();
+ }
mCookieSaver.onCookiesModified();
return true;
}
@@ -96,7 +102,9 @@
}
private void clearCookiesAsync(final Callback callback) {
- getCookieManager().removeAllCookies(
+ CookieManager cookieManager = getCookieManager();
+ if (cookieManager != null) {
+ cookieManager.removeAllCookies(
new ValueCallback<Boolean>() {
@Override
public void onReceiveValue(Boolean value) {
@@ -105,22 +113,29 @@
}
});
}
+ }
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 @@
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,15 @@
* 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);
+ try {
mCookieManager = CookieManager.getInstance();
+ } catch (IllegalArgumentException ex) {
+ // https://bugs.chromium.org/p/chromium/issues/detail?id=559720
+ return null;
+ }
if (USES_LEGACY_STORE) {
mCookieManager.removeExpiredCookie();
@@ -228,7 +251,10 @@
@TargetApi(21)
private void flush() {
- getCookieManager().flush();
+ CookieManager cookieManager = getCookieManager();
+ if (cookieManager != null) {
+ cookieManager.flush();
+ }
}
}
}

ReactAndroid/src/main/java/com/facebook/react/modules/network/HeaderUtil.java

@@ -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;
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,6 +9,7 @@
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;
@@ -47,6 +48,8 @@
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.ByteString;
+import okio.GzipSource;
+import okio.Okio;
/**
* Implements the XMLHttpRequest JavaScript interface.
@@ -102,6 +105,7 @@
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";
@@ -161,7 +165,7 @@
* @param context the ReactContext of the application
*/
public NetworkingModule(final ReactApplicationContext context) {
- this(context, null, OkHttpClientProvider.createClient(), null);
+ this(context, null, OkHttpClientProvider.createClient(context), null);
}
/**
@@ -172,7 +176,7 @@
public NetworkingModule(
ReactApplicationContext context,
List<NetworkInterceptorCreator> networkInterceptorCreators) {
- this(context, null, OkHttpClientProvider.createClient(), networkInterceptorCreators);
+ this(context, null, OkHttpClientProvider.createClient(context), networkInterceptorCreators);
}
/**
@@ -181,7 +185,7 @@
* caller does not provide one explicitly
*/
public NetworkingModule(ReactApplicationContext context, String defaultUserAgent) {
- this(context, defaultUserAgent, OkHttpClientProvider.createClient(), null);
+ this(context, defaultUserAgent, OkHttpClientProvider.createClient(context), null);
}
@Override
@@ -232,10 +236,29 @@
}
@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,
@@ -370,7 +393,13 @@
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) {
@@ -454,8 +483,26 @@
translateHeaders(response.headers()),
response.request().url().toString());
- ResponseBody responseBody = response.body();
try {
+ // OkHttp implements something called transparent gzip, which mean that it will
+ // automatically add the Accept-Encoding gzip header and handle decoding internally.
+ // The issue is that it won't handle decoding if the user provides a Accept-Encoding
+ // header. This is also undesirable considering that iOS does handle the decoding even
+ // when the header is provided. To make sure this works in all cases, handle gzip body
+ // here also. This works fine since OKHttp will remove the Content-Encoding header if
+ // it used transparent gzip.
+ // See https://github.com/square/okhttp/blob/5b37cda9e00626f43acf354df145fd452c3031f1/okhttp/src/main/java/okhttp3/internal/http/BridgeInterceptor.java#L76-L111
+ ResponseBody responseBody = response.body();
+ if ("gzip".equalsIgnoreCase(response.header("Content-Encoding")) &&
+ responseBody != null) {
+ GzipSource gzipSource = new GzipSource(responseBody.source());
+ String contentType = response.header("Content-Type");
+ responseBody = ResponseBody.create(
+ contentType != null ? MediaType.parse(contentType) : null,
+ -1L,
+ Okio.buffer(gzipSource));
+ }
+
// Check if a handler is registered
for (ResponseHandler handler : mResponseHandlers) {
if (handler.supports(responseType)) {
@@ -694,8 +741,8 @@
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;
}

ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkInterceptorCreator.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/network/OkHttpClientFactory.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/network/OkHttpClientProvider.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,16 +7,21 @@
package com.facebook.react.modules.network;
+import android.content.Context;
import android.os.Build;
import com.facebook.common.logging.FLog;
+import java.io.File;
+import java.security.Provider;
+import java.security.Security;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
+import okhttp3.Cache;
import okhttp3.ConnectionSpec;
import okhttp3.OkHttpClient;
import okhttp3.TlsVersion;
@@ -44,12 +49,6 @@
return sClient;
}
- // okhttp3 OkHttpClient is immutable
- // This allows app to init an OkHttpClient with custom settings.
- public static void replaceOkHttpClient(OkHttpClient client) {
- sClient = client;
- }
-
public static OkHttpClient createClient() {
if (sFactory != null) {
return sFactory.createNewNetworkModuleClient();
@@ -57,6 +56,13 @@
return createClientBuilder().build();
}
+ public static OkHttpClient createClient(Context context) {
+ if (sFactory != null) {
+ return sFactory.createNewNetworkModuleClient();
+ }
+ return createClientBuilder(context).build();
+ }
+
public static OkHttpClient.Builder createClientBuilder() {
// No timeouts by default
OkHttpClient.Builder client = new OkHttpClient.Builder()
@@ -65,8 +71,33 @@
.writeTimeout(0, TimeUnit.MILLISECONDS)
.cookieJar(new ReactCookieJarContainer());
+ 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) {
+ int cacheSize = 10 * 1024 * 1024; // 10 Mo
+ return createClientBuilder(context, cacheSize);
+ }
+
+ public static OkHttpClient.Builder createClientBuilder(Context context, int cacheSize) {
+ OkHttpClient.Builder client = createClientBuilder();
+
+ if (cacheSize == 0) {
+ return client;
+ }
+
+ File cacheDirectory = new File(context.getCacheDir(), "http-cache");
+ Cache cache = new Cache(cacheDirectory, cacheSize);
+
+ return client.cache(cache);
+ }
/*
On Android 4.1-4.4 (API level 16 to 19) TLS 1.1 and 1.2 are
@@ -74,7 +105,7 @@
enables it.
*/
public static OkHttpClient.Builder enableTls12OnPreLollipop(OkHttpClient.Builder client) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
try {
client.sslSocketFactory(new TLSSocketFactory());

ReactAndroid/src/main/java/com/facebook/react/modules/network/ProgressiveStringDecoder.java

@@ -1,5 +1,5 @@
/**
-* Copyright (c) 2017-present, Facebook, Inc.
+* 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.

ReactAndroid/src/main/java/com/facebook/react/modules/network/ProgressListener.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/network/ProgressRequestBody.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/network/ProgressResponseBody.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/modules/network/ReactCookieJarContainer.java

@@ -1,3 +1,10 @@
+/**
+ * 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;
import java.util.ArrayList;

ReactAndroid/src/main/java/com/facebook/react/modules/network/RequestBodyUtil.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/network/ResponseUtil.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -85,7 +85,7 @@
RCTDeviceEventEmitter eventEmitter,
int requestId,
String error,
- IOException e) {
+ Throwable e) {
WritableArray args = Arguments.createArray();
args.pushInt(requestId);
args.pushString(error);

ReactAndroid/src/main/java/com/facebook/react/modules/network/TLSSocketFactory.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/permissions/PermissionsModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -29,10 +29,11 @@
/**
* Module that exposes the Android M Permission system to JS.
*/
-@ReactModule(name = "PermissionsAndroid")
+@ReactModule(name = PermissionsModule.NAME)
public class PermissionsModule extends ReactContextBaseJavaModule implements PermissionListener {
private static final String ERROR_INVALID_ACTIVITY = "E_INVALID_ACTIVITY";
+ public static final String NAME = "PermissionsAndroid";
private final SparseArray<Callback> mCallbacks;
private int mRequestCode = 0;
private final String GRANTED = "granted";
@@ -46,7 +47,7 @@
@Override
public String getName() {
- return "PermissionsAndroid";
+ return NAME;
}
/**

ReactAndroid/src/main/java/com/facebook/react/modules/share/ShareModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/StatusBarModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -34,10 +34,12 @@
/**
* {@link NativeModule} that allows changing the appearance of the status bar.
*/
-@ReactModule(name = "StatusBarManager")
+@ReactModule(name = StatusBarModule.NAME)
public class StatusBarModule extends ReactContextBaseJavaModule {
private static final String HEIGHT_KEY = "HEIGHT";
+ private static final String DEFAULT_BACKGROUND_COLOR_KEY = "DEFAULT_BACKGROUND_COLOR";
+ public static final String NAME = "StatusBarManager";
public StatusBarModule(ReactApplicationContext reactContext) {
super(reactContext);
@@ -45,20 +47,28 @@
@Override
public String getName() {
- return "StatusBarManager";
+ return NAME;
}
@Override
public @Nullable Map<String, Object> getConstants() {
final Context context = getReactApplicationContext();
+ final Activity activity = getCurrentActivity();
+
final int heightResId = context.getResources()
.getIdentifier("status_bar_height", "dimen", "android");
final float height = heightResId > 0 ?
PixelUtil.toDIPFromPixel(context.getResources().getDimensionPixelSize(heightResId)) :
0;
+ String statusBarColorString = "black";
+
+ if (activity != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ final int statusBarColor = activity.getWindow().getStatusBarColor();
+ statusBarColorString = String.format("#%06X", (0xFFFFFF & statusBarColor));
+ }
return MapBuilder.<String, Object>of(
- HEIGHT_KEY, height);
+ HEIGHT_KEY, height, DEFAULT_BACKGROUND_COLOR_KEY, statusBarColorString);
}
@ReactMethod
@@ -179,8 +189,13 @@
@Override
public void run() {
View decorView = activity.getWindow().getDecorView();
- decorView.setSystemUiVisibility(
- "dark-content".equals(style) ? View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR : 0);
+ int systemUiVisibilityFlags = decorView.getSystemUiVisibility();
+ if ("dark-content".equals(style)) {
+ systemUiVisibilityFlags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+ } else {
+ systemUiVisibilityFlags &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+ }
+ decorView.setSystemUiVisibility(systemUiVisibilityFlags);
}
}
);

ReactAndroid/src/main/java/com/facebook/react/modules/storage/AsyncLocalStorageUtil.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/storage/AsyncStorageErrorUtil.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/storage/AsyncStorageModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -38,7 +38,7 @@
public final class AsyncStorageModule
extends ReactContextBaseJavaModule implements ModuleDataCleaner.Cleanable {
- protected static final String NAME = "AsyncSQLiteDBStorage";
+ public static final String NAME = "AsyncSQLiteDBStorage";
// SQL variable number limit, defined by SQLITE_LIMIT_VARIABLE_NUMBER:
// https://raw.githubusercontent.com/android/platform_external_sqlite/master/dist/sqlite3.c

ReactAndroid/src/main/java/com/facebook/react/modules/storage/ReactDatabaseSupplier.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoHelpers.java

@@ -1,23 +1,33 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.systeminfo;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.util.Locale;
import android.os.Build;
+import com.facebook.common.logging.FLog;
+
public class AndroidInfoHelpers {
public static final String EMULATOR_LOCALHOST = "10.0.2.2";
public static final String GENYMOTION_LOCALHOST = "10.0.3.2";
public static final String DEVICE_LOCALHOST = "localhost";
+ public static final String METRO_HOST_PROP_NAME = "metro.host";
+
private static final int DEBUG_SERVER_HOST_PORT = 8081;
private static final int INSPECTOR_PROXY_PORT = 8082;
+ private static final String TAG = AndroidInfoHelpers.class.getSimpleName();
+
private static boolean isRunningOnGenymotion() {
return Build.FINGERPRINT.contains("vbox");
}
@@ -49,7 +59,10 @@
// We detect whether app runs on genymotion and replace js bundle server hostname accordingly
String ipAddress;
- if (isRunningOnGenymotion()) {
+ String metroHostProp = getMetroHostPropValue();
+ if (!metroHostProp.equals("")) {
+ ipAddress = metroHostProp;
+ } else if (isRunningOnGenymotion()) {
ipAddress = GENYMOTION_LOCALHOST;
} else if (isRunningOnStockEmulator()) {
ipAddress = EMULATOR_LOCALHOST;
@@ -59,4 +72,41 @@
return String.format(Locale.US, "%s:%d", ipAddress, port);
}
+
+ private static String metroHostPropValue = null;
+ private static synchronized String getMetroHostPropValue() {
+ if (metroHostPropValue != null) {
+ return metroHostPropValue;
+ }
+ Process process = null;
+ BufferedReader reader = null;
+ try {
+ process =
+ Runtime.getRuntime().exec(new String[] {"/system/bin/getprop", METRO_HOST_PROP_NAME});
+ reader =
+ new BufferedReader(
+ new InputStreamReader(process.getInputStream(), Charset.forName("UTF-8")));
+
+ String lastLine = "";
+ String line;
+ while ((line = reader.readLine()) != null) {
+ lastLine = line;
+ }
+ metroHostPropValue = lastLine;
+ } catch (Exception e) {
+ FLog.w(TAG, "Failed to query for metro.host prop:", e);
+ metroHostPropValue = "";
+ } finally {
+ try {
+ if (reader != null) {
+ reader.close();
+ }
+ } catch (Exception exc) {
+ }
+ if (process != null) {
+ process.destroy();
+ }
+ }
+ return metroHostPropValue;
+ }
}

ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,6 +7,7 @@
package com.facebook.react.modules.systeminfo;
+import android.annotation.SuppressLint;
import android.app.UiModeManager;
import android.content.res.Configuration;
import android.os.Build;
@@ -14,6 +15,8 @@
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
+import com.facebook.react.common.build.ReactBuildConfig;
+import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.module.annotations.ReactModule;
import java.util.HashMap;
@@ -26,9 +29,10 @@
/**
* Module that exposes Android Constants to JS.
*/
-@ReactModule(name = "PlatformConstants")
+@ReactModule(name = AndroidInfoModule.NAME)
+@SuppressLint("HardwareIds")
public class AndroidInfoModule extends ReactContextBaseJavaModule {
-
+ public static final String NAME = "PlatformConstants";
private static final String IS_TESTING = "IS_TESTING";
public AndroidInfoModule(ReactApplicationContext reactContext) {
@@ -69,11 +73,17 @@
constants.put("Serial", Build.SERIAL);
constants.put("Fingerprint", Build.FINGERPRINT);
constants.put("Model", Build.MODEL);
+ if (ReactBuildConfig.DEBUG) {
constants.put("ServerHost", AndroidInfoHelpers.getServerHost());
+ }
constants.put("isTesting", "true".equals(System.getProperty(IS_TESTING)));
constants.put("reactNativeVersion", ReactNativeVersion.VERSION);
constants.put("uiMode", uiMode());
- constants.put("androidID", Secure.getString(getReactApplicationContext().getContentResolver(), Secure.ANDROID_ID));
return constants;
}
+
+ @ReactMethod(isBlockingSynchronousMethod = true)
+ public String getAndroidID(){
+ return Secure.getString(getReactApplicationContext().getContentResolver(),Secure.ANDROID_ID);
+ }
}

ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/BUCK

@@ -29,6 +29,7 @@
"PUBLIC",
],
deps = [
+ 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"),
],

ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.java

@@ -1,7 +1,7 @@
/**
* @generated by scripts/bump-oss-version.js
*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -16,7 +16,7 @@
public class ReactNativeVersion {
public static final Map<String, Object> VERSION = MapBuilder.<String, Object>of(
"major", 0,
- "minor", 57,
- "patch", 8,
+ "minor", 59,
+ "patch", 4,
"prerelease", null);
}

ReactAndroid/src/main/java/com/facebook/react/modules/timepicker/DismissableTimePickerDialog.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/timepicker/SupportTimePickerDialogFragment.java

@@ -1,48 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-package com.facebook.react.modules.timepicker;
-
-import javax.annotation.Nullable;
-
-import android.app.Dialog;
-import android.app.TimePickerDialog.OnTimeSetListener;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnDismissListener;
-import android.os.Bundle;
-import android.support.v4.app.DialogFragment;
-
-@SuppressWarnings("ValidFragment")
-public class SupportTimePickerDialogFragment extends DialogFragment {
-
- @Nullable
- private OnTimeSetListener mOnTimeSetListener;
- @Nullable
- private OnDismissListener mOnDismissListener;
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- final Bundle args = getArguments();
- return TimePickerDialogFragment.createDialog(args, getActivity(), mOnTimeSetListener);
- }
-
- @Override
- public void onDismiss(DialogInterface dialog) {
- super.onDismiss(dialog);
- if (mOnDismissListener != null) {
- mOnDismissListener.onDismiss(dialog);
- }
- }
-
- public void setOnDismissListener(@Nullable OnDismissListener onDismissListener) {
- mOnDismissListener = onDismissListener;
- }
-
- public void setOnTimeSetListener(@Nullable OnTimeSetListener onTimeSetListener) {
- mOnTimeSetListener = onTimeSetListener;
- }
-}

ReactAndroid/src/main/java/com/facebook/react/modules/timepicker/TimePickerDialogFragment.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -8,14 +8,13 @@
package com.facebook.react.modules.timepicker;
import android.app.Dialog;
-import android.app.DialogFragment;
-import android.app.TimePickerDialog;
import android.app.TimePickerDialog.OnTimeSetListener;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.os.Build;
import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
import android.text.format.DateFormat;
import java.util.Calendar;

ReactAndroid/src/main/java/com/facebook/react/modules/timepicker/TimePickerDialogModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,13 +7,13 @@
package com.facebook.react.modules.timepicker;
-import android.app.Activity;
-import android.app.DialogFragment;
-import android.app.FragmentManager;
import android.app.TimePickerDialog.OnTimeSetListener;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentManager;
import android.widget.TimePicker;
import com.facebook.react.bridge.NativeModule;
@@ -33,7 +33,7 @@
* {@link NativeModule} that allows JS to show a native time picker dialog and get called back when
* the user selects a time.
*/
-@ReactModule(name = "TimePickerAndroid")
+@ReactModule(name = TimePickerDialogModule.FRAGMENT_TAG)
public class TimePickerDialogModule extends ReactContextBaseJavaModule {
@VisibleForTesting
@@ -54,7 +54,7 @@
@Override
public String getName() {
- return "TimePickerAndroid";
+ return FRAGMENT_TAG;
}
private class TimePickerDialogListener implements OnTimeSetListener, OnDismissListener {
@@ -92,7 +92,7 @@
@ReactMethod
public void open(@Nullable final ReadableMap options, Promise promise) {
- Activity activity = getCurrentActivity();
+ FragmentActivity activity = (FragmentActivity) getCurrentActivity();
if (activity == null) {
promise.reject(
ERROR_NO_ACTIVITY,
@@ -101,32 +101,14 @@
}
// We want to support both android.app.Activity and the pre-Honeycomb FragmentActivity
// (for apps that use it for legacy reasons). This unfortunately leads to some code duplication.
- if (activity instanceof android.support.v4.app.FragmentActivity) {
- android.support.v4.app.FragmentManager fragmentManager =
- ((android.support.v4.app.FragmentActivity) activity).getSupportFragmentManager();
- android.support.v4.app.DialogFragment oldFragment =
- (android.support.v4.app.DialogFragment) fragmentManager.findFragmentByTag(FRAGMENT_TAG);
- if (oldFragment != null) {
- oldFragment.dismiss();
- }
- SupportTimePickerDialogFragment fragment = new SupportTimePickerDialogFragment();
- if (options != null) {
- Bundle args = createFragmentArguments(options);
- fragment.setArguments(args);
- }
- TimePickerDialogListener listener = new TimePickerDialogListener(promise);
- fragment.setOnDismissListener(listener);
- fragment.setOnTimeSetListener(listener);
- fragment.show(fragmentManager, FRAGMENT_TAG);
- } else {
- FragmentManager fragmentManager = activity.getFragmentManager();
+ FragmentManager fragmentManager = activity.getSupportFragmentManager();
DialogFragment oldFragment = (DialogFragment) fragmentManager.findFragmentByTag(FRAGMENT_TAG);
if (oldFragment != null) {
oldFragment.dismiss();
}
TimePickerDialogFragment fragment = new TimePickerDialogFragment();
if (options != null) {
- final Bundle args = createFragmentArguments(options);
+ Bundle args = createFragmentArguments(options);
fragment.setArguments(args);
}
TimePickerDialogListener listener = new TimePickerDialogListener(promise);
@@ -134,7 +116,6 @@
fragment.setOnTimeSetListener(listener);
fragment.show(fragmentManager, FRAGMENT_TAG);
}
- }
private Bundle createFragmentArguments(ReadableMap options) {
final Bundle args = new Bundle();

ReactAndroid/src/main/java/com/facebook/react/modules/timepicker/TimePickerMode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/modules/toast/ToastModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -21,7 +21,7 @@
/**
* {@link NativeModule} that allows JS to show an Android Toast.
*/
-@ReactModule(name = "ToastAndroid")
+@ReactModule(name = ToastModule.NAME)
public class ToastModule extends ReactContextBaseJavaModule {
private static final String DURATION_SHORT_KEY = "SHORT";
@@ -30,6 +30,7 @@
private static final String GRAVITY_TOP_KEY = "TOP";
private static final String GRAVITY_BOTTOM_KEY = "BOTTOM";
private static final String GRAVITY_CENTER = "CENTER";
+ public static final String NAME = "ToastAndroid";
public ToastModule(ReactApplicationContext reactContext) {
super(reactContext);
@@ -37,7 +38,7 @@
@Override
public String getName() {
- return "ToastAndroid";
+ return NAME;
}
@Override

ReactAndroid/src/main/java/com/facebook/react/modules/vibration/VibrationModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,6 +7,7 @@
package com.facebook.react.modules.vibration;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Vibrator;
@@ -16,16 +17,19 @@
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.module.annotations.ReactModule;
-@ReactModule(name = "Vibration")
+@SuppressLint("MissingPermission")
+@ReactModule(name = VibrationModule.NAME)
public class VibrationModule extends ReactContextBaseJavaModule {
+ public static final String NAME = "Vibration";
+
public VibrationModule(ReactApplicationContext reactContext) {
super(reactContext);
}
@Override
public String getName() {
- return "Vibration";
+ return NAME;
}
@ReactMethod

ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -25,10 +25,10 @@
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
-import java.util.concurrent.ConcurrentHashMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
import okhttp3.OkHttpClient;
@@ -38,9 +38,9 @@
import okhttp3.WebSocketListener;
import okio.ByteString;
-@ReactModule(name = "WebSocketModule", hasConstants = false)
+@ReactModule(name = WebSocketModule.NAME, hasConstants = false)
public final class WebSocketModule extends ReactContextBaseJavaModule {
-
+ public static final String NAME="WebSocketModule";
public interface ContentHandler {
void onMessage(String text, WritableMap params);
@@ -67,7 +67,7 @@
@Override
public String getName() {
- return "WebSocketModule";
+ return NAME;
}
public void setContentHandler(final int id, final ContentHandler contentHandler) {

ReactAndroid/src/main/java/com/facebook/react/NativeModuleRegistryBuilder.java

@@ -1,128 +1,77 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import com.facebook.common.logging.FLog;
-import com.facebook.react.bridge.BaseJavaModule;
-import com.facebook.react.bridge.ModuleSpec;
import com.facebook.react.bridge.ModuleHolder;
-import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.NativeModuleRegistry;
-import com.facebook.react.bridge.OnBatchCompleteListener;
import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.ReactMarker;
-import com.facebook.react.bridge.ReactMarkerConstants;
-import com.facebook.react.common.ReactConstants;
-import com.facebook.react.module.model.ReactModuleInfo;
-
-/**
- * Helper class to build NativeModuleRegistry.
- */
+import com.facebook.react.config.ReactFeatureFlags;
+import java.util.HashMap;
+import java.util.Map;
+
+/** Helper class to build NativeModuleRegistry. */
public class NativeModuleRegistryBuilder {
private final ReactApplicationContext mReactApplicationContext;
private final ReactInstanceManager mReactInstanceManager;
private final Map<String, ModuleHolder> mModules = new HashMap<>();
- private final Map<String,String> namesToType = new HashMap<>();
public NativeModuleRegistryBuilder(
- ReactApplicationContext reactApplicationContext,
- ReactInstanceManager reactInstanceManager) {
+ ReactApplicationContext reactApplicationContext, ReactInstanceManager reactInstanceManager) {
mReactApplicationContext = reactApplicationContext;
mReactInstanceManager = reactInstanceManager;
}
public void processPackage(ReactPackage reactPackage) {
+ // We use an iterable instead of an iterator here to ensure thread safety, and that this list
+ // cannot be modified
+ Iterable<ModuleHolder> moduleHolders;
if (reactPackage instanceof LazyReactPackage) {
- LazyReactPackage lazyReactPackage = (LazyReactPackage) reactPackage;
- List<ModuleSpec> moduleSpecs = lazyReactPackage.getNativeModules(mReactApplicationContext);
- Map<String, ReactModuleInfo> reactModuleInfoMap =
- lazyReactPackage.getReactModuleInfoProvider().getReactModuleInfos();
-
- for (ModuleSpec moduleSpec : moduleSpecs) {
- String className = moduleSpec.getClassName();
- ReactModuleInfo reactModuleInfo = reactModuleInfoMap.get(className);
- ModuleHolder moduleHolder;
- if (reactModuleInfo == null) {
- NativeModule module;
- ReactMarker.logMarker(
- ReactMarkerConstants.CREATE_MODULE_START,
- moduleSpec.getClassName());
- try {
- module = moduleSpec.getProvider().get();
- } finally {
- ReactMarker.logMarker(ReactMarkerConstants.CREATE_MODULE_END);
- }
- moduleHolder = new ModuleHolder(module);
+ moduleHolders =
+ ((LazyReactPackage) reactPackage).getNativeModuleIterator(mReactApplicationContext);
+ } else if (reactPackage instanceof TurboReactPackage) {
+ moduleHolders =
+ ((TurboReactPackage) reactPackage).getNativeModuleIterator(mReactApplicationContext);
} else {
- moduleHolder = new ModuleHolder(reactModuleInfo, moduleSpec.getProvider());
+ moduleHolders =
+ ReactPackageHelper.getNativeModuleIterator(
+ reactPackage, mReactApplicationContext, mReactInstanceManager);
}
+ for (ModuleHolder moduleHolder : moduleHolders) {
String name = moduleHolder.getName();
- putModuleTypeAndHolderToModuleMaps(className, name, moduleHolder);
- }
- } else {
- FLog.d(
- ReactConstants.TAG,
- reactPackage.getClass().getSimpleName()
- + " is not a LazyReactPackage, falling back to old version.");
- List<NativeModule> nativeModules;
- if (reactPackage instanceof ReactInstancePackage) {
- ReactInstancePackage reactInstancePackage = (ReactInstancePackage) reactPackage;
- nativeModules =
- reactInstancePackage.createNativeModules(
- mReactApplicationContext, mReactInstanceManager);
- } else {
- nativeModules = reactPackage.createNativeModules(mReactApplicationContext);
- }
- for (NativeModule nativeModule : nativeModules) {
- addNativeModule(nativeModule);
- }
- }
- }
-
- public void addNativeModule(NativeModule nativeModule) {
- String name = nativeModule.getName();
- Class<? extends NativeModule> type = nativeModule.getClass();
- putModuleTypeAndHolderToModuleMaps(type.getName(), name, new ModuleHolder(nativeModule));
- }
-
- private void putModuleTypeAndHolderToModuleMaps(
- String className, String underName, ModuleHolder moduleHolder)
- throws IllegalStateException {
- if (namesToType.containsKey(underName)) {
- String existingNativeModule = namesToType.get(underName);
+ if (mModules.containsKey(name)) {
+ ModuleHolder existingNativeModule = mModules.get(name);
if (!moduleHolder.getCanOverrideExistingModule()) {
throw new IllegalStateException(
"Native module "
- + className
+ + name
+ " tried to override "
- + existingNativeModule
- + " for module name "
- + underName
- + ". Check the getPackages() method in MainApplication.java, it might be "
- + "that module is being created twice. "
- + "If this was your intention, set canOverrideExistingModule=true");
+ + existingNativeModule.getClassName()
+ + " for module name .Check the getPackages() method in MainApplication.java, it might be that module is being created twice. If this was your intention, set canOverrideExistingModule=true");
}
-
mModules.remove(existingNativeModule);
}
+ if (ReactFeatureFlags.useTurboModules && moduleHolder.isTurboModule()) {
+ // If this module is a TurboModule, and if TurboModules are enabled, don't add this module
- namesToType.put(underName, className);
- mModules.put(className, moduleHolder);
+ // This condition is after checking for overrides, since if there is already a module,
+ // and we want to override it with a turbo module, we would need to remove the modules thats
+ // already in the list, and then NOT add the new module, since that will be directly exposed
+
+ // Note that is someone uses {@link NativeModuleRegistry#registerModules}, we will NOT check
+ // for TurboModules - assuming that people wanted to explicitly register native modules there
+ continue;
+ }
+ mModules.put(name, moduleHolder);
+ }
}
public NativeModuleRegistry build() {
- return new NativeModuleRegistry(
- mReactApplicationContext, mModules);
+ return new NativeModuleRegistry(mReactApplicationContext, mModules);
}
}

ReactAndroid/src/main/java/com/facebook/react/packagerconnection/FileIoHandler.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/packagerconnection/JSPackagerClient.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/packagerconnection/NotificationOnlyHandler.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/packagerconnection/PackagerConnectionSettings.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/packagerconnection/ReconnectingWebSocket.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/packagerconnection/RequestHandler.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/packagerconnection/RequestOnlyHandler.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/packagerconnection/Responder.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/processing/ReactPropertyProcessor.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -11,7 +11,6 @@
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
-import android.support.v4.app.FragmentActivity;
import android.view.KeyEvent;
import com.facebook.infer.annotation.Assertions;
@@ -30,7 +29,6 @@
public class ReactActivityDelegate {
private final @Nullable Activity mActivity;
- private final @Nullable FragmentActivity mFragmentActivity;
private final @Nullable String mMainComponentName;
private @Nullable ReactRootView mReactRootView;
@@ -38,18 +36,15 @@
private @Nullable PermissionListener mPermissionListener;
private @Nullable Callback mPermissionsCallback;
+ @Deprecated
public ReactActivityDelegate(Activity activity, @Nullable String mainComponentName) {
mActivity = activity;
mMainComponentName = mainComponentName;
- mFragmentActivity = null;
}
- public ReactActivityDelegate(
- FragmentActivity fragmentActivity,
- @Nullable String mainComponentName) {
- mFragmentActivity = fragmentActivity;
+ public ReactActivityDelegate(ReactActivity activity, @Nullable String mainComponentName) {
+ mActivity = activity;
mMainComponentName = mainComponentName;
- mActivity = null;
}
protected @Nullable Bundle getLaunchOptions() {
@@ -205,14 +200,11 @@
};
}
- private Context getContext() {
- if (mActivity != null) {
- return mActivity;
- }
- return Assertions.assertNotNull(mFragmentActivity);
+ protected Context getContext() {
+ return Assertions.assertNotNull(mActivity);
}
- private Activity getPlainActivity() {
+ protected Activity getPlainActivity() {
return ((Activity) getContext());
}
}

ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,9 +9,9 @@
import javax.annotation.Nullable;
-import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
import android.view.KeyEvent;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
@@ -21,7 +21,7 @@
/**
* Base Activity for React Native applications.
*/
-public abstract class ReactActivity extends Activity
+public abstract class ReactActivity extends AppCompatActivity
implements DefaultHardwareBackBtnHandler, PermissionAwareActivity {
private final ReactActivityDelegate mDelegate;

ReactAndroid/src/main/java/com/facebook/react/ReactAndroidHWInputDeviceHelper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/ReactApplication.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/ReactFragmentActivity.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,126 +7,11 @@
package com.facebook.react;
-import javax.annotation.Nullable;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.v4.app.FragmentActivity;
-import android.view.KeyEvent;
-
-import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
-import com.facebook.react.modules.core.PermissionAwareActivity;
-import com.facebook.react.modules.core.PermissionListener;
-
/**
* @deprecated
- * ReactFragmentActivity will be removed in 0.57 release.
+ * ReactFragmentActivity will be removed in 0.59 release.
* Use {@link ReactActivity} instead.
*/
@Deprecated
-public abstract class ReactFragmentActivity extends FragmentActivity implements
- DefaultHardwareBackBtnHandler, PermissionAwareActivity {
-
- private final ReactActivityDelegate mDelegate;
-
- protected ReactFragmentActivity() {
- mDelegate = createReactActivityDelegate();
- }
-
- /**
- * Returns the name of the main component registered from JavaScript.
- * This is used to schedule rendering of the component.
- * e.g. "MoviesApp"
- */
- protected @Nullable String getMainComponentName() {
- return null;
- }
-
- /**
- * Called at construction time, override if you have a custom delegate implementation.
- */
- protected ReactActivityDelegate createReactActivityDelegate() {
- return new ReactActivityDelegate(this, getMainComponentName());
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- mDelegate.onCreate(savedInstanceState);
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- mDelegate.onPause();
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- mDelegate.onResume();
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- mDelegate.onDestroy();
- }
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- mDelegate.onActivityResult(requestCode, resultCode, data);
- }
-
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- return mDelegate.onKeyUp(keyCode, event) || super.onKeyUp(keyCode, event);
- }
-
- @Override
- public void onBackPressed() {
- if (!mDelegate.onBackPressed()) {
- super.onBackPressed();
- }
- }
-
- @Override
- public void invokeDefaultOnBackPressed() {
- super.onBackPressed();
- }
-
- @Override
- public void onNewIntent(Intent intent) {
- if (!mDelegate.onNewIntent(intent)) {
- super.onNewIntent(intent);
- }
- }
-
- @Override
- public void requestPermissions(
- String[] permissions,
- int requestCode,
- PermissionListener listener) {
- mDelegate.requestPermissions(permissions, requestCode, listener);
- }
-
- @Override
- public void onRequestPermissionsResult(
- int requestCode,
- String[] permissions,
- int[] grantResults) {
- mDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults);
- }
-
- protected final ReactNativeHost getReactNativeHost() {
- return mDelegate.getReactNativeHost();
- }
-
- protected final ReactInstanceManager getReactInstanceManager() {
- return mDelegate.getReactInstanceManager();
- }
-
- protected final void loadApp(String appKey) {
- mDelegate.loadApp(appKey);
- }
+public abstract class ReactFragmentActivity extends ReactActivity {
}

ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -11,7 +11,6 @@
import android.app.Application;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.JSBundleLoader;
-import com.facebook.react.bridge.JSCJavaScriptExecutorFactory;
import com.facebook.react.bridge.JSIModulePackage;
import com.facebook.react.bridge.JavaScriptExecutorFactory;
import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
@@ -20,6 +19,7 @@
import com.facebook.react.devsupport.RedBoxHandler;
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener;
import com.facebook.react.devsupport.interfaces.DevSupportManager;
+import com.facebook.react.jscexecutor.JSCExecutorFactory;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.packagerconnection.RequestHandler;
import com.facebook.react.uimanager.UIImplementationProvider;
@@ -268,7 +268,7 @@
mCurrentActivity,
mDefaultHardwareBackBtnHandler,
mJavaScriptExecutorFactory == null
- ? new JSCJavaScriptExecutorFactory(appName, deviceName)
+ ? new JSCExecutorFactory(appName, deviceName)
: mJavaScriptExecutorFactory,
(mJSBundleLoader == null && mJSBundleAssetUrl != null)
? JSBundleLoader.createAssetLoader(

ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -25,6 +25,8 @@
import static com.facebook.react.bridge.ReactMarkerConstants.REACT_CONTEXT_THREAD_START;
import static com.facebook.react.bridge.ReactMarkerConstants.SETUP_REACT_CONTEXT_END;
import static com.facebook.react.bridge.ReactMarkerConstants.SETUP_REACT_CONTEXT_START;
+import static com.facebook.react.bridge.ReactMarkerConstants.CHANGE_THREAD_PRIORITY;
+import static com.facebook.react.bridge.ReactMarkerConstants.VM_INIT;
import static com.facebook.react.uimanager.common.UIManagerType.FABRIC;
import static com.facebook.systrace.Systrace.TRACE_TAG_REACT_APPS;
import static com.facebook.systrace.Systrace.TRACE_TAG_REACT_JAVA_BRIDGE;
@@ -34,6 +36,7 @@
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
+import android.os.Bundle;
import android.os.Process;
import android.support.v4.view.ViewCompat;
import android.util.Log;
@@ -44,6 +47,7 @@
import com.facebook.infer.annotation.Assertions;
import com.facebook.infer.annotation.ThreadConfined;
import com.facebook.infer.annotation.ThreadSafe;
+import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.CatalystInstance;
import com.facebook.react.bridge.CatalystInstanceImpl;
import com.facebook.react.bridge.JSBundleLoader;
@@ -62,6 +66,7 @@
import com.facebook.react.bridge.ReactMarkerConstants;
import com.facebook.react.bridge.UIManager;
import com.facebook.react.bridge.UiThreadUtil;
+import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.bridge.queue.ReactQueueConfigurationSpec;
import com.facebook.react.common.LifecycleState;
import com.facebook.react.common.ReactConstants;
@@ -94,6 +99,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.Nullable;
/**
@@ -129,8 +135,8 @@
void onReactContextInitialized(ReactContext context);
}
- private final List<ReactRootView> mAttachedRootViews = Collections.synchronizedList(
- new ArrayList<ReactRootView>());
+ private final Set<ReactRootView> mAttachedRootViews = Collections.synchronizedSet(
+ new HashSet<ReactRootView>());
private volatile LifecycleState mLifecycleState;
@@ -222,6 +228,8 @@
mJSMainModulePath = jsMainModulePath;
mPackages = new ArrayList<>();
mUseDeveloperSupport = useDeveloperSupport;
+ Systrace.beginSection(
+ Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "ReactInstanceManager.initDevSupportManager");
mDevSupportManager =
DevSupportManagerFactory.create(
applicationContext,
@@ -232,6 +240,7 @@
devBundleDownloadListener,
minNumShakes,
customPackagerCommandHandlers);
+ Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
mBridgeIdleDebugListener = bridgeIdleDebugListener;
mLifecycleState = initialLifecycleState;
mMemoryPressureRouter = new MemoryPressureRouter(applicationContext);
@@ -353,9 +362,7 @@
.logMessage(ReactDebugOverlayTags.RN_CORE, "RNCore: recreateReactContextInBackground");
UiThreadUtil.assertOnUiThread();
- if (mUseDeveloperSupport
- && mJSMainModulePath != null
- && !Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JS_VM_CALLS)) {
+ if (mUseDeveloperSupport && mJSMainModulePath != null) {
final DeveloperSettings devSettings = mDevSupportManager.getDevSettings();
// If remote JS debugging is enabled, load from dev server.
@@ -364,7 +371,11 @@
// If there is a up-to-date bundle downloaded from server,
// with remote JS debugging disabled, always use that.
onJSBundleLoadedFromServer(null);
- } else if (mBundleLoader == null) {
+ return;
+ }
+
+ if (!Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JS_VM_CALLS)) {
+ if (mBundleLoader == null) {
mDevSupportManager.handleReloadJS();
} else {
mDevSupportManager.isPackagerRunning(
@@ -389,6 +400,7 @@
}
return;
}
+ }
recreateReactContextInBackgroundFromBundleLoader();
}
@@ -732,13 +743,16 @@
@ThreadConfined(UI)
public void detachRootView(ReactRootView rootView) {
UiThreadUtil.assertOnUiThread();
- if (mAttachedRootViews.remove(rootView)) {
+ synchronized (mAttachedRootViews) {
+ if (mAttachedRootViews.contains(rootView)) {
ReactContext currentContext = getCurrentReactContext();
+ mAttachedRootViews.remove(rootView);
if (currentContext != null && currentContext.hasActiveCatalystInstance()) {
detachViewFromInstance(rootView, currentContext.getCatalystInstance());
}
}
}
+ }
/**
* Uses configured {@link ReactPackage} instances to create all view managers.
@@ -791,6 +805,7 @@
}
public @Nullable List<String> getViewManagerNames() {
+ Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "ReactInstanceManager.getViewManagerNames");
ReactApplicationContext context;
synchronized(mReactContextLock) {
context = (ReactApplicationContext) getCurrentReactContext();
@@ -802,15 +817,19 @@
synchronized (mPackages) {
Set<String> uniqueNames = new HashSet<>();
for (ReactPackage reactPackage : mPackages) {
+ SystraceMessage.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "ReactInstanceManager.getViewManagerName")
+ .arg("Package", reactPackage.getClass().getSimpleName())
+ .flush();
if (reactPackage instanceof ViewManagerOnDemandReactPackage) {
List<String> names =
- ((ViewManagerOnDemandReactPackage) reactPackage)
- .getViewManagerNames(context);
+ ((ViewManagerOnDemandReactPackage) reactPackage).getViewManagerNames(context);
if (names != null) {
uniqueNames.addAll(names);
}
}
+ SystraceMessage.endSection(TRACE_TAG_REACT_JAVA_BRIDGE).flush();
}
+ Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
return new ArrayList<>(uniqueNames);
}
}
@@ -840,6 +859,10 @@
return mLifecycleState;
}
+ public String getJsExecutorName() {
+ return mJavaScriptExecutorFactory.toString();
+ }
+
@ThreadConfined(UI)
private void onReloadWithJSDebugger(JavaJSExecutor.Factory jsExecutorFactory) {
Log.d(ReactConstants.TAG, "ReactInstanceManager.onReloadWithJSDebugger()");
@@ -885,15 +908,18 @@
private void runCreateReactContextOnNewThread(final ReactContextInitParams initParams) {
Log.d(ReactConstants.TAG, "ReactInstanceManager.runCreateReactContextOnNewThread()");
UiThreadUtil.assertOnUiThread();
+ synchronized (mAttachedRootViews) {
synchronized (mReactContextLock) {
if (mCurrentReactContext != null) {
tearDownReactContext(mCurrentReactContext);
mCurrentReactContext = null;
}
}
+ }
mCreateReactContextThread =
new Thread(
+ null,
new Runnable() {
@Override
public void run() {
@@ -912,6 +938,7 @@
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
+ ReactMarker.logMarker(VM_INIT);
final ReactApplicationContext reactApplicationContext =
createReactContext(
initParams.getJsExecutorFactory().create(),
@@ -947,7 +974,8 @@
mDevSupportManager.handleException(e);
}
}
- });
+ },
+ "create_react_context");
ReactMarker.logMarker(REACT_CONTEXT_THREAD_START);
mCreateReactContextThread.start();
}
@@ -957,6 +985,7 @@
ReactMarker.logMarker(PRE_SETUP_REACT_CONTEXT_END);
ReactMarker.logMarker(SETUP_REACT_CONTEXT_START);
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "setupReactContext");
+ synchronized (mAttachedRootViews) {
synchronized (mReactContextLock) {
mCurrentReactContext = Assertions.assertNotNull(reactContext);
}
@@ -969,12 +999,11 @@
moveReactContextToCurrentLifecycleState();
ReactMarker.logMarker(ATTACH_MEASURED_ROOT_VIEWS_START);
- synchronized (mAttachedRootViews) {
for (ReactRootView rootView : mAttachedRootViews) {
attachRootViewToInstance(rootView);
}
- }
ReactMarker.logMarker(ATTACH_MEASURED_ROOT_VIEWS_END);
+ }
ReactInstanceEventListener[] listeners =
new ReactInstanceEventListener[mReactInstanceEventListeners.size()];
@@ -997,6 +1026,7 @@
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
+ ReactMarker.logMarker(CHANGE_THREAD_PRIORITY, "js_default");
}
});
reactContext.runOnNativeModulesQueueThread(
@@ -1008,12 +1038,17 @@
});
}
- private void attachRootViewToInstance(
- final ReactRootView rootView) {
+ private void attachRootViewToInstance(final ReactRootView rootView) {
Log.d(ReactConstants.TAG, "ReactInstanceManager.attachRootViewToInstance()");
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "attachRootViewToInstance");
UIManager uiManagerModule = UIManagerHelper.getUIManager(mCurrentReactContext, rootView.getUIManagerType());
- final int rootTag = uiManagerModule.addRootView(rootView);
+
+ @Nullable Bundle initialProperties = rootView.getAppProperties();
+ final int rootTag = uiManagerModule.addRootView(
+ rootView,
+ initialProperties == null ?
+ new WritableNativeMap() : Arguments.fromBundle(initialProperties),
+ rootView.getInitialUITemplate());
rootView.setRootViewTag(rootTag);
rootView.runApplication();
Systrace.beginAsyncSection(
@@ -1113,9 +1148,13 @@
catalystInstance.setGlobalVariable("__RCTProfileIsProfiling", "true");
}
ReactMarker.logMarker(ReactMarkerConstants.PRE_RUN_JS_BUNDLE_START);
+ Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "runJSBundle");
catalystInstance.runJSBundle();
+ Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
+
reactContext.initializeWithInstance(catalystInstance);
+
return reactContext;
}

ReactAndroid/src/main/java/com/facebook/react/ReactInstancePackage.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/ReactPackageHelper.java

@@ -0,0 +1,69 @@
+/**
+ * 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;
+
+import android.support.annotation.NonNull;
+import com.facebook.common.logging.FLog;
+import com.facebook.react.bridge.ModuleHolder;
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.common.ReactConstants;
+import java.util.Iterator;
+import java.util.List;
+
+public class ReactPackageHelper {
+ /**
+ * A helper method to iterate over a list of Native Modules and convert them to an iterable.
+ *
+ * @param reactPackage
+ * @param reactApplicationContext
+ * @param reactInstanceManager
+ * @return
+ */
+ public static Iterable<ModuleHolder> getNativeModuleIterator(
+ ReactPackage reactPackage,
+ ReactApplicationContext reactApplicationContext,
+ ReactInstanceManager reactInstanceManager) {
+ FLog.d(
+ ReactConstants.TAG,
+ reactPackage.getClass().getSimpleName()
+ + " is not a LazyReactPackage, falling back to old version.");
+ final List<NativeModule> nativeModules;
+ if (reactPackage instanceof ReactInstancePackage) {
+ ReactInstancePackage reactInstancePackage = (ReactInstancePackage) reactPackage;
+ nativeModules =
+ reactInstancePackage.createNativeModules(reactApplicationContext, reactInstanceManager);
+ } else {
+ nativeModules = reactPackage.createNativeModules(reactApplicationContext);
+ }
+ return new Iterable<ModuleHolder>() {
+ @NonNull
+ @Override
+ public Iterator<ModuleHolder> iterator() {
+ return new Iterator<ModuleHolder>() {
+ int position = 0;
+
+ @Override
+ public ModuleHolder next() {
+ return new ModuleHolder(nativeModules.get(position++));
+ }
+
+ @Override
+ public boolean hasNext() {
+ return position < nativeModules.size();
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("Cannot remove methods ");
+ }
+ };
+ }
+ };
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/ReactPackage.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,13 +7,13 @@
package com.facebook.react;
-import java.util.List;
-
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.ViewManager;
+import java.util.List;
+
+import javax.annotation.Nonnull;
/**
* Main interface for providing additional capabilities to the catalyst framework by couple of
@@ -34,10 +34,12 @@
* @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
*/
- List<NativeModule> createNativeModules(ReactApplicationContext reactContext);
+ @Nonnull
+ List<NativeModule> createNativeModules(@Nonnull ReactApplicationContext reactContext);
/**
* @return a list of view managers that should be registered with {@link UIManagerModule}
*/
- List<ViewManager> createViewManagers(ReactApplicationContext reactContext);
+ @Nonnull
+ List<ViewManager> createViewManagers(@Nonnull ReactApplicationContext reactContext);
}

ReactAndroid/src/main/java/com/facebook/react/ReactPackageLogger.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -29,7 +29,6 @@
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.CatalystInstance;
-import com.facebook.react.bridge.GuardedRunnable;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactMarker;
import com.facebook.react.bridge.ReactMarkerConstants;
@@ -48,7 +47,6 @@
import com.facebook.react.uimanager.RootView;
import com.facebook.react.uimanager.UIManagerHelper;
import com.facebook.react.uimanager.UIManagerModule;
-import com.facebook.react.uimanager.ViewProps;
import com.facebook.react.uimanager.common.MeasureSpecProvider;
import com.facebook.react.uimanager.common.SizeMonitoringFrameLayout;
import com.facebook.react.uimanager.common.UIManagerType;
@@ -84,6 +82,7 @@
private @Nullable ReactInstanceManager mReactInstanceManager;
private @Nullable String mJSModuleName;
private @Nullable Bundle mAppProperties;
+ private @Nullable String mInitialUITemplate;
private @Nullable CustomGlobalLayoutListener mCustomGlobalLayoutListener;
private @Nullable ReactRootViewEventListener mRootViewEventListener;
private int mRootViewTag;
@@ -309,6 +308,7 @@
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (mIsAttachedToInstance) {
+ removeOnGlobalLayoutListener();
getViewTreeObserver().addOnGlobalLayoutListener(getCustomGlobalLayoutListener());
}
}
@@ -317,12 +317,12 @@
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mIsAttachedToInstance) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
- getViewTreeObserver().removeOnGlobalLayoutListener(getCustomGlobalLayoutListener());
- } else {
- getViewTreeObserver().removeGlobalOnLayoutListener(getCustomGlobalLayoutListener());
+ removeOnGlobalLayoutListener();
}
}
+
+ private void removeOnGlobalLayoutListener() {
+ getViewTreeObserver().removeOnGlobalLayoutListener(getCustomGlobalLayoutListener());
}
@Override
@@ -346,6 +346,13 @@
}
/**
+ * {@see #startReactApplication(ReactInstanceManager, String, android.os.Bundle, String)}
+ */
+ public void startReactApplication(ReactInstanceManager reactInstanceManager, String moduleName, @Nullable Bundle initialProperties) {
+ startReactApplication(reactInstanceManager, moduleName, initialProperties, null);
+ }
+
+ /**
* Schedule rendering of the react component rendered by the JS application from the given JS
* module (@{param moduleName}) using provided {@param reactInstanceManager} to attach to the
* JS context of that manager. Extra parameter {@param launchOptions} can be used to pass initial
@@ -354,7 +361,8 @@
public void startReactApplication(
ReactInstanceManager reactInstanceManager,
String moduleName,
- @Nullable Bundle initialProperties) {
+ @Nullable Bundle initialProperties,
+ @Nullable String initialUITemplate) {
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "startReactApplication");
try {
UiThreadUtil.assertOnUiThread();
@@ -369,6 +377,7 @@
mReactInstanceManager = reactInstanceManager;
mJSModuleName = moduleName;
mAppProperties = initialProperties;
+ mInitialUITemplate = initialUITemplate;
if (!mReactInstanceManager.hasStartedCreatingInitialContext()) {
mReactInstanceManager.createReactContextInBackground();
@@ -406,17 +415,11 @@
return;
}
final ReactContext reactApplicationContext = mReactInstanceManager.getCurrentReactContext();
+
if (reactApplicationContext != null) {
- reactApplicationContext.runOnNativeModulesQueueThread(
- new GuardedRunnable(reactApplicationContext) {
- @Override
- public void runGuarded() {
- UIManagerHelper
- .getUIManager(reactApplicationContext, getUIManagerType())
+ UIManagerHelper.getUIManager(reactApplicationContext, getUIManagerType())
.updateRootLayoutSpecs(getRootViewTag(), widthMeasureSpec, heightMeasureSpec);
}
- });
- }
}
/**
@@ -457,6 +460,10 @@
return mAppProperties;
}
+ public @Nullable String getInitialUITemplate() {
+ return mInitialUITemplate;
+ }
+
public void setAppProperties(@Nullable Bundle appProperties) {
UiThreadUtil.assertOnUiThread();
mAppProperties = appProperties;
@@ -658,7 +665,7 @@
}
private boolean areMetricsEqual(DisplayMetrics displayMetrics, DisplayMetrics otherMetrics) {
- if (Build.VERSION.SDK_INT >= 17) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
return displayMetrics.equals(otherMetrics);
} else {
// DisplayMetrics didn't have an equals method before API 17.

ReactAndroid/src/main/java/com/facebook/react/shell/MainPackageConfig.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/touch/JSResponderHandler.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/touch/OnInterceptTouchEventListener.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/touch/ReactHitSlopView.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/touch/ReactInterceptingViewGroup.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/BUCK

@@ -0,0 +1,25 @@
+load("//tools/build_defs/oss:rn_defs.bzl", "react_native_dep", "react_native_target", "rn_android_library")
+
+rn_android_library(
+ name = "core",
+ srcs = glob(
+ [
+ "*.java",
+ ],
+ ),
+ required_for_source_only_abi = True,
+ visibility = [
+ "PUBLIC",
+ ],
+ deps = [
+ react_native_target("java/com/facebook/react/turbomodule/core/interfaces:interfaces"),
+ react_native_dep("java/com/facebook/systrace:systrace"),
+ react_native_dep("libraries/soloader/java/com/facebook/soloader:soloader"),
+ 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/turbomodule/core/jni:jni"),
+ react_native_target("java/com/facebook/debug/holder:holder"),
+ react_native_target("java/com/facebook/react/bridge:interfaces"),
+ react_native_target("java/com/facebook/react/bridge:bridge"),
+ ],
+)

ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/interfaces/BUCK

@@ -0,0 +1,12 @@
+load("//tools/build_defs/oss:rn_defs.bzl", "rn_android_library")
+
+rn_android_library(
+ name = "interfaces",
+ srcs = [
+ "TurboModule.java",
+ ],
+ required_for_source_only_abi = True,
+ visibility = [
+ "PUBLIC",
+ ],
+)

ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/interfaces/TurboModule.java

@@ -0,0 +1,16 @@
+/**
+ * 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.turbomodule.core.interfaces;
+
+/**
+ * All turbo modules should inherit from this interface
+ */
+public interface TurboModule {
+ /** When CatalystInstance is destroyed, this method will be called. All implementing TurboModules can perform cleanup here. */
+ void invalidate();
+}

ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/BUCK

@@ -0,0 +1,38 @@
+load("@fbsource//tools/build_defs:glob_defs.bzl", "subdir_glob")
+load("@fbsource//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "react_native_target", "react_native_xplat_target", "rn_xplat_cxx_library")
+
+rn_xplat_cxx_library(
+ name = "jni",
+ srcs = glob(["**/*.cpp"]),
+ header_namespace = "",
+ exported_headers = subdir_glob(
+ [
+ ("", "**/*.h"),
+ ],
+ prefix = "jsireact",
+ ),
+ compiler_flags = [
+ "-fexceptions",
+ "-frtti",
+ "-std=c++14",
+ "-Wall",
+ ],
+ force_static = True,
+ platforms = ANDROID,
+ preprocessor_flags = [
+ "-DLOG_TAG=\"ReactNative\"",
+ "-DWITH_FBSYSTRACE=1",
+ ],
+ visibility = [
+ "PUBLIC",
+ ],
+ deps = [
+ react_native_target("jni/react/jni:jni"),
+ "xplat//jsi:JSIDynamic",
+ "xplat//jsi:jsi",
+ ],
+ exported_deps = [
+ "xplat//jsi:jsi",
+ react_native_xplat_target("turbomodule/core:core"),
+ ],
+)

ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/TurboModuleManager.cpp

@@ -0,0 +1,74 @@
+/**
+ * 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.
+ */
+
+#include <memory>
+#include <string>
+
+#include <fb/fbjni.h>
+#include <jsi/jsi.h>
+
+#include <jsireact/TurboModuleBinding.h>
+
+#include <react/jni/JMessageQueueThread.h>
+
+#include "TurboModuleManager.h"
+
+namespace facebook {
+namespace react {
+
+static JTurboModuleProviderFunctionType moduleProvider_ = nullptr;
+
+TurboModuleManager::TurboModuleManager(
+ jni::alias_ref<TurboModuleManager::javaobject> jThis,
+ jsi::Runtime* rt,
+ std::shared_ptr<JMessageQueueThread> jsMessageQueueThread
+):
+ javaPart_(make_global(jThis)),
+ runtime_(rt),
+ jsMessageQueueThread_(jsMessageQueueThread)
+ {}
+
+jni::local_ref<TurboModuleManager::jhybriddata> TurboModuleManager::initHybrid(
+ jni::alias_ref<jhybridobject> jThis,
+ jlong jsContext,
+ jni::alias_ref<JavaMessageQueueThread::javaobject> jsQueue
+) {
+ auto sharedJSMessageQueueThread = std::make_shared<JMessageQueueThread> (jsQueue);
+ return makeCxxInstance(jThis, (jsi::Runtime *) jsContext, sharedJSMessageQueueThread);
+}
+
+void TurboModuleManager::registerNatives() {
+ registerHybrid({
+ makeNativeMethod("initHybrid", TurboModuleManager::initHybrid),
+ makeNativeMethod("installJSIBindings", TurboModuleManager::installJSIBindings),
+ });
+}
+
+void TurboModuleManager::installJSIBindings() {
+ if (!runtime_) {
+ return; // Runtime doesn't exist when attached to Chrome debugger.
+ }
+ TurboModuleBinding::install(*runtime_, std::make_shared<TurboModuleBinding>(
+ [this](const std::string &name) {
+ const auto moduleInstance = getJavaModule(name);
+ const auto jsInvoker = std::make_shared<react::JSCallInvoker>(jsMessageQueueThread_);
+ return moduleProvider_(name, moduleInstance, jsInvoker);
+ })
+ );
+}
+
+jni::global_ref<JTurboModule> TurboModuleManager::getJavaModule(std::string name) {
+ static auto method = javaClassStatic()->getMethod<jni::alias_ref<JTurboModule>(const std::string&)>("getJavaModule");
+ return make_global(method(javaPart_.get(), name));
+}
+
+void TurboModuleManager::setModuleProvider(JTurboModuleProviderFunctionType fn) {
+ moduleProvider_ = fn;
+}
+
+} // namespace react
+} // namespace facebook

ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/TurboModuleManager.h

@@ -0,0 +1,49 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <fb/fbjni.h>
+#include <jsi/jsi.h>
+#include <jsireact/TurboModule.h>
+#include <jsireact/JavaTurboModule.h>
+#include <react/jni/JMessageQueueThread.h>
+
+namespace facebook {
+namespace react {
+
+using JTurboModuleProviderFunctionType = std::function<std::shared_ptr<TurboModule>(
+ const std::string &name, jni::global_ref<JTurboModule> moduleInstance, std::shared_ptr<JSCallInvoker> jsInvoker)>;
+
+class TurboModuleManager : public jni::HybridClass<TurboModuleManager> {
+public:
+ static auto constexpr kJavaDescriptor = "Lcom/facebook/react/turbomodule/core/TurboModuleManager;";
+ static jni::local_ref<jhybriddata> initHybrid(
+ jni::alias_ref<jhybridobject> jThis,
+ jlong jsContext,
+ jni::alias_ref<JavaMessageQueueThread::javaobject> jsQueue
+ );
+ static void registerNatives();
+ static void setModuleProvider(JTurboModuleProviderFunctionType moduleProvider);
+private:
+ friend HybridBase;
+ jni::global_ref<TurboModuleManager::javaobject> javaPart_;
+ jsi::Runtime* runtime_;
+ std::shared_ptr<JMessageQueueThread> jsMessageQueueThread_;
+
+ jni::global_ref<JTurboModule> getJavaModule(std::string name);
+ void installJSIBindings();
+ explicit TurboModuleManager(
+ jni::alias_ref<TurboModuleManager::jhybridobject> jThis,
+ jsi::Runtime* rt,
+ std::shared_ptr<JMessageQueueThread> jsMessageQueueThread
+ );
+};
+
+} // namespace react
+} // namespace facebook

ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManager.java

@@ -0,0 +1,76 @@
+/**
+ * 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.turbomodule.core;
+
+import com.facebook.jni.HybridData;
+import com.facebook.proguard.annotations.DoNotStrip;
+import com.facebook.react.bridge.JSIModule;
+import com.facebook.react.bridge.JavaScriptContextHolder;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.queue.MessageQueueThread;
+import com.facebook.react.turbomodule.core.interfaces.TurboModule;
+import com.facebook.soloader.SoLoader;
+
+/**
+* This is the main class and entry point for TurboModules.
+* Note that this is a hybrid class, and has a C++ counterpart
+* This class installs the JSI bindings. It also implements the method to get a Java module, that the C++ counterpart calls.
+*/
+public class TurboModuleManager implements JSIModule {
+ static {
+ SoLoader.loadLibrary("turbomodulejsijni");
+ }
+
+ private final ReactApplicationContext mReactApplicationContext;
+
+ @DoNotStrip
+ @SuppressWarnings("unused")
+ private final HybridData mHybridData;
+ private final ModuleProvider mModuleProvider;
+
+ public TurboModuleManager(
+ ReactApplicationContext reactApplicationContext, JavaScriptContextHolder jsContext, ModuleProvider moduleProvider) {
+ mReactApplicationContext = reactApplicationContext;
+ MessageQueueThread jsMessageQueueThread =
+ mReactApplicationContext
+ .getCatalystInstance()
+ .getReactQueueConfiguration()
+ .getJSQueueThread();
+ mHybridData = initHybrid(jsContext.get(), jsMessageQueueThread);
+ mModuleProvider = moduleProvider;
+ }
+
+ @DoNotStrip
+ @SuppressWarnings("unused")
+ protected TurboModule getJavaModule(String name) {
+ return mModuleProvider.getModule(name, mReactApplicationContext);
+ }
+
+ protected native HybridData initHybrid(long jsContext, MessageQueueThread jsQueue);
+
+ protected native void installJSIBindings();
+
+ public void installBindings() {
+ installJSIBindings();
+ }
+
+ protected ReactApplicationContext getReactApplicationContext() {
+ return mReactApplicationContext;
+ }
+
+ @Override
+ public void initialize() {}
+
+ @Override
+ public void onCatalystInstanceDestroy() {}
+
+ /** All applications must implement this interface, and provide the Java TurboModule class */
+ public interface ModuleProvider {
+ TurboModule getModule(String name, ReactApplicationContext reactApplicationContext);
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/TurboReactPackage.java

@@ -0,0 +1,126 @@
+/**
+ * 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;
+
+import android.support.annotation.NonNull;
+import com.facebook.react.bridge.ModuleHolder;
+import com.facebook.react.bridge.ModuleSpec;
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.module.model.ReactModuleInfo;
+import com.facebook.react.module.model.ReactModuleInfoProvider;
+import com.facebook.react.uimanager.ViewManager;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.inject.Provider;
+
+/** This will eventually replace {@link LazyReactPackage} when TurboModules are finally done. */
+public abstract class TurboReactPackage implements ReactPackage {
+
+ @Override
+ public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
+ throw new UnsupportedOperationException(
+ "In case of TurboModules, createNativeModules is not supported. NativeModuleRegistry should instead use getModuleList or getModule method");
+ }
+
+ /**
+ * The API needed for TurboModules. Given a module name, it returns an instance of {@link
+ * NativeModule} for the name
+ *
+ * @param name
+ * @param reactContext
+ * @return
+ */
+ public abstract NativeModule getModule(String name, final ReactApplicationContext reactContext);
+
+ /**
+ * This is a temporary method till we implement TurboModules. Once we implement TurboModules, we
+ * will be able to directly call {@link TurboReactPackage#getModule(String,
+ * ReactApplicationContext)} This method will be removed when TurboModule implementation is
+ * complete
+ *
+ * @param reactContext
+ * @return
+ */
+ public Iterable<ModuleHolder> getNativeModuleIterator(
+ final ReactApplicationContext reactContext) {
+ final Set<Map.Entry<String, ReactModuleInfo>> entrySet =
+ getReactModuleInfoProvider().getReactModuleInfos().entrySet();
+ final Iterator<Map.Entry<String, ReactModuleInfo>> entrySetIterator = entrySet.iterator();
+ return new Iterable<ModuleHolder>() {
+ @NonNull
+ @Override
+ // This should ideally be an IteratorConvertor, but we don't have any internal library for it
+ public Iterator<ModuleHolder> iterator() {
+ return new Iterator<ModuleHolder>() {
+ @Override
+ public boolean hasNext() {
+ return entrySetIterator.hasNext();
+ }
+
+ @Override
+ public ModuleHolder next() {
+ Map.Entry<String, ReactModuleInfo> entry = entrySetIterator.next();
+ String name = entry.getKey();
+ ReactModuleInfo reactModuleInfo = entry.getValue();
+ return new ModuleHolder(reactModuleInfo, new ModuleHolderProvider(name, reactContext));
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("Cannot remove native modules from the list");
+ }
+ };
+ }
+ };
+ }
+
+ /**
+ * @param reactContext react application context that can be used to create View Managers.
+ * @return list of module specs that can create the View Managers.
+ */
+ protected List<ModuleSpec> getViewManagers(ReactApplicationContext reactContext) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
+ List<ModuleSpec> viewManagerModuleSpecs = getViewManagers(reactContext);
+ if (viewManagerModuleSpecs == null || viewManagerModuleSpecs.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ List<ViewManager> viewManagers = new ArrayList<>();
+ for (ModuleSpec moduleSpec : viewManagerModuleSpecs) {
+ viewManagers.add((ViewManager) moduleSpec.getProvider().get());
+ }
+ return viewManagers;
+ }
+
+ public abstract ReactModuleInfoProvider getReactModuleInfoProvider();
+
+ private class ModuleHolderProvider implements Provider<NativeModule> {
+
+ private final String mName;
+ private final ReactApplicationContext mReactContext;
+
+ public ModuleHolderProvider(String name, ReactApplicationContext reactContext) {
+ mName = name;
+ mReactContext = reactContext;
+ }
+
+ @Override
+ public NativeModule get() {
+ return getModule(mName, mReactContext);
+ }
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/uimanager/AccessibilityDelegateUtil.java

@@ -9,6 +9,9 @@
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 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 @@
info.setContentDescription(accessibilityHint);
}
}
+
+ setRole(info, accessibilityRole, view.getContext());
}
});
}
@@ -127,6 +131,18 @@
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 @@
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);

ReactAndroid/src/main/java/com/facebook/react/uimanager/AccessibilityHelper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/AndroidManifest.xml

@@ -1,6 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.facebook" >
-
- <uses-sdk android:minSdkVersion="15"/>
-
-</manifest>

ReactAndroid/src/main/java/com/facebook/react/uimanager/annotations/ReactPropertyHolder.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/annotations/ReactPropGroup.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/annotations/ReactProp.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -7,6 +7,7 @@
import android.graphics.Color;
import android.os.Build;
+import android.support.v4.view.ViewCompat;
import android.view.View;
import android.view.ViewParent;
import com.facebook.react.R;
@@ -14,7 +15,9 @@
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}.
@@ -44,7 +47,7 @@
private static final String PROP_TRANSLATE_Y = "translateY";
private static final int PERSPECTIVE_ARRAY_INVERTED_CAMERA_DISTANCE_INDEX = 2;
- private static final float CAMERA_DISTANCE_NORMALIZATION_MULTIPLIER = 5;
+ private static final float CAMERA_DISTANCE_NORMALIZATION_MULTIPLIER = (float)Math.sqrt(5);
/**
* Used to locate views in end-to-end (UI) tests.
@@ -57,12 +60,12 @@
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 {
@@ -71,20 +74,17 @@
}
@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();
@@ -94,12 +94,12 @@
}
@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
@@ -107,28 +107,28 @@
}
@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;
}
@@ -137,7 +137,7 @@
}
@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) {
@@ -154,62 +154,60 @@
}
@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")) {
- view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+ ViewCompat.setImportantForAccessibility(view, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
} else if (importantForAccessibility.equals("yes")) {
- view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+ ViewCompat.setImportantForAccessibility(view, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
} else if (importantForAccessibility.equals("no")) {
- view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+ ViewCompat.setImportantForAccessibility(view, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO);
} else if (importantForAccessibility.equals("no-hide-descendants")) {
- view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+ ViewCompat.setImportantForAccessibility(view, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
}
}
@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 >= 19) {
+ 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(
@@ -234,14 +232,18 @@
float scale = DisplayMetricsHolder.getScreenDisplayMetrics().density;
// The following converts the matrix's perspective to a camera distance
- // such that the camera perspective looks the same on Android and iOS
- float normalizedCameraDistance = scale * cameraDistance * CAMERA_DISTANCE_NORMALIZATION_MULTIPLIER;
+ // such that the camera perspective looks the same on Android and iOS.
+ // The native Android implementation removed the screen density from the
+ // calculation, so squaring and a normalization value of
+ // sqrt(5) produces an exact replica with iOS.
+ // For more information, see https://github.com/facebook/react-native/pull/18302
+ float normalizedCameraDistance = scale * scale * cameraDistance * CAMERA_DISTANCE_NORMALIZATION_MULTIPLIER;
view.setCameraDistance(normalizedCameraDistance);
}
}
- 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);
@@ -252,12 +254,12 @@
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);
}

ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK

@@ -13,7 +13,6 @@
),
provided_deps = [
react_native_dep("third-party/android/support/v4:lib-support-v4"),
- react_native_dep("third-party/android/support-annotations:android-support-annotations"),
],
required_for_source_only_abi = True,
visibility = [
@@ -30,7 +29,7 @@
react_native_target("java/com/facebook/react/animation:animation"),
react_native_target("java/com/facebook/react/bridge:bridge"),
react_native_target("java/com/facebook/react/common:common"),
- react_native_target("java/com/facebook/react/common:common"),
+ react_native_target("java/com/facebook/react/config:config"),
react_native_target("java/com/facebook/react/module/annotations:annotations"),
react_native_target("java/com/facebook/react/modules/core:core"),
react_native_target("java/com/facebook/react/modules/i18nmanager:i18nmanager"),
@@ -49,9 +48,9 @@
rn_android_library(
name = "DisplayMetrics",
- srcs = glob([
+ srcs = [
"DisplayMetricsHolder.java",
- ]),
+ ],
required_for_source_only_abi = True,
visibility = [
"PUBLIC",

ReactAndroid/src/main/java/com/facebook/react/uimanager/common/BUCK

@@ -1,11 +1,10 @@
-load("//tools/build_defs/oss:rn_defs.bzl", "react_native_dep", "react_native_target", "rn_android_library")
+load("//tools/build_defs/oss:rn_defs.bzl", "react_native_dep", "rn_android_library")
rn_android_library(
name = "common",
srcs = glob(["*.java"]),
provided_deps = [
react_native_dep("third-party/android/support/v4:lib-support-v4"),
- react_native_dep("third-party/android/support-annotations:android-support-annotations"),
],
visibility = [
"PUBLIC",

ReactAndroid/src/main/java/com/facebook/react/uimanager/common/MeasureSpecProvider.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/common/SizeMonitoringFrameLayout.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/common/UIManagerType.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/common/ViewUtil.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.
@@ -25,4 +25,13 @@
return DEFAULT;
}
+ /**
+ * @param reactTag {@link int} react tag
+ * @return if the react tag received by parameter is a RootTag or not.
+ */
+ @Deprecated
+ public static boolean isRootTag(int reactTag) {
+ return reactTag % 10 == 1;
+ }
+
}

ReactAndroid/src/main/java/com/facebook/react/uimanager/debug/NotThreadSafeViewHierarchyUpdateDebugListener.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/DisplayMetricsHolder.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -68,7 +68,7 @@
// The real metrics include system decor elements (e.g. soft menu bar).
//
// See: http://developer.android.com/reference/android/view/Display.html#getRealMetrics(android.util.DisplayMetrics)
- if (Build.VERSION.SDK_INT >= 17) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
display.getRealMetrics(screenDisplayMetrics);
} else {
// For 14 <= API level <= 16, we need to invoke getRawHeight and getRawWidth to get the real dimensions.

ReactAndroid/src/main/java/com/facebook/react/uimanager/events/BatchEventDispatchedListener.java

@@ -0,0 +1,16 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+package com.facebook.react.uimanager.events;
+
+public interface BatchEventDispatchedListener {
+
+ /**
+ * Called after a batch of low priority events has been dispatched.
+ */
+ void onBatchEventDispatched();
+
+}

ReactAndroid/src/main/java/com/facebook/react/uimanager/events/ContentSizeChangeEvent.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/events/EventDispatcher.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -20,9 +20,9 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
-import javax.annotation.Nullable;
/**
* Class responsible for dispatching UI events to JS. The main purpose of this class is to act as an
@@ -90,6 +90,7 @@
private final DispatchEventsRunnable mDispatchEventsRunnable = new DispatchEventsRunnable();
private final ArrayList<Event> mEventStaging = new ArrayList<>();
private final ArrayList<EventDispatcherListener> mListeners = new ArrayList<>();
+ private final List<BatchEventDispatchedListener> mPostEventDispatchListeners = new ArrayList<>();
private final ScheduleDispatchFrameCallback mCurrentFrameCallback =
new ScheduleDispatchFrameCallback();
private final AtomicInteger mHasDispatchScheduledCount = new AtomicInteger();
@@ -123,6 +124,14 @@
event.getEventName(),
event.getUniqueID());
}
+ maybePostFrameCallbackFromNonUI();
+ }
+
+ public void dispatchAllEvents() {
+ maybePostFrameCallbackFromNonUI();
+ }
+
+ private void maybePostFrameCallbackFromNonUI() {
if (mReactEventEmitter != null) {
// If the host activity is paused, the frame callback may not be currently
// posted. Ensure that it is so that this event gets delivered promptly.
@@ -135,10 +144,6 @@
}
}
- public void dispatchAllEvents() {
- mCurrentFrameCallback.maybePostFromNonUI();
- }
-
/**
* Add a listener to this EventDispatcher.
*/
@@ -153,6 +158,14 @@
mListeners.remove(listener);
}
+ public void addBatchEventDispatchedListener(BatchEventDispatchedListener listener) {
+ mPostEventDispatchListeners.add(listener);
+ }
+
+ public void removeBatchEventDispatchedListener(BatchEventDispatchedListener listener) {
+ mPostEventDispatchListeners.remove(listener);
+ }
+
@Override
public void onHostResume() {
mCurrentFrameCallback.maybePostFromNonUI();
@@ -362,6 +375,9 @@
mEventCookieToLastEventIdx.clear();
}
}
+ for (BatchEventDispatchedListener listener : mPostEventDispatchListeners) {
+ listener.onBatchEventDispatched();
+ }
} finally {
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
}

ReactAndroid/src/main/java/com/facebook/react/uimanager/events/EventDispatcherListener.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/events/Event.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/events/NativeGestureUtil.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/events/RCTEventEmitter.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/events/ReactEventEmitter.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.
@@ -9,7 +9,6 @@
import static com.facebook.react.uimanager.events.TouchesHelper.TARGET_KEY;
-import android.util.Log;
import android.util.SparseArray;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.ReactApplicationContext;
@@ -17,8 +16,6 @@
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.common.UIManagerType;
import com.facebook.react.uimanager.common.ViewUtil;
-import java.io.Closeable;
-import java.io.IOException;
import javax.annotation.Nullable;
public class ReactEventEmitter implements RCTEventEmitter {

ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchesHelper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchEventCoalescingKeyHelper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchEventType.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/FloatUtil.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/GuardedFrameCallback.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/IllegalViewOperationException.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/JSTouchDispatcher.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AbstractLayoutAnimation.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AnimatedPropertyType.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/BaseLayoutAnimation.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/InterpolatorType.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationController.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationListener.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationType.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutCreateAnimation.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutDeleteAnimation.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutHandlingAnimation.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutUpdateAnimation.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/OpacityAnimation.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/PositionAndSizeAnimation.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/SimpleSpringInterpolator.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -75,16 +75,6 @@
mTempYogaValue = new MutableYogaValue();
}
- protected LayoutShadowNode(LayoutShadowNode node) {
- super(node);
- mTempYogaValue = new MutableYogaValue(node.mTempYogaValue);
- }
-
- @Override
- protected LayoutShadowNode copy() {
- return new LayoutShadowNode(this);
- }
-
@ReactProp(name = ViewProps.WIDTH)
public void setWidth(Dynamic width) {
if (isVirtual()) {

ReactAndroid/src/main/java/com/facebook/react/uimanager/MatrixMathHelper.java

@@ -1,3 +1,10 @@
+/**
+ * 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.uimanager;
import com.facebook.infer.annotation.Assertions;

ReactAndroid/src/main/java/com/facebook/react/uimanager/MeasureSpecAssertions.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,9 +7,7 @@
package com.facebook.react.uimanager;
-import android.annotation.TargetApi;
import android.content.res.Resources;
-import android.os.Build;
import com.facebook.common.logging.FLog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -198,7 +196,7 @@
parentViewGroupManager = (ViewGroupManager) parentViewManager;
} else {
throw new IllegalViewOperationException(
- "Trying to use view with tag " + tag +
+ "Trying to use view with tag " + parentTag +
" as a parent, but its Manager doesn't extends ViewGroupManager");
}
if (parentViewGroupManager != null
@@ -213,14 +211,12 @@
}
}
- @TargetApi(Build.VERSION_CODES.DONUT)
private void updateInstanceHandle(View viewToUpdate, long instanceHandle) {
UiThreadUtil.assertOnUiThread();
viewToUpdate.setTag(R.id.view_tag_instance_handle, instanceHandle);
}
@Nullable
- @TargetApi(Build.VERSION_CODES.DONUT)
public long getInstanceHandle(int reactTag) {
View view = mTagsToViews.get(reactTag);
if (view == null) {
@@ -382,6 +378,11 @@
tagsToDelete));
}
if (indexToRemove >= viewManager.getChildCount(viewToManage)) {
+ if (mRootTags.get(tag) && viewManager.getChildCount(viewToManage) == 0) {
+ // This root node has already been removed (likely due to a threading issue caused by
+ // async js execution). Ignore this root removal.
+ return;
+ }
throw new IllegalViewOperationException(
"Trying to remove a view index above child " +
"count " + indexToRemove + " view tag: " + tag + "\n detail: " +
@@ -409,12 +410,11 @@
if (mLayoutAnimationEnabled &&
mLayoutAnimator.shouldAnimateLayout(viewToRemove) &&
arrayContains(tagsToDelete, viewToRemove.getId())) {
- // Display the view in the parent after removal for the duration of the layout animation,
- // but pretend that it doesn't exist when calling other ViewGroup methods.
- viewManager.startViewTransition(viewToManage, viewToRemove);
- }
-
+ // The view will be removed and dropped by the 'delete' layout animation
+ // instead, so do nothing
+ } else {
viewManager.removeViewAt(viewToManage, indexToRemove);
+ }
lastIndexToRemove = indexToRemove;
}
@@ -460,9 +460,7 @@
mLayoutAnimator.deleteView(viewToDestroy, new LayoutAnimationListener() {
@Override
public void onAnimationEnd() {
- // Already removed from the ViewGroup, we can just end the transition here to
- // release the child.
- viewManager.endViewTransition(viewToManage, viewToDestroy);
+ viewManager.removeView(viewToManage, viewToDestroy);
dropView(viewToDestroy);
}
});
@@ -546,10 +544,12 @@
ViewGroup view,
ThemedReactContext themedContext) {
if (view.getId() != View.NO_ID) {
- throw new IllegalViewOperationException(
- "Trying to add a root view with an explicit id already set. React Native uses " +
- "the id field to track react tags and will overwrite this field. If that is fine, " +
- "explicitly overwrite the id field to View.NO_ID before calling addRootView.");
+ FLog.e(
+ TAG,
+ "Trying to add a root view with an explicit id (" + view.getId() + ") already " +
+ "set. React Native uses the id field to track react tags and will overwrite this field. " +
+ "If that is fine, explicitly overwrite the id field to View.NO_ID before calling " +
+ "addRootView.");
}
mTagsToViews.put(tag, view);

ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/NoSuchNativeViewException.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/OnLayoutEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/PixelUtil.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,6 +7,7 @@
package com.facebook.react.uimanager;
+import android.util.DisplayMetrics;
import android.util.TypedValue;
/**
@@ -32,13 +33,31 @@
}
/**
+ * Convert from PX to SP
+ */
+ public static float toSPFromPixel(float value) {
+ return value / DisplayMetricsHolder.getScreenDisplayMetrics().scaledDensity;
+ }
+
+ /**
* Convert from SP to PX
*/
public static float toPixelFromSP(float value) {
- return TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_SP,
- value,
- DisplayMetricsHolder.getWindowDisplayMetrics());
+ return toPixelFromSP(value, Float.NaN);
+ }
+
+ /**
+ * Convert from SP to PX
+ */
+ public static float toPixelFromSP(float value, float maxFontScale) {
+ DisplayMetrics displayMetrics = DisplayMetricsHolder.getWindowDisplayMetrics();
+ float scaledDensity = displayMetrics.scaledDensity;
+ float currentFontScale = scaledDensity / displayMetrics.density;
+ if (maxFontScale >= 1 && maxFontScale < currentFontScale) {
+ scaledDensity = displayMetrics.density * maxFontScale;
+ }
+
+ return value * scaledDensity;
}
/**
@@ -55,4 +74,11 @@
return value / DisplayMetricsHolder.getWindowDisplayMetrics().density;
}
+ /**
+ * @return {@link float} that represents the density of the display metrics for device screen.
+ */
+ public static float getDisplayMetricDensity() {
+ return DisplayMetricsHolder.getScreenDisplayMetrics().density;
+ }
+
}

ReactAndroid/src/main/java/com/facebook/react/uimanager/PointerEvents.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactClippingViewGroupHelper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactClippingViewGroup.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactCompoundViewGroup.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactCompoundView.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactInvalidPropertyException.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactPointerEventsView.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactRootViewTagGenerator.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java

@@ -1,21 +1,13 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.uimanager;
-import static java.lang.System.arraycopy;
-
-import com.facebook.common.logging.FLog;
-import com.facebook.debug.holder.PrinterHolder;
-import com.facebook.debug.tags.ReactDebugOverlayTags;
import com.facebook.infer.annotation.Assertions;
-import com.facebook.react.common.build.ReactBuildConfig;
import com.facebook.react.uimanager.annotations.ReactPropertyHolder;
-import com.facebook.systrace.Systrace;
-import com.facebook.systrace.SystraceMessage;
import com.facebook.yoga.YogaAlign;
import com.facebook.yoga.YogaBaselineFunction;
import com.facebook.yoga.YogaConfig;
@@ -27,15 +19,12 @@
import com.facebook.yoga.YogaJustify;
import com.facebook.yoga.YogaMeasureFunction;
import com.facebook.yoga.YogaNode;
-import com.facebook.yoga.YogaNodeCloneFunction;
import com.facebook.yoga.YogaOverflow;
import com.facebook.yoga.YogaPositionType;
import com.facebook.yoga.YogaValue;
import com.facebook.yoga.YogaWrap;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
import javax.annotation.Nullable;
/**
@@ -64,41 +53,10 @@
@ReactPropertyHolder
public class ReactShadowNodeImpl implements ReactShadowNode<ReactShadowNodeImpl> {
- private static final boolean DEBUG = ReactBuildConfig.DEBUG || PrinterHolder.getPrinter().shouldDisplayLogMessage(ReactDebugOverlayTags.FABRIC_UI_MANAGER);
- private static final String TAG = ReactShadowNodeImpl.class.getSimpleName();
private static final YogaConfig sYogaConfig;
+
static {
sYogaConfig = ReactYogaConfigProvider.get();
- sYogaConfig.setOnCloneNode(new YogaNodeCloneFunction() {
- @Override
- public YogaNode cloneNode(YogaNode oldYogaNode,
- YogaNode parent,
- int childIndex) {
- SystraceMessage.beginSection(
- Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
- "FabricReconciler.YogaNodeCloneFunction")
- .flush();
- try {
- ReactShadowNodeImpl parentReactShadowNode = (ReactShadowNodeImpl) parent.getData();
- Assertions.assertNotNull(parentReactShadowNode);
- ReactShadowNodeImpl oldReactShadowNode = (ReactShadowNodeImpl) oldYogaNode.getData();
- Assertions.assertNotNull(oldReactShadowNode);
-
- if (DEBUG) {
- FLog.d(
- TAG,
- "YogaNode started cloning: oldYogaNode: " + oldReactShadowNode + " - parent: "
- + parentReactShadowNode + " index: " + childIndex);
- }
-
- ReactShadowNodeImpl newNode = oldReactShadowNode.mutableCopy(oldReactShadowNode.getInstanceHandle());
- parentReactShadowNode.replaceChild(newNode, childIndex);
- return newNode.mYogaNode;
- } finally{
- Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
- }
- }
- });
}
private int mReactTag;
@@ -123,12 +81,6 @@
private final float[] mPadding = new float[Spacing.ALL + 1];
private final boolean[] mPaddingIsPercent = new boolean[Spacing.ALL + 1];
private YogaNode mYogaNode;
- private int mGenerationDebugInformation = 1;
- private ReactShadowNode mOriginalReactShadowNode = null;
-
- private @Nullable ReactStylesDiffMap mNewProps;
- private long mInstanceHandle;
- private boolean mIsSealed = false;
public ReactShadowNodeImpl() {
mDefaultPadding = new Spacing(0);
@@ -142,120 +94,6 @@
}
}
- protected ReactShadowNodeImpl(ReactShadowNodeImpl original) {
- mReactTag = original.mReactTag;
- mRootTag = original.mRootTag;
- mViewClassName = original.mViewClassName;
- mThemedContext = original.mThemedContext;
- mShouldNotifyOnLayout = original.mShouldNotifyOnLayout;
- mIsLayoutOnly = original.mIsLayoutOnly;
- mNativeParent = original.mNativeParent;
- mDefaultPadding = new Spacing(original.mDefaultPadding);
- // Cloned nodes should be always updated.
- mNodeUpdated = true;
- // "cached" screen coordinates are not cloned because FabricJS not always clone the last
- // ReactShadowNode that was rendered in the screen.
- mScreenX = 0;
- mScreenY = 0;
- mScreenWidth = 0;
- mScreenHeight = 0;
- mGenerationDebugInformation = original.mGenerationDebugInformation + 1;
- arraycopy(original.mPadding, 0, mPadding, 0, original.mPadding.length);
- arraycopy(original.mPaddingIsPercent, 0, mPaddingIsPercent, 0, original.mPaddingIsPercent.length);
- mNewProps = null;
- mParent = null;
- mOriginalReactShadowNode = original;
- mIsSealed = false;
- }
-
- private void replaceChild(ReactShadowNodeImpl newNode, int childIndex) {
- mChildren.remove(childIndex);
- mChildren.add(childIndex, newNode);
- newNode.mParent = this;
- }
-
- /**
- * @return a copy of this object (no including copy of its children or the underlying yogaNode).
- */
- protected ReactShadowNodeImpl copy() {
- return new ReactShadowNodeImpl(this);
- }
-
- @Override
- public ReactShadowNodeImpl mutableCopy(long instanceHandle) {
- ReactShadowNodeImpl copy = copy();
- Assertions.assertCondition(
- getClass() == copy.getClass(),
- "Copied shadow node must use the same class");
- copy.mInstanceHandle = instanceHandle;
- if (mYogaNode != null) {
- copy.mYogaNode = mYogaNode.clone();
- copy.mYogaNode.setData(copy);
- } else {
- // Virtual ReactShadowNode do not have a YogaNode associated
- copy.mYogaNode = null;
- }
- copy.mTotalNativeChildren = mTotalNativeChildren;
- copy.mNativeChildren = copyChildren(mNativeChildren);
- copy.mChildren = copyChildren(mChildren);
-
- return copy;
- }
-
- @Nullable
- private ArrayList<ReactShadowNodeImpl> copyChildren(@Nullable List<ReactShadowNodeImpl> list){
- ArrayList<ReactShadowNodeImpl> result = list == null ? null : new ArrayList<>(list);
- if (result != null) {
- for (ReactShadowNodeImpl child : result) {
- child.mParent = null;
- }
- }
- return result;
- }
-
- @Override
- public ReactShadowNodeImpl mutableCopyWithNewChildren(long instanceHandle) {
- ReactShadowNodeImpl copy = copy();
- copy.mInstanceHandle = instanceHandle;
- Assertions.assertCondition(
- getClass() == copy.getClass(),
- "Copied shadow node must use the same class");
- if (mYogaNode != null) {
- copy.mYogaNode = mYogaNode.cloneWithNewChildren();
- copy.mYogaNode.setData(copy);
- } else {
- // Virtual ReactShadowNode do not have a YogaNode associated
- copy.mYogaNode = null;
- }
- copy.mNativeChildren = null;
- copy.mChildren = null;
- copy.mTotalNativeChildren = 0;
- return copy;
- }
-
- @Override
- public ReactShadowNodeImpl mutableCopyWithNewProps(long instanceHandle,
- @Nullable ReactStylesDiffMap newProps) {
- ReactShadowNodeImpl copy = mutableCopy(instanceHandle);
- if (newProps != null) {
- copy.updateProperties(newProps);
- copy.mNewProps = newProps;
- }
- return copy;
- }
-
- @Override
- public ReactShadowNodeImpl mutableCopyWithNewChildrenAndProps(long instanceHandle,
- @Nullable ReactStylesDiffMap newProps) {
- ReactShadowNodeImpl copy = mutableCopyWithNewChildren(instanceHandle);
- if (newProps != null) {
- copy.updateProperties(newProps);
- copy.mNewProps = newProps;
- }
- return copy;
- }
-
-
/**
* Nodes that return {@code true} will be treated as "virtual" nodes. That is, nodes that are not
* mapped into native views (e.g. nested text node). By default this method returns {@code false}.
@@ -299,7 +137,6 @@
@Override
public final void markUpdateSeen() {
- assertNotSealed();
mNodeUpdated = false;
if (hasNewLayout()) {
markLayoutSeen();
@@ -325,7 +162,6 @@
@Override
public void dirty() {
- assertNotSealed();
if (!isVirtual()) {
mYogaNode.dirty();
}
@@ -338,7 +174,6 @@
@Override
public void addChildAt(ReactShadowNodeImpl child, int i) {
- assertNotSealed();
if (mChildren == null) {
mChildren = new ArrayList<>(4);
}
@@ -370,7 +205,6 @@
@Override
public ReactShadowNodeImpl removeChildAt(int i) {
- assertNotSealed();
if (mChildren == null) {
throw new ArrayIndexOutOfBoundsException(
"Index " + i + " out of bounds: node has no children");
@@ -464,12 +298,6 @@
// no-op
}
- @Override
- @Nullable
- public ReactStylesDiffMap getNewProps() {
- return mNewProps;
- }
-
/**
* Called after layout step at the end of the UI batch from {@link UIManagerModule}. May be used
* to enqueue additional ui operations for the native view. Will only be called on nodes marked as
@@ -543,7 +371,6 @@
@Override
public void setReactTag(int reactTag) {
- assertNotSealed();
mReactTag = reactTag;
}
@@ -555,13 +382,11 @@
@Override
public final void setRootTag(int rootTag) {
- assertNotSealed();
mRootTag = rootTag;
}
@Override
public final void setViewClassName(String viewClassName) {
- assertNotSealed();
mViewClassName = viewClassName;
}
@@ -603,7 +428,6 @@
@Override
public final void markLayoutSeen() {
- assertNotSealed();
if (mYogaNode != null) {
mYogaNode.markLayoutSeen();
}
@@ -615,7 +439,6 @@
*/
@Override
public final void addNativeChildAt(ReactShadowNodeImpl child, int nativeIndex) {
- assertNotSealed();
Assertions.assertCondition(!mIsLayoutOnly);
Assertions.assertCondition(!child.mIsLayoutOnly);
@@ -667,7 +490,6 @@
*/
@Override
public final void setIsLayoutOnly(boolean isLayoutOnly) {
- assertNotSealed();
Assertions.assertCondition(getParent() == null, "Must remove from no opt parent first");
Assertions.assertCondition(mNativeParent == null, "Must remove from native parent first");
Assertions.assertCondition(getNativeChildCount() == 0, "Must remove all native children first");
@@ -816,7 +638,6 @@
@Override
public void setLayoutDirection(YogaDirection direction) {
- assertNotSealed();
mYogaNode.setDirection(direction);
}
@@ -827,43 +648,36 @@
@Override
public void setStyleWidth(float widthPx) {
- assertNotSealed();
mYogaNode.setWidth(widthPx);
}
@Override
public void setStyleWidthPercent(float percent) {
- assertNotSealed();
mYogaNode.setWidthPercent(percent);
}
@Override
public void setStyleWidthAuto() {
- assertNotSealed();
mYogaNode.setWidthAuto();
}
@Override
public void setStyleMinWidth(float widthPx) {
- assertNotSealed();
mYogaNode.setMinWidth(widthPx);
}
@Override
public void setStyleMinWidthPercent(float percent) {
- assertNotSealed();
mYogaNode.setMinWidthPercent(percent);
}
@Override
public void setStyleMaxWidth(float widthPx) {
- assertNotSealed();
mYogaNode.setMaxWidth(widthPx);
}
@Override
public void setStyleMaxWidthPercent(float percent) {
- assertNotSealed();
mYogaNode.setMaxWidthPercent(percent);
}
@@ -874,151 +688,126 @@
@Override
public void setStyleHeight(float heightPx) {
- assertNotSealed();
mYogaNode.setHeight(heightPx);
}
@Override
public void setStyleHeightPercent(float percent) {
- assertNotSealed();
mYogaNode.setHeightPercent(percent);
}
@Override
public void setStyleHeightAuto() {
- assertNotSealed();
mYogaNode.setHeightAuto();
}
@Override
public void setStyleMinHeight(float widthPx) {
- assertNotSealed();
mYogaNode.setMinHeight(widthPx);
}
@Override
public void setStyleMinHeightPercent(float percent) {
- assertNotSealed();
mYogaNode.setMinHeightPercent(percent);
}
@Override
public void setStyleMaxHeight(float widthPx) {
- assertNotSealed();
mYogaNode.setMaxHeight(widthPx);
}
@Override
public void setStyleMaxHeightPercent(float percent) {
- assertNotSealed();
mYogaNode.setMaxHeightPercent(percent);
}
@Override
public void setFlex(float flex) {
- assertNotSealed();
mYogaNode.setFlex(flex);
}
@Override
public void setFlexGrow(float flexGrow) {
- assertNotSealed();
mYogaNode.setFlexGrow(flexGrow);
}
@Override
public void setFlexShrink(float flexShrink) {
- assertNotSealed();
mYogaNode.setFlexShrink(flexShrink);
}
@Override
public void setFlexBasis(float flexBasis) {
- assertNotSealed();
mYogaNode.setFlexBasis(flexBasis);
}
@Override
public void setFlexBasisAuto() {
- assertNotSealed();
mYogaNode.setFlexBasisAuto();
}
@Override
public void setFlexBasisPercent(float percent) {
- assertNotSealed();
mYogaNode.setFlexBasisPercent(percent);
}
@Override
public void setStyleAspectRatio(float aspectRatio) {
- assertNotSealed();
mYogaNode.setAspectRatio(aspectRatio);
}
@Override
public void setFlexDirection(YogaFlexDirection flexDirection) {
- assertNotSealed();
mYogaNode.setFlexDirection(flexDirection);
}
@Override
public void setFlexWrap(YogaWrap wrap) {
- assertNotSealed();
mYogaNode.setWrap(wrap);
}
@Override
public void setAlignSelf(YogaAlign alignSelf) {
- assertNotSealed();
mYogaNode.setAlignSelf(alignSelf);
}
@Override
public void setAlignItems(YogaAlign alignItems) {
- assertNotSealed();
mYogaNode.setAlignItems(alignItems);
}
@Override
public void setAlignContent(YogaAlign alignContent) {
- assertNotSealed();
mYogaNode.setAlignContent(alignContent);
}
@Override
public void setJustifyContent(YogaJustify justifyContent) {
- assertNotSealed();
mYogaNode.setJustifyContent(justifyContent);
}
@Override
public void setOverflow(YogaOverflow overflow) {
- assertNotSealed();
mYogaNode.setOverflow(overflow);
}
@Override
public void setDisplay(YogaDisplay display) {
- assertNotSealed();
mYogaNode.setDisplay(display);
}
@Override
public void setMargin(int spacingType, float margin) {
- assertNotSealed();
mYogaNode.setMargin(YogaEdge.fromInt(spacingType), margin);
}
@Override
public void setMarginPercent(int spacingType, float percent) {
- assertNotSealed();
mYogaNode.setMarginPercent(YogaEdge.fromInt(spacingType), percent);
}
@Override
public void setMarginAuto(int spacingType) {
- assertNotSealed();
mYogaNode.setMarginAuto(YogaEdge.fromInt(spacingType));
}
@@ -1034,14 +823,12 @@
@Override
public void setDefaultPadding(int spacingType, float padding) {
- assertNotSealed();
mDefaultPadding.set(spacingType, padding);
updatePadding();
}
@Override
public void setPadding(int spacingType, float padding) {
- assertNotSealed();
mPadding[spacingType] = padding;
mPaddingIsPercent[spacingType] = false;
updatePadding();
@@ -1049,14 +836,12 @@
@Override
public void setPaddingPercent(int spacingType, float percent) {
- assertNotSealed();
mPadding[spacingType] = percent;
mPaddingIsPercent[spacingType] = !YogaConstants.isUndefined(percent);
updatePadding();
}
private void updatePadding() {
- assertNotSealed();
for (int spacingType = Spacing.LEFT; spacingType <= Spacing.ALL; spacingType++) {
if (spacingType == Spacing.LEFT
|| spacingType == Spacing.RIGHT
@@ -1092,43 +877,36 @@
@Override
public void setBorder(int spacingType, float borderWidth) {
- assertNotSealed();
mYogaNode.setBorder(YogaEdge.fromInt(spacingType), borderWidth);
}
@Override
public void setPosition(int spacingType, float position) {
- assertNotSealed();
mYogaNode.setPosition(YogaEdge.fromInt(spacingType), position);
}
@Override
public void setPositionPercent(int spacingType, float percent) {
- assertNotSealed();
mYogaNode.setPositionPercent(YogaEdge.fromInt(spacingType), percent);
}
@Override
public void setPositionType(YogaPositionType positionType) {
- assertNotSealed();
mYogaNode.setPositionType(positionType);
}
@Override
public void setShouldNotifyOnLayout(boolean shouldNotifyOnLayout) {
- assertNotSealed();
mShouldNotifyOnLayout = shouldNotifyOnLayout;
}
@Override
public void setBaselineFunction(YogaBaselineFunction baselineFunction) {
- assertNotSealed();
mYogaNode.setBaselineFunction(baselineFunction);
}
@Override
public void setMeasureFunction(YogaMeasureFunction measureFunction) {
- assertNotSealed();
mYogaNode.setMeasureFunction(measureFunction);
}
@@ -1151,7 +929,7 @@
}
result.append("<").append(getClass().getSimpleName()).append(" view='").append(getViewClass())
- .append("' tag=").append(getReactTag()).append(" gen=").append(mGenerationDebugInformation);
+ .append("' tag=").append(getReactTag());
if (mYogaNode != null) {
result.append(" layout='x:").append(getScreenX())
.append(" y:").append(getScreenY()).append(" w:").append(getLayoutWidth()).append(" h:")
@@ -1178,54 +956,4 @@
}
}
- @Nullable
- @Override
- public List<ReactShadowNode> getChildrenList() {
- return mChildren == null ? null : Collections.<ReactShadowNode>unmodifiableList(mChildren);
- }
-
- @Override
- public ReactShadowNode getOriginalReactShadowNode() {
- return mOriginalReactShadowNode;
- }
-
- @Override
- public void setOriginalReactShadowNode(ReactShadowNode node) {
- mOriginalReactShadowNode = node;
- }
-
- @Override
- public long getInstanceHandle() {
- return mInstanceHandle;
- }
-
- @Override
- public void setInstanceHandle(long instanceHandle) {
- assertNotSealed();
- mInstanceHandle = instanceHandle;
- }
-
- @Override
- public void markAsSealed() {
- mIsSealed = true;
- }
-
- @Override
- public boolean isSealed() {
- return mIsSealed;
- }
-
- private void assertNotSealed() {
- if (mIsSealed) {
- throw new IllegalStateException("Can not modify sealed node " + toString());
- }
- }
-
- @Override
- public void updateScreenLayout(ReactShadowNode prevNode) {
- mScreenHeight = prevNode.getScreenHeight();
- mScreenWidth = prevNode.getScreenWidth();
- mScreenX = prevNode.getScreenX();
- mScreenY = prevNode.getScreenY();
- }
}

ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -68,17 +68,6 @@
*/
boolean isYogaLeafNode();
- /**
- * @return a mutable copy of the {@link ReactShadowNode}
- */
- T mutableCopy(long instanceHandle);
-
- T mutableCopyWithNewProps(long instanceHandle, @Nullable ReactStylesDiffMap newProps);
-
- T mutableCopyWithNewChildren(long instanceHandle);
-
- T mutableCopyWithNewChildrenAndProps(long instanceHandle, @Nullable ReactStylesDiffMap newProps);
-
String getViewClass();
boolean hasUpdates();
@@ -105,8 +94,6 @@
void removeAndDisposeAllChildren();
- @Nullable ReactStylesDiffMap getNewProps();
-
/**
* This method will be called by {@link UIManagerModule} once per batch, before calculating
* layout. Will be only called for nodes that are marked as updated with {@link #markUpdated()} or
@@ -359,35 +346,4 @@
boolean isMeasureDefined();
void dispose();
-
- /**
- * @return an immutable {@link List<ReactShadowNode>} containing the children of this
- * {@link ReactShadowNode}.
- */
- List<ReactShadowNode> getChildrenList();
-
- /**
- * @return the {@link ReactShadowNode} that was used during the cloning mechanism to create
- * this {@link ReactShadowNode} or null if this object was not created using a clone operation.
- */
- @Nullable ReactShadowNode getOriginalReactShadowNode();
-
- void setOriginalReactShadowNode(@Nullable ReactShadowNode node);
-
- long getInstanceHandle();
-
- void setInstanceHandle(long instanceHandle);
-
- /**
- * Mark this {@link ReactShadowNode} as sealed. This means that the node was already committed
- * and it should not be updated anymore.
- */
- void markAsSealed();
-
- /**
- * @return a {@link boolean} that represents if the {@link ReactShadowNode} is sealed.
- */
- boolean isSealed();
-
- void updateScreenLayout(ReactShadowNode prevNode);
}

ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactStylesDiffMap.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactYogaConfigProvider.java

@@ -1,3 +1,10 @@
+/**
+ * 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.uimanager;
import com.facebook.yoga.YogaConfig;

ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactZIndexedViewGroup.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/RootView.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/RootViewManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/RootViewUtil.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/ShadowNodeRegistry.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,6 +9,7 @@
import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import android.view.View;
import com.facebook.react.common.SingleThreadAsserter;
/**
@@ -36,6 +37,11 @@
public void removeRootNode(int tag) {
mThreadAsserter.assertNow();
+ if (tag == View.NO_ID) {
+ // This root node has already been removed (likely due to a threading issue caused by async js
+ // execution). Ignore this root removal.
+ return;
+ }
if (!mRootTags.get(tag)) {
throw new IllegalViewOperationException(
"View with tag " + tag + " is not registered as a root view");

ReactAndroid/src/main/java/com/facebook/react/uimanager/SimpleViewManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/Spacing.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/ThemedReactContext.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.java

@@ -1,3 +1,10 @@
+/**
+ * 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.uimanager;
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;

ReactAndroid/src/main/java/com/facebook/react/uimanager/UIBlock.java

@@ -1,3 +1,10 @@
+/**
+ * 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.uimanager;
import android.view.View;

ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -87,7 +87,7 @@
minTimeLeftInFrameForNonBatchedOperationMs);
}
- private UIImplementation(
+ UIImplementation(
ReactApplicationContext reactContext,
ViewManagerRegistry viewManagers,
EventDispatcher eventDispatcher,
@@ -709,7 +709,7 @@
}
if (mLayoutUpdateListener != null) {
- mLayoutUpdateListener.onLayoutUpdated(cssRoot);
+ mOperationsQueue.enqueueLayoutUpdateFinished(cssRoot, mLayoutUpdateListener);
}
}
}

ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementationProvider.java

@@ -39,4 +39,16 @@
eventDispatcher,
minTimeLeftInFrameForNonBatchedOperationMs);
}
+
+ UIImplementation createUIImplementation(
+ ReactApplicationContext reactContext,
+ ViewManagerRegistry viewManagerRegistry,
+ EventDispatcher eventDispatcher,
+ int minTimeLeftInFrameForNonBatchedOperationMs) {
+ return new UIImplementation(
+ reactContext,
+ viewManagerRegistry,
+ eventDispatcher,
+ minTimeLeftInFrameForNonBatchedOperationMs);
+ }
}

ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerHelper.java

@@ -1,3 +1,10 @@
+/**
+ * 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.uimanager;
import static com.facebook.react.uimanager.common.UIManagerType.FABRIC;

ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,7 +10,7 @@
import static com.facebook.systrace.Systrace.TRACE_TAG_REACT_JAVA_BRIDGE;
import com.facebook.react.common.MapBuilder;
-import com.facebook.systrace.Systrace;
+import com.facebook.react.config.ReactFeatureFlags;
import com.facebook.systrace.SystraceMessage;
import java.util.List;
import java.util.Map;
@@ -28,14 +28,17 @@
/**
* Generates a lazy discovery enabled version of {@link UIManagerModule} constants. It only
* contains a list of view manager names, so that JS side is aware of the managers there are.
- * Actual ViewManager instantiation happens when {@code UIManager.SpecificViewManager} call happens.
- * The View Manager is then registered on the JS side with the help of
- * {@code UIManagerModule.getConstantsForViewManager}.
+ * Actual ViewManager instantiation happens when
+ * {@code UIManager.getViewManagerConfig('SpecificViewManager')} call happens. The View Manager is then
+ * registered on the JS side with the help of {@code UIManagerModule.getConstantsForViewManager}.
*/
/* package */ static Map<String, Object> createConstants(
UIManagerModule.ViewManagerResolver resolver) {
Map<String, Object> constants = UIManagerModuleConstants.getConstants();
+ if (!ReactFeatureFlags.lazilyLoadViewManagers) {
constants.put("ViewManagerNames", resolver.getViewManagerNames());
+ }
+ constants.put("LazyViewManagersEnabled", true);
return constants;
}
@@ -99,7 +102,7 @@
constants.put(viewManagerName, viewManagerConstants);
}
} finally {
- Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
+ SystraceMessage.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
}
}

ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java

@@ -1,10 +1,9 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
+ * <p>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.uimanager;
import static com.facebook.react.bridge.ReactMarkerConstants.CREATE_UI_MANAGER_MODULE_CONSTANTS_END;
@@ -15,6 +14,7 @@
import android.content.Context;
import android.content.res.Configuration;
import android.media.AudioManager;
+import android.util.ArrayMap;
import com.facebook.common.logging.FLog;
import com.facebook.debug.holder.PrinterHolder;
import com.facebook.debug.tags.ReactDebugOverlayTags;
@@ -34,6 +34,7 @@
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.common.ReactConstants;
+import com.facebook.react.common.annotations.VisibleForTesting;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.uimanager.common.MeasureSpecProvider;
import com.facebook.react.uimanager.common.SizeMonitoringFrameLayout;
@@ -44,52 +45,52 @@
import com.facebook.systrace.Systrace;
import com.facebook.systrace.SystraceMessage;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
/**
- * <p>Native module to allow JS to create and update native Views.</p>
+ * Native module to allow JS to create and update native Views.
*
* <p>
+ *
* <h2>== Transactional Requirement ==</h2>
+ *
* A requirement of this class is to make sure that transactional UI updates occur all at once,
* meaning that no intermediate state is ever rendered to the screen. For example, if a JS
* application update changes the background of View A to blue and the width of View B to 100, both
* need to appear at once. Practically, this means that all UI update code related to a single
* transaction must be executed as a single code block on the UI thread. Executing as multiple code
* blocks could allow the platform UI system to interrupt and render a partial UI state.
- * </p>
*
* <p>To facilitate this, this module enqueues operations that are then applied to native view
* hierarchy through {@link NativeViewHierarchyManager} at the end of each transaction.
*
* <p>
+ *
* <h2>== CSSNodes ==</h2>
- * In order to allow layout and measurement to occur on a non-UI thread, this module also
- * operates on intermediate CSSNodeDEPRECATED objects that correspond to a native view. These CSSNodeDEPRECATED are able
- * to calculate layout according to their styling rules, and then the resulting x/y/width/height of
- * that layout is scheduled as an operation that will be applied to native view hierarchy at the end
- * of current batch.
- * </p>
- *
- * TODO(5241856): Investigate memory usage of creating many small objects in UIManageModule and
- * consider implementing a pool
- * TODO(5483063): Don't dispatch the view hierarchy at the end of a batch if no UI changes occurred
+ *
+ * In order to allow layout and measurement to occur on a non-UI thread, this module also operates
+ * on intermediate CSSNodeDEPRECATED objects that correspond to a native view. These
+ * CSSNodeDEPRECATED are able to calculate layout according to their styling rules, and then the
+ * resulting x/y/width/height of that layout is scheduled as an operation that will be applied to
+ * native view hierarchy at the end of current batch. TODO(5241856): Investigate memory usage of
+ * creating many small objects in UIManageModule and consider implementing a pool TODO(5483063):
+ * Don't dispatch the view hierarchy at the end of a batch if no UI changes occurred
*/
@ReactModule(name = UIManagerModule.NAME)
-public class UIManagerModule extends ReactContextBaseJavaModule implements
- OnBatchCompleteListener, LifecycleEventListener, UIManager {
+public class UIManagerModule extends ReactContextBaseJavaModule
+ implements OnBatchCompleteListener, LifecycleEventListener, UIManager {
- /**
- * Enables lazy discovery of a specific {@link ViewManager} by its name.
- */
+ /** Enables lazy discovery of a specific {@link ViewManager} by its name. */
public interface ViewManagerResolver {
/**
- * {@class UIManagerModule} class uses this method to get a ViewManager by its name.
- * This is the same name that comes from JS by {@code UIManager.ViewManagerName} call.
+ * {@class UIManagerModule} class uses this method to get a ViewManager by its name. This is the
+ * same name that comes from JS by {@code UIManager.ViewManagerName} call.
*/
- @Nullable ViewManager getViewManager(String viewManagerName);
+ @Nullable
+ ViewManager getViewManager(String viewManagerName);
/**
* Provides a list of view manager names to register in JS as {@code UIManager.ViewManagerName}
@@ -97,17 +98,14 @@
List<String> getViewManagerNames();
}
- /**
- * Resolves a name coming from native side to a name of the event that is exposed to JS.
- */
+ /** Resolves a name coming from native side to a name of the event that is exposed to JS. */
public interface CustomEventNamesResolver {
- /**
- * Returns custom event name by the provided event name.
- */
- @Nullable String resolveCustomEventName(String eventName);
+ /** Returns custom event name by the provided event name. */
+ @Nullable
+ String resolveCustomEventName(String eventName);
}
- protected static final String NAME = "UIManager";
+ public static final String NAME = "UIManager";
private static final boolean DEBUG =
PrinterHolder.getPrinter().shouldDisplayLogMessage(ReactDebugOverlayTags.UI_MANAGER);
@@ -115,6 +113,7 @@
private final EventDispatcher mEventDispatcher;
private final Map<String, Object> mModuleConstants;
private final Map<String, Object> mCustomDirectEvents;
+ private final ViewManagerRegistry mViewManagerRegistry;
private final UIImplementation mUIImplementation;
private final MemoryTrimCallback mMemoryTrimCallback = new MemoryTrimCallback();
private final List<UIManagerModuleListener> mListeners = new ArrayList<>();
@@ -158,10 +157,11 @@
mEventDispatcher = new EventDispatcher(reactContext);
mModuleConstants = createConstants(viewManagerResolver);
mCustomDirectEvents = UIManagerModuleConstants.getDirectEventTypeConstants();
+ mViewManagerRegistry = new ViewManagerRegistry(viewManagerResolver);
mUIImplementation =
uiImplementationProvider.createUIImplementation(
reactContext,
- viewManagerResolver,
+ mViewManagerRegistry,
mEventDispatcher,
minTimeLeftInFrameForNonBatchedOperationMs);
@@ -179,10 +179,11 @@
mEventDispatcher = new EventDispatcher(reactContext);
mCustomDirectEvents = MapBuilder.newHashMap();
mModuleConstants = createConstants(viewManagersList, null, mCustomDirectEvents);
+ mViewManagerRegistry = new ViewManagerRegistry(viewManagersList);
mUIImplementation =
uiImplementationProvider.createUIImplementation(
reactContext,
- viewManagersList,
+ mViewManagerRegistry,
mEventDispatcher,
minTimeLeftInFrameForNonBatchedOperationMs);
@@ -211,8 +212,7 @@
public void initialize() {
getReactApplicationContext().registerComponentCallbacks(mMemoryTrimCallback);
mEventDispatcher.registerEventEmitter(
- DEFAULT,
- getReactApplicationContext().getJSModule(RCTEventEmitter.class));
+ DEFAULT, getReactApplicationContext().getJSModule(RCTEventEmitter.class));
}
@Override
@@ -241,9 +241,20 @@
ViewManagerPropertyUpdater.clear();
}
+ /**
+ * This method is intended to reuse the {@link ViewManagerRegistry} with FabricUIManager.
+ * Do not use this method as this will be removed in the near future.
+ */
+ @Deprecated
+ public ViewManagerRegistry getViewManagerRegistry_DO_NOT_USE() {
+ return mViewManagerRegistry;
+ }
+
private static Map<String, Object> createConstants(ViewManagerResolver viewManagerResolver) {
ReactMarker.logMarker(CREATE_UI_MANAGER_MODULE_CONSTANTS_START);
- Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "CreateUIManagerConstants");
+ SystraceMessage.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "CreateUIManagerConstants")
+ .arg("Lazy", true)
+ .flush();
try {
return UIManagerModuleConstantsHelper.createConstants(viewManagerResolver);
} finally {
@@ -257,7 +268,9 @@
@Nullable Map<String, Object> customBubblingEvents,
@Nullable Map<String, Object> customDirectEvents) {
ReactMarker.logMarker(CREATE_UI_MANAGER_MODULE_CONSTANTS_START);
- Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "CreateUIManagerConstants");
+ SystraceMessage.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "CreateUIManagerConstants")
+ .arg("Lazy", false)
+ .flush();
try {
return UIManagerModuleConstantsHelper.createConstants(
viewManagers, customBubblingEvents, customDirectEvents);
@@ -267,8 +280,48 @@
}
}
+ /**
+ * Helper method to pre-compute the constants for a view manager. This method ensures that we
+ * don't block for getting the constants for view managers during TTI
+ *
+ * @param viewManagerNames
+ */
+ @Deprecated
+ public void preComputeConstantsForViewManager(List<String> viewManagerNames) {
+ Map<String, WritableMap> constantsMap = new ArrayMap<>();
+ for (String viewManagerName : viewManagerNames) {
+ WritableMap constants = computeConstantsForViewManager(viewManagerName);
+ if (constants != null) {
+ constantsMap.put(viewManagerName, constants);
+ }
+ }
+
+ // To ensure that this is thread safe, we return an unmodifiableMap
+ // We use mViewManagerConstantsCacheSize to count the times we access the contents of the map
+ // Once we have accessed all the values, we free this cache
+ // Assumption is that JS gets the constants only once for each viewManager.
+ // Using this mechanism prevents expensive synchronized blocks, due to the nature of how this is
+ // accessed - write one, read multiple times, and then throw the data away.
+ mViewManagerConstantsCacheSize = viewManagerNames.size();
+ mViewManagerConstantsCache = Collections.unmodifiableMap(constantsMap);
+ }
+
@ReactMethod(isBlockingSynchronousMethod = true)
public @Nullable WritableMap getConstantsForViewManager(final String viewManagerName) {
+ if (mViewManagerConstantsCache != null
+ && mViewManagerConstantsCache.containsKey(viewManagerName)) {
+ WritableMap constants = mViewManagerConstantsCache.get(viewManagerName);
+ if (--mViewManagerConstantsCacheSize <= 0) {
+ // Looks like we have read all the values from the cache, so we may as well free this cache
+ mViewManagerConstantsCache = null;
+ }
+ return constants;
+ } else {
+ return computeConstantsForViewManager(viewManagerName);
+ }
+ }
+
+ private @Nullable WritableMap computeConstantsForViewManager(final String viewManagerName) {
ViewManager targetView =
viewManagerName != null ? mUIImplementation.resolveViewManager(viewManagerName) : null;
if (targetView == null) {
@@ -323,6 +376,11 @@
return mUIImplementation.getProfiledBatchPerfCounters();
}
+ public <T extends SizeMonitoringFrameLayout & MeasureSpecProvider> int addRootView(
+ final T rootView) {
+ return addRootView(rootView, null, null);
+ }
+
/**
* Registers a new root view. JS can use the returned tag with manageChildren to add/remove
* children to this view.
@@ -334,10 +392,8 @@
*/
@Override
public <T extends SizeMonitoringFrameLayout & MeasureSpecProvider> int addRootView(
- final T rootView) {
- Systrace.beginSection(
- Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
- "UIManagerModule.addRootView");
+ final T rootView, WritableMap initialProps, @Nullable String initialUITemplate) {
+ Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "UIManagerModule.addRootView");
final int tag = ReactRootViewTagGenerator.getNextRootViewTag();
final ReactApplicationContext reactApplicationContext = getReactApplicationContext();
final ThemedReactContext themedRootContext =
@@ -375,13 +431,11 @@
}
/**
- * Sets local data for a shadow node corresponded with given tag.
- * In some cases we need a way to specify some environmental data to shadow node
- * to improve layout (or do something similar), so {@code localData} serves these needs.
- * For example, any stateful embedded native views may benefit from this.
- * Have in mind that this data is not supposed to interfere with the state of
- * the shadow view.
- * Please respect one-directional data flow of React.
+ * Sets local data for a shadow node corresponded with given tag. In some cases we need a way to
+ * specify some environmental data to shadow node to improve layout (or do something similar), so
+ * {@code localData} serves these needs. For example, any stateful embedded native views may
+ * benefit from this. Have in mind that this data is not supposed to interfere with the state of
+ * the shadow view. Please respect one-directional data flow of React.
*/
public void setViewLocalData(final int tag, final Object data) {
final ReactApplicationContext reactApplicationContext = getReactApplicationContext();
@@ -456,12 +510,7 @@
PrinterHolder.getPrinter().logMessage(ReactDebugOverlayTags.UI_MANAGER, message);
}
mUIImplementation.manageChildren(
- viewTag,
- moveFrom,
- moveTo,
- addChildTags,
- addAtIndices,
- removeFrom);
+ viewTag, moveFrom, moveTo, addChildTags, addAtIndices, removeFrom);
}
/**
@@ -472,9 +521,7 @@
* @param childrenTags An array of tags to add to the parent in order
*/
@ReactMethod
- public void setChildren(
- int viewTag,
- ReadableArray childrenTags) {
+ public void setChildren(int viewTag, ReadableArray childrenTags) {
if (DEBUG) {
String message = "(UIManager.setChildren) tag: " + viewTag + ", children: " + childrenTags;
FLog.d(ReactConstants.TAG, message);
@@ -495,8 +542,8 @@
/**
* Method which takes a container tag and then releases all subviews for that container upon
- * receipt.
- * TODO: The method name is incorrect and will be renamed, #6033872
+ * receipt. TODO: The method name is incorrect and will be renamed, #6033872
+ *
* @param containerTag the tag of the container for which the subviews must be removed
*/
@ReactMethod
@@ -526,34 +573,29 @@
/**
* Measures the view specified by tag relative to the given ancestorTag. This means that the
* returned x, y are relative to the origin x, y of the ancestor view. Results are stored in the
- * given outputBuffer. We allow ancestor view and measured view to be the same, in which case
- * the position always will be (0, 0) and method will only measure the view dimensions.
+ * given outputBuffer. We allow ancestor view and measured view to be the same, in which case the
+ * position always will be (0, 0) and method will only measure the view dimensions.
*
- * NB: Unlike {@link #measure}, this will measure relative to the view layout, not the visible
+ * <p>NB: Unlike {@link #measure}, this will measure relative to the view layout, not the visible
* window which can cause unexpected results when measuring relative to things like ScrollViews
* that can have offset content on the screen.
*/
@ReactMethod
public void measureLayout(
- int tag,
- int ancestorTag,
- Callback errorCallback,
- Callback successCallback) {
+ int tag, int ancestorTag, Callback errorCallback, Callback successCallback) {
mUIImplementation.measureLayout(tag, ancestorTag, errorCallback, successCallback);
}
/**
* Like {@link #measure} and {@link #measureLayout} but measures relative to the immediate parent.
*
- * NB: Unlike {@link #measure}, this will measure relative to the view layout, not the visible
+ * <p>NB: Unlike {@link #measure}, this will measure relative to the view layout, not the visible
* window which can cause unexpected results when measuring relative to things like ScrollViews
* that can have offset content on the screen.
*/
@ReactMethod
public void measureLayoutRelativeToParent(
- int tag,
- Callback errorCallback,
- Callback successCallback) {
+ int tag, Callback errorCallback, Callback successCallback) {
mUIImplementation.measureLayoutRelativeToParent(tag, errorCallback, successCallback);
}
@@ -561,7 +603,7 @@
* Find the touch target child native view in the supplied root view hierarchy, given a react
* target location.
*
- * This method is currently used only by Element Inspector DevTool.
+ * <p>This method is currently used only by Element Inspector DevTool.
*
* @param reactTag the tag of the root view to traverse
* @param point an array containing both X and Y target location
@@ -570,9 +612,7 @@
*/
@ReactMethod
public void findSubviewIn(
- final int reactTag,
- final ReadableArray point,
- final Callback callback) {
+ final int reactTag, final ReadableArray point, final Callback callback) {
mUIImplementation.findSubviewIn(
reactTag,
Math.round(PixelUtil.toPixelFromDIP(point.getDouble(0))),
@@ -580,20 +620,14 @@
callback);
}
- /**
- * Check if the first shadow node is the descendant of the second shadow node
- */
+ /** Check if the first shadow node is the descendant of the second shadow node */
@ReactMethod
public void viewIsDescendantOf(
- final int reactTag,
- final int ancestorReactTag,
- final Callback callback) {
+ final int reactTag, final int ancestorReactTag, final Callback callback) {
mUIImplementation.viewIsDescendantOf(reactTag, ancestorReactTag, callback);
}
- /**
- * Registers a new Animation that can then be added to a View using {@link #addAnimation}.
- */
+ /** Registers a new Animation that can then be added to a View using {@link #addAnimation}. */
public void registerAnimation(Animation animation) {
mUIImplementation.registerAnimation(animation);
}
@@ -605,9 +639,7 @@
mUIImplementation.addAnimation(reactTag, animationID, onSuccess);
}
- /**
- * Removes an existing Animation, canceling it if it was in progress.
- */
+ /** Removes an existing Animation, canceling it if it was in progress. */
public void removeAnimation(int reactTag, int animationID) {
mUIImplementation.removeAnimation(reactTag, animationID);
}
@@ -625,8 +657,9 @@
}
@ReactMethod
- public void dispatchViewManagerCommand(int reactTag, int commandId, @Nullable ReadableArray commandArgs) {
- //TODO: this is a temporary approach to support ViewManagerCommands in Fabric until
+ public void dispatchViewManagerCommand(
+ int reactTag, int commandId, @Nullable ReadableArray commandArgs) {
+ // TODO: this is a temporary approach to support ViewManagerCommands in Fabric until
// the dispatchViewManagerCommand() method is supported by Fabric JS API.
UIManagerHelper.getUIManager(getReactApplicationContext(), ViewUtil.getUIManagerType(reactTag))
.dispatchCommand(reactTag, commandId, commandArgs);
@@ -639,7 +672,8 @@
@ReactMethod
public void playTouchSound() {
- AudioManager audioManager = (AudioManager) getReactApplicationContext().getSystemService(Context.AUDIO_SERVICE);
+ AudioManager audioManager =
+ (AudioManager) getReactApplicationContext().getSystemService(Context.AUDIO_SERVICE);
if (audioManager != null) {
audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
}
@@ -669,10 +703,10 @@
* LayoutAnimation API on Android is currently experimental. Therefore, it needs to be enabled
* explicitly in order to avoid regression in existing application written for iOS using this API.
*
- * Warning : This method will be removed in future version of React Native, and layout animation
- * will be enabled by default, so always check for its existence before invoking it.
+ * <p>Warning : This method will be removed in future version of React Native, and layout
+ * animation will be enabled by default, so always check for its existence before invoking it.
*
- * TODO(9139831) : remove this method once layout animation is fully stable.
+ * <p>TODO(9139831) : remove this method once layout animation is fully stable.
*
* @param enabled whether layout animation is enabled or not
*/
@@ -682,11 +716,11 @@
}
/**
- * Configure an animation to be used for the native layout changes, and native views
- * creation. The animation will only apply during the current batch operations.
+ * Configure an animation to be used for the native layout changes, and native views creation. The
+ * animation will only apply during the current batch operations.
*
- * TODO(7728153) : animating view deletion is currently not supported.
- * TODO(7613721) : callbacks are not supported, this feature will likely be killed.
+ * <p>TODO(7728153) : animating view deletion is currently not supported. TODO(7613721) :
+ * callbacks are not supported, this feature will likely be killed.
*
* @param config the configuration of the animation for view addition/removal/update.
* @param success will be called when the animation completes, or when the animation get
@@ -694,25 +728,22 @@
* @param error will be called if there was an error processing the animation
*/
@ReactMethod
- public void configureNextLayoutAnimation(
- ReadableMap config,
- Callback success,
- Callback error) {
+ public void configureNextLayoutAnimation(ReadableMap config, Callback success, Callback error) {
mUIImplementation.configureNextLayoutAnimation(config, success, error);
}
/**
- * To implement the transactional requirement mentioned in the class javadoc, we only commit
- * UI changes to the actual view hierarchy once a batch of JS->Java calls have been completed.
- * We know this is safe because all JS->Java calls that are triggered by a Java->JS call (e.g.
- * the delivery of a touch event or execution of 'renderApplication') end up in a single
- * JS->Java transaction.
- *
- * A better way to do this would be to have JS explicitly signal to this module when a UI
- * transaction is done. Right now, though, this is how iOS does it, and we should probably
- * update the JS and native code and make this change at the same time.
+ * To implement the transactional requirement mentioned in the class javadoc, we only commit UI
+ * changes to the actual view hierarchy once a batch of JS->Java calls have been completed. We
+ * know this is safe because all JS->Java calls that are triggered by a Java->JS call (e.g. the
+ * delivery of a touch event or execution of 'renderApplication') end up in a single JS->Java
+ * transaction.
+ *
+ * <p>A better way to do this would be to have JS explicitly signal to this module when a UI
+ * transaction is done. Right now, though, this is how iOS does it, and we should probably update
+ * the JS and native code and make this change at the same time.
*
- * TODO(5279396): Make JS UI library explicitly notify the native UI module of the end of a UI
+ * <p>TODO(5279396): Make JS UI library explicitly notify the native UI module of the end of a UI
* transaction using a standard native call
*/
@Override
@@ -748,28 +779,23 @@
}
/**
- * Schedule a block to be executed on the UI thread. Useful if you need to execute
- * view logic after all currently queued view updates have completed.
+ * Schedule a block to be executed on the UI thread. Useful if you need to execute view logic
+ * after all currently queued view updates have completed.
*
* @param block that contains UI logic you want to execute.
- *
- * Usage Example:
-
- UIManagerModule uiManager = reactContext.getNativeModule(UIManagerModule.class);
- uiManager.addUIBlock(new UIBlock() {
- public void execute (NativeViewHierarchyManager nvhm) {
- View view = nvhm.resolveView(tag);
- // ...execute your code on View (e.g. snapshot the view)
- }
- });
+ * <p>Usage Example:
+ * <p>UIManagerModule uiManager = reactContext.getNativeModule(UIManagerModule.class);
+ * uiManager.addUIBlock(new UIBlock() { public void execute (NativeViewHierarchyManager nvhm)
+ * { View view = nvhm.resolveView(tag); // ...execute your code on View (e.g. snapshot the
+ * view) } });
*/
public void addUIBlock(UIBlock block) {
mUIImplementation.addUIBlock(block);
}
/**
- * Schedule a block to be executed on the UI thread. Useful if you need to execute
- * view logic before all currently queued view updates have completed.
+ * Schedule a block to be executed on the UI thread. Useful if you need to execute view logic
+ * before all currently queued view updates have completed.
*
* @param block that contains UI logic you want to execute.
*/
@@ -786,16 +812,16 @@
}
/**
- * Given a reactTag from a component, find its root node tag, if possible.
- * Otherwise, this will return 0. If the reactTag belongs to a root node, this
- * will return the same reactTag.
+ * Given a reactTag from a component, find its root node tag, if possible. Otherwise, this will
+ * return 0. If the reactTag belongs to a root node, this will return the same reactTag.
*
* @param reactTag the component tag
- *
* @return the rootTag
*/
public int resolveRootTagFromReactTag(int reactTag) {
- return mUIImplementation.resolveRootTagFromReactTag(reactTag);
+ return ViewUtil.isRootTag(reactTag)
+ ? reactTag
+ : mUIImplementation.resolveRootTagFromReactTag(reactTag);
}
/** Dirties the node associated with the given react tag */
@@ -815,10 +841,18 @@
* Updates the styles of the {@link ReactShadowNode} based on the Measure specs received by
* parameters.
*/
- public void updateRootLayoutSpecs(int rootViewTag, int widthMeasureSpec, int heightMeasureSpec) {
+ public void updateRootLayoutSpecs(
+ final int rootViewTag, final int widthMeasureSpec, final int heightMeasureSpec) {
+ ReactApplicationContext reactApplicationContext = getReactApplicationContext();
+ reactApplicationContext.runOnNativeModulesQueueThread(
+ new GuardedRunnable(reactApplicationContext) {
+ @Override
+ public void runGuarded() {
mUIImplementation.updateRootView(rootViewTag, widthMeasureSpec, heightMeasureSpec);
mUIImplementation.dispatchViewUpdates(-1);
}
+ });
+ }
/** Listener that drops the CSSNode pool on low memory when the app is backgrounded. */
private class MemoryTrimCallback implements ComponentCallbacks2 {
@@ -831,11 +865,9 @@
}
@Override
- public void onConfigurationChanged(Configuration newConfig) {
- }
+ public void onConfigurationChanged(Configuration newConfig) {}
@Override
- public void onLowMemory() {
- }
+ public void onLowMemory() {}
}
}

ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleListener.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -556,6 +556,22 @@
}
}
+ private final class LayoutUpdateFinishedOperation implements UIOperation {
+
+ private final ReactShadowNode mNode;
+ private final UIImplementation.LayoutUpdateListener mListener;
+
+ private LayoutUpdateFinishedOperation(ReactShadowNode node, UIImplementation.LayoutUpdateListener listener) {
+ mNode = node;
+ mListener = listener;
+ }
+
+ @Override
+ public void execute() {
+ mListener.onLayoutUpdated(mNode);
+ }
+ }
+
private class UIBlockOperation implements UIOperation {
private final UIBlock mBlock;
public UIBlockOperation (UIBlock block) {
@@ -610,6 +626,7 @@
private long mProfiledBatchRunStartTime;
private long mProfiledBatchBatchedExecutionTime;
private long mProfiledBatchNonBatchedExecutionTime;
+ private long mThreadCpuTime;
public UIViewOperationQueue(
ReactApplicationContext reactContext,
@@ -648,6 +665,7 @@
perfMap.put("RunStartTime", mProfiledBatchRunStartTime);
perfMap.put("BatchedExecutionTime", mProfiledBatchBatchedExecutionTime);
perfMap.put("NonBatchedExecutionTime", mProfiledBatchNonBatchedExecutionTime);
+ perfMap.put("NativeModulesThreadCpuTime", mThreadCpuTime);
return perfMap;
}
@@ -829,6 +847,10 @@
mOperations.add(new SendAccessibilityEvent(tag, eventType));
}
+ public void enqueueLayoutUpdateFinished(ReactShadowNode node, UIImplementation.LayoutUpdateListener listener) {
+ mOperations.add(new LayoutUpdateFinishedOperation(node, listener));
+ }
+
public void enqueueUIBlock(UIBlock block) {
mOperations.add(new UIBlockOperation(block));
}
@@ -846,6 +868,7 @@
.flush();
try {
final long dispatchViewUpdatesTime = SystemClock.uptimeMillis();
+ final long nativeModulesThreadCpuTime = SystemClock.currentThreadTimeMillis();
// Store the current operation queues to dispatch and create new empty ones to continue
// receiving new operations
@@ -900,6 +923,7 @@
mProfiledBatchLayoutTime = layoutTime;
mProfiledBatchDispatchViewUpdatesTime = dispatchViewUpdatesTime;
mProfiledBatchRunStartTime = runStartTime;
+ mThreadCpuTime = nativeModulesThreadCpuTime;
Systrace.beginAsyncSection(
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,

ReactAndroid/src/main/java/com/facebook/react/uimanager/util/ReactFindViewUtil.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewAtIndex.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewDefaults.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewGroupDrawingOrderHelper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewGroupManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -87,14 +87,6 @@
}
}
- public void startViewTransition(T parent, View view) {
- parent.startViewTransition(view);
- }
-
- public void endViewTransition(T parent, View view) {
- parent.endViewTransition(view);
- }
-
/**
* Returns whether this View type needs to handle laying out its own children instead of
* deferring to the standard css-layout algorithm.

ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewHierarchyDumper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,13 +10,18 @@
import android.view.View;
import com.facebook.react.bridge.BaseJavaModule;
import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableNativeMap;
import com.facebook.react.touch.JSResponderHandler;
import com.facebook.react.touch.ReactInterceptingViewGroup;
import com.facebook.react.uimanager.annotations.ReactProp;
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;
/**
@@ -28,7 +33,7 @@
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);
}
@@ -36,8 +41,8 @@
/**
* 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);
@@ -51,7 +56,7 @@
* @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
@@ -62,7 +67,7 @@
throw new RuntimeException("ViewManager subclasses must implement createShadowNodeInstance()");
}
- public C createShadowNodeInstance(ReactApplicationContext context) {
+ public @Nonnull C createShadowNodeInstance(@Nonnull ReactApplicationContext context) {
return createShadowNodeInstance();
}
@@ -82,13 +87,13 @@
* 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) {
}
/**
@@ -96,7 +101,7 @@
* 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) {
}
/**
@@ -105,7 +110,7 @@
* 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) {
}
/**
@@ -119,7 +124,7 @@
*
* 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
@@ -130,7 +135,7 @@
* @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) {
}
/**
@@ -202,4 +207,22 @@
public Map<String, String> getNativeProps() {
return ViewManagerPropertyUpdater.getNativeProps(getClass(), getShadowNodeClass());
}
+
+ /**
+ *
+ */
+ public @Nullable Object updateLocalData(@Nonnull T view, ReactStylesDiffMap props, ReactStylesDiffMap localData) {
+ return null;
+ }
+
+ public long measure(
+ ReactContext context,
+ ReadableNativeMap localData,
+ ReadableNativeMap props,
+ float width,
+ YogaMeasureMode widthMode,
+ float height,
+ YogaMeasureMode heightMode) {
+ return 0;
+ }
}

ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerPropertyUpdater.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerRegistry.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagersPropertyCache.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -106,6 +106,7 @@
public static final String VISIBLE = "visible";
public static final String ALLOW_FONT_SCALING = "allowFontScaling";
+ public static final String MAX_FONT_SIZE_MULTIPLIER = "maxFontSizeMultiplier";
public static final String INCLUDE_FONT_PADDING = "includeFontPadding";
public static final String BORDER_WIDTH = "borderWidth";

ReactAndroid/src/main/java/com/facebook/react/uimanager/YogaNodePool.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/util/JSStackTrace.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2017-present, Facebook, Inc.
+ * 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.
@@ -15,7 +15,7 @@
public class JSStackTrace {
- final private static Pattern mJsModuleIdPattern = Pattern.compile("(?:^|[/\\\\])(\\d+\\.js)$");
+ private static final Pattern FILE_ID_PATTERN = Pattern.compile("\\b((?:seg-\\d+(?:_\\d+)?|\\d+)\\.js)");
public static String format(String message, ReadableArray stack) {
StringBuilder stringBuilder = new StringBuilder(message).append(", stack:\n");
@@ -24,7 +24,7 @@
stringBuilder
.append(frame.getString("methodName"))
.append("@")
- .append(stackFrameToModuleId(frame))
+ .append(parseFileId(frame))
.append(frame.getInt("lineNumber"));
if (frame.hasKey("column") &&
!frame.isNull("column") &&
@@ -38,16 +38,18 @@
return stringBuilder.toString();
}
- // If the file name of a stack frame is numeric (+ ".js"), we assume it's a lazily injected module
- // coming from a "random access bundle". We are using special source maps for these bundles, so
- // that we can symbolicate stack traces for multiple injected files with a single source map.
- // We have to include the module id in the stack for that, though. The ".js" suffix is kept to
- // avoid ambiguities between "module-id:line" and "line:column".
- private static String stackFrameToModuleId(ReadableMap frame) {
+ // Besides a regular bundle (e.g. "bundle.js"), a stack frame can be produced by:
+ // 1) "random access bundle (RAM)", e.g. "1.js", where "1" is a module name
+ // 2) "segment file", e.g. "seg-1.js", where "1" is a segment name
+ // 3) "RAM segment file", e.g. "seg-1_2.js", where "1" is a segment name and "2" is a module name
+ // We are using a special source map format for such cases, so that we could symbolicate
+ // stack traces with a single source map file.
+ // NOTE: The ".js" suffix is kept to avoid ambiguities between "module-id:line" and "line:column".
+ private static String parseFileId(ReadableMap frame) {
if (frame.hasKey("file") &&
!frame.isNull("file") &&
frame.getType("file") == ReadableType.String) {
- final Matcher matcher = mJsModuleIdPattern.matcher(frame.getString("file"));
+ final Matcher matcher = FILE_ID_PATTERN.matcher(frame.getString("file"));
if (matcher.find()) {
return matcher.group(1) + ":";
}

ReactAndroid/src/main/java/com/facebook/react/ViewManagerOnDemandReactPackage.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/art/ARTGroupShadowNode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -28,11 +28,6 @@
public ARTGroupShadowNode() { }
- public ARTGroupShadowNode(ARTGroupShadowNode node) {
- super(node);
- this.mClipping = new RectF(node.mClipping);
- }
-
@ReactProp(name = "clipping")
public void setClipping(@Nullable ReadableArray clippingDims) {
float[] clippingData = PropHelper.toFloatArray(clippingDims);
@@ -43,11 +38,6 @@
}
@Override
- protected ReactShadowNodeImpl copy() {
- return new ARTGroupShadowNode(this);
- }
-
- @Override
public boolean isVirtual() {
return true;
}

ReactAndroid/src/main/java/com/facebook/react/views/art/ARTGroupViewManager.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/views/art/ARTRenderableViewManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -20,9 +20,9 @@
*/
public class ARTRenderableViewManager extends ViewManager<View, ReactShadowNode> {
- /* package */ static final String CLASS_GROUP = "ARTGroup";
- /* package */ static final String CLASS_SHAPE = "ARTShape";
- /* package */ static final String CLASS_TEXT = "ARTText";
+ public static final String CLASS_GROUP = "ARTGroup";
+ public static final String CLASS_SHAPE = "ARTShape";
+ public static final String CLASS_TEXT = "ARTText";
private final String mClassName;

ReactAndroid/src/main/java/com/facebook/react/views/art/ARTShapeShadowNode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -60,22 +60,6 @@
public ARTShapeShadowNode() { }
- public ARTShapeShadowNode(ARTShapeShadowNode node) {
- super(node);
- mPath = new Path(node.mPath);
- mStrokeColor = copyArray(node.mStrokeColor);
- mBrushData = copyArray(node.mBrushData);
- mStrokeDash = copyArray(node.mStrokeDash);
- mStrokeWidth = node.mStrokeWidth;
- mStrokeCap = node.mStrokeCap;
- mStrokeJoin = node.mStrokeJoin;
- }
-
- @Override
- protected ARTShapeShadowNode copy() {
- return new ARTShapeShadowNode(this);
- }
-
@ReactProp(name = "d")
public void setShapePath(@Nullable ReadableArray shapePath) {
float[] pathData = PropHelper.toFloatArray(shapePath);

ReactAndroid/src/main/java/com/facebook/react/views/art/ARTShapeViewManager.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceView.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -22,7 +22,7 @@
public class ARTSurfaceViewManager extends
BaseViewManager<ARTSurfaceView, ARTSurfaceViewShadowNode> {
- protected static final String REACT_CLASS = "ARTSurfaceView";
+ public static final String REACT_CLASS = "ARTSurfaceView";
private static final YogaMeasureFunction MEASURE_FUNCTION = new YogaMeasureFunction() {
@Override

ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewShadowNode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/art/ARTTextShadowNode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -42,17 +42,6 @@
public ARTTextShadowNode() { }
- public ARTTextShadowNode(ARTTextShadowNode node) {
- super(node);
- mTextAlignment = node.mTextAlignment;
- mFrame = node.mFrame; // copy reference as mFrame is already immutable
- }
-
- @Override
- protected ARTShapeShadowNode copy() {
- return new ARTTextShadowNode(this);
- }
-
@ReactProp(name = "frame")
public void setFrame(@Nullable ReadableMap frame) {
mFrame = frame;

ReactAndroid/src/main/java/com/facebook/react/views/art/ARTTextViewManager.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/views/art/ARTVirtualNode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -37,13 +37,6 @@
mScale = DisplayMetricsHolder.getWindowDisplayMetrics().density;
}
- protected ARTVirtualNode(ARTVirtualNode artVirtualNode) {
- super(artVirtualNode);
- mScale = artVirtualNode.mScale;
- mOpacity = artVirtualNode.mOpacity;
- mMatrix = new Matrix(artVirtualNode.mMatrix);
- }
-
@Override
public boolean isVirtual() {
return true;

ReactAndroid/src/main/java/com/facebook/react/views/art/PropHelper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/checkbox/ReactCheckBoxEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2017-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/checkbox/ReactCheckBox.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2017-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/checkbox/ReactCheckBoxManager.java

@@ -1,11 +1,13 @@
/**
- * Copyright (c) 2017-present, Facebook, Inc.
+ * 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.views.checkbox;
+import android.content.Context;
+import android.support.v7.widget.TintContextWrapper;
import android.widget.CompoundButton;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.uimanager.SimpleViewManager;
@@ -13,7 +15,6 @@
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.ViewProps;
import com.facebook.react.uimanager.annotations.ReactProp;
-import com.facebook.react.uimanager.events.EventDispatcher;
/** View manager for {@link ReactCheckBox} components. */
public class ReactCheckBoxManager extends SimpleViewManager<ReactCheckBox> {
@@ -24,11 +25,22 @@
new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- ReactContext reactContext = (ReactContext) buttonView.getContext();
+ ReactContext reactContext = getReactContext(buttonView);
reactContext
.getNativeModule(UIManagerModule.class).getEventDispatcher()
.dispatchEvent(new ReactCheckBoxEvent(buttonView.getId(), isChecked));
}
+
+ private ReactContext getReactContext(CompoundButton buttonView) {
+ ReactContext reactContext;
+ Context ctx = buttonView.getContext();
+ if (ctx instanceof TintContextWrapper) {
+ reactContext = (ReactContext) ((TintContextWrapper) ctx).getBaseContext();
+ } else {
+ reactContext = (ReactContext) buttonView.getContext();
+ }
+ return reactContext;
+ }
};
@Override

ReactAndroid/src/main/java/com/facebook/react/views/common/ContextUtils.java

@@ -1,3 +1,9 @@
+/**
+ * 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.views.common;
import android.content.Context;

ReactAndroid/src/main/java/com/facebook/react/views/common/ViewHelper.java

@@ -1,31 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-package com.facebook.react.views.common;
-
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.view.View;
-
-/** Helper class for Views */
-public class ViewHelper {
-
- /**
- * Set the background to a given Drawable, or remove the background. It calls {@link
- * View#setBackground(Drawable)} or {@link View#setBackgroundDrawable(Drawable)} based on the sdk
- * version.
- *
- * @param view {@link View} to apply the background.
- * @param drawable {@link Drawable} The Drawable to use as the background, or null to remove the
- * background
- */
- public static void setBackground(View view, Drawable drawable) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
- view.setBackground(drawable);
- } else {
- view.setBackgroundDrawable(drawable);
- }
- }
-}

ReactAndroid/src/main/java/com/facebook/react/views/drawer/events/DrawerClosedEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/drawer/events/DrawerOpenedEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/drawer/events/DrawerSlideEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/drawer/events/DrawerStateChangedEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/drawer/ReactDrawerLayout.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/drawer/ReactDrawerLayoutManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/image/BUCK

@@ -8,7 +8,6 @@
name = "imageevents",
srcs = IMAGE_EVENT_FILES,
provided_deps = [
- react_native_dep("third-party/android/support-annotations:android-support-annotations"),
react_native_dep("third-party/android/support/v4:lib-support-v4"),
],
required_for_source_only_abi = True,
@@ -27,7 +26,6 @@
exclude = IMAGE_EVENT_FILES,
),
provided_deps = [
- react_native_dep("third-party/android/support-annotations:android-support-annotations"),
react_native_dep("third-party/android/support/v4:lib-support-v4"),
],
visibility = [

ReactAndroid/src/main/java/com/facebook/react/views/image/GlobalImageLoadListener.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/views/image/ImageLoadEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -33,13 +33,18 @@
private final @Nullable String mImageUri;
private final int mWidth;
private final int mHeight;
+ private final @Nullable String mImageError;
public ImageLoadEvent(int viewId, @ImageEventType int eventType) {
this(viewId, eventType, null);
}
+ public ImageLoadEvent(int viewId, @ImageEventType int eventType, boolean error, String message) {
+ this(viewId, eventType, null, 0, 0, message);
+ }
+
public ImageLoadEvent(int viewId, @ImageEventType int eventType, String imageUri) {
- this(viewId, eventType, imageUri, 0, 0);
+ this(viewId, eventType, imageUri, 0, 0, null);
}
public ImageLoadEvent(
@@ -48,11 +53,22 @@
@Nullable String imageUri,
int width,
int height) {
+ this(viewId, eventType, imageUri, width, height, null);
+ }
+
+ public ImageLoadEvent(
+ int viewId,
+ @ImageEventType int eventType,
+ @Nullable String imageUri,
+ int width,
+ int height,
+ @Nullable String message) {
super(viewId);
mEventType = eventType;
mImageUri = imageUri;
mWidth = width;
mHeight = height;
+ mImageError = message;
}
public static String eventNameForType(@ImageEventType int eventType) {
@@ -88,7 +104,7 @@
public void dispatch(RCTEventEmitter rctEventEmitter) {
WritableMap eventData = null;
- if (mImageUri != null || mEventType == ON_LOAD) {
+ if (mImageUri != null || (mEventType == ON_LOAD || mEventType == ON_ERROR)) {
eventData = Arguments.createMap();
if (mImageUri != null) {
@@ -103,6 +119,8 @@
source.putString("url", mImageUri);
}
eventData.putMap("source", source);
+ } else if (mEventType == ON_ERROR) {
+ eventData.putString("error", mImageError);
}
}

ReactAndroid/src/main/java/com/facebook/react/views/image/ImageResizeMethod.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/image/ImageResizeMode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/image/MultiPostprocessor.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2017-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -29,7 +29,7 @@
@ReactModule(name = ReactImageManager.REACT_CLASS)
public class ReactImageManager extends SimpleViewManager<ReactImageView> {
- protected static final String REACT_CLASS = "RCTImageView";
+ public static final String REACT_CLASS = "RCTImageView";
@Override
public String getName() {
@@ -109,7 +109,7 @@
}
}
- @ReactProp(name = "overlayColor")
+ @ReactProp(name = "overlayColor", customType = "Color")
public void setOverlayColor(ReactImageView view, @Nullable Integer overlayColor) {
if (overlayColor == null) {
view.setOverlayColor(Color.TRANSPARENT);

ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java

@@ -1,6 +1,6 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -262,9 +262,8 @@
@Override
public void onFailure(String id, Throwable throwable) {
mEventDispatcher.dispatchEvent(
- new ImageLoadEvent(getId(), ImageLoadEvent.ON_ERROR));
- mEventDispatcher.dispatchEvent(
- new ImageLoadEvent(getId(), ImageLoadEvent.ON_LOAD_END));
+ new ImageLoadEvent(getId(), ImageLoadEvent.ON_ERROR,
+ true, throwable.getMessage()));
}
};
}

ReactAndroid/src/main/java/com/facebook/react/views/image/ScaleTypeStartInside.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2017-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/imagehelper/ImageSource.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/imagehelper/MultiSourceHelper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/imagehelper/ResourceDrawableIdHelper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/modal/ModalHostHelper.java

@@ -1,11 +1,10 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.views.modal;
-import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -34,7 +33,6 @@
* and landscape on tablets.
* This should only be called on the native modules/shadow nodes thread.
*/
- @TargetApi(16)
public static Point getModalHostSize(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = Assertions.assertNotNull(wm).getDefaultDisplay();

ReactAndroid/src/main/java/com/facebook/react/views/modal/ModalHostShadowNode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -23,15 +23,6 @@
public ModalHostShadowNode() {}
- private ModalHostShadowNode(ModalHostShadowNode node) {
- super(node);
- }
-
- @Override
- protected ModalHostShadowNode copy() {
- return new ModalHostShadowNode(this);
- }
-
/**
* We need to set the styleWidth and styleHeight of the one child (represented by the <View/>
* within the <RCTModalHostView/> in Modal.js. This needs to fill the entire window.

ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -24,7 +24,7 @@
@ReactModule(name = ReactModalHostManager.REACT_CLASS)
public class ReactModalHostManager extends ViewGroupManager<ReactModalHostView> {
- protected static final String REACT_CLASS = "RCTModalHostView";
+ public static final String REACT_CLASS = "RCTModalHostView";
@Override
public String getName() {

ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,6 +7,7 @@
package com.facebook.react.views.modal;
+import android.annotation.TargetApi;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
@@ -15,6 +16,7 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewStructure;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.widget.FrameLayout;
@@ -73,6 +75,12 @@
mHostView = new DialogRootViewGroup(context);
}
+ @TargetApi(23)
+ @Override
+ public void dispatchProvideStructure(ViewStructure structure) {
+ mHostView.dispatchProvideStructure(structure);
+ }
+
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// Do nothing as we are laid out by UIManager

ReactAndroid/src/main/java/com/facebook/react/views/modal/RequestCloseEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/modal/ShowEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/picker/BUCK

@@ -6,6 +6,10 @@
visibility = [
"PUBLIC",
],
+ provided_deps = [
+ react_native_dep("third-party/android/support/v4:lib-support-v4"),
+ react_native_dep("third-party/android/support/v7/appcompat-orig:appcompat"),
+ ],
deps = [
react_native_dep("third-party/java/infer-annotations:infer-annotations"),
react_native_dep("third-party/java/jsr-305:jsr-305"),

ReactAndroid/src/main/java/com/facebook/react/views/picker/events/PickerItemSelectEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactDialogPickerManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -18,7 +18,7 @@
@ReactModule(name = ReactDialogPickerManager.REACT_CLASS)
public class ReactDialogPickerManager extends ReactPickerManager {
- protected static final String REACT_CLASS = "AndroidDialogPicker";
+ public static final String REACT_CLASS = "AndroidDialogPicker";
@Override
public String getName() {

ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactDropdownPickerManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -18,7 +18,7 @@
@ReactModule(name = ReactDropdownPickerManager.REACT_CLASS)
public class ReactDropdownPickerManager extends ReactPickerManager {
- protected static final String REACT_CLASS = "AndroidDropdownPicker";
+ public static final String REACT_CLASS = "AndroidDropdownPicker";
@Override
public String getName() {

ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactPicker.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,9 +7,8 @@
package com.facebook.react.views.picker;
-import javax.annotation.Nullable;
-
import android.content.Context;
+import android.support.v7.widget.AppCompatSpinner;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AdapterView;
@@ -17,14 +16,31 @@
import com.facebook.react.common.annotations.VisibleForTesting;
-public class ReactPicker extends Spinner {
+import javax.annotation.Nullable;
+
+public class ReactPicker extends AppCompatSpinner {
- private int mMode = MODE_DIALOG;
+ private int mMode = Spinner.MODE_DIALOG;
private @Nullable Integer mPrimaryColor;
- private boolean mSuppressNextEvent;
private @Nullable OnSelectListener mOnSelectListener;
private @Nullable Integer mStagedSelection;
+ private final OnItemSelectedListener mItemSelectedListener = new OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ if (mOnSelectListener != null) {
+ mOnSelectListener.onItemSelected(position);
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ if (mOnSelectListener != null) {
+ mOnSelectListener.onItemSelected(-1);
+ }
+ }
+ };
+
/**
* Listener interface for ReactPicker events.
*/
@@ -75,31 +91,19 @@
post(measureAndLayout);
}
- public void setOnSelectListener(@Nullable OnSelectListener onSelectListener) {
- if (getOnItemSelectedListener() == null) {
- // onItemSelected gets fired immediately after layout because checkSelectionChanged() in
- // AdapterView updates the selection position from the default INVALID_POSITION. To match iOS
- // behavior, we don't want the event emitter for onItemSelected to fire right after layout.
- mSuppressNextEvent = true;
- setOnItemSelectedListener(
- new OnItemSelectedListener() {
@Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- if (!mSuppressNextEvent && mOnSelectListener != null) {
- mOnSelectListener.onItemSelected(position);
- }
- mSuppressNextEvent = false;
- }
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- if (!mSuppressNextEvent && mOnSelectListener != null) {
- mOnSelectListener.onItemSelected(-1);
- }
- mSuppressNextEvent = false;
- }
- });
+ // onItemSelected gets fired immediately after layout because checkSelectionChanged() in
+ // AdapterView updates the selection position from the default INVALID_POSITION.
+ // To match iOS behavior, which no onItemSelected during initial layout.
+ // We setup the listener after layout.
+ if (getOnItemSelectedListener() == null)
+ setOnItemSelectedListener(mItemSelectedListener);
}
+
+ public void setOnSelectListener(@Nullable OnSelectListener onSelectListener) {
mOnSelectListener = onSelectListener;
}
@@ -130,8 +134,9 @@
*/
private void setSelectionWithSuppressEvent(int position) {
if (position != getSelectedItemPosition()) {
- mSuppressNextEvent = true;
- setSelection(position);
+ setOnItemSelectedListener(null);
+ setSelection(position, false);
+ setOnItemSelectedListener(mItemSelectedListener);
}
}

ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactPickerManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarContainerView.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,23 +7,19 @@
package com.facebook.react.views.progressbar;
-import com.facebook.react.uimanager.ReactShadowNodeImpl;
-import javax.annotation.Nullable;
-
-import java.util.HashSet;
-import java.util.Set;
-
import android.util.SparseIntArray;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
-
-import com.facebook.yoga.YogaMeasureMode;
-import com.facebook.yoga.YogaMeasureFunction;
-import com.facebook.yoga.YogaNode;
-import com.facebook.yoga.YogaMeasureOutput;
import com.facebook.react.uimanager.LayoutShadowNode;
import com.facebook.react.uimanager.annotations.ReactProp;
+import com.facebook.yoga.YogaMeasureFunction;
+import com.facebook.yoga.YogaMeasureMode;
+import com.facebook.yoga.YogaMeasureOutput;
+import com.facebook.yoga.YogaNode;
+import java.util.HashSet;
+import java.util.Set;
+import javax.annotation.Nullable;
/**
* Node responsible for holding the style of the ProgressBar, see under
@@ -45,36 +41,10 @@
initMeasureFunction();
}
- public ProgressBarShadowNode(ProgressBarShadowNode node) {
- super(node);
- mWidth = node.mWidth.clone();
- mHeight = node.mHeight.clone();
- mMeasured = new HashSet<>(node.mMeasured);
- }
-
- @Override
- public ReactShadowNodeImpl mutableCopyWithNewChildren(long instanceHandle) {
- ProgressBarShadowNode node = (ProgressBarShadowNode) super.mutableCopyWithNewChildren(instanceHandle);
- node.initMeasureFunction();
- return node;
- }
-
private void initMeasureFunction() {
setMeasureFunction(this);
}
- @Override
- public ReactShadowNodeImpl mutableCopy(long instanceHandle) {
- ProgressBarShadowNode node = (ProgressBarShadowNode) super.mutableCopy(instanceHandle);
- node.initMeasureFunction();
- return node;
- }
-
- @Override
- public ProgressBarShadowNode copy() {
- return new ProgressBarShadowNode(this);
- }
-
public @Nullable String getStyle() {
return mStyle;
}

ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ReactProgressBarViewManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -29,7 +29,7 @@
public class ReactProgressBarViewManager extends
BaseViewManager<ProgressBarContainerView, ProgressBarShadowNode> {
- protected static final String REACT_CLASS = "AndroidProgressBar";
+ public static final String REACT_CLASS = "AndroidProgressBar";
/* package */ static final String PROP_STYLE = "styleAttr";
/* package */ static final String PROP_INDETERMINATE = "indeterminate";

ReactAndroid/src/main/java/com/facebook/react/views/scroll/FpsListener.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/scroll/OnScrollDispatchHelper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollContainerView.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -6,6 +6,7 @@
package com.facebook.react.views.scroll;
import android.content.Context;
+import android.support.v4.view.ViewCompat;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import com.facebook.react.modules.i18nmanager.I18nUtil;
@@ -19,7 +20,7 @@
public ReactHorizontalScrollContainerView(Context context) {
super(context);
mLayoutDirection =
- I18nUtil.getInstance().isRTL(context) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR;
+ I18nUtil.getInstance().isRTL(context) ? ViewCompat.LAYOUT_DIRECTION_RTL : ViewCompat.LAYOUT_DIRECTION_LTR;
mCurrentWidth = 0;
}

ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollContainerViewManager.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -14,7 +14,7 @@
public class ReactHorizontalScrollContainerViewManager
extends ViewGroupManager<ReactHorizontalScrollContainerView> {
- protected static final String REACT_CLASS = "AndroidHorizontalScrollContentView";
+ public static final String REACT_CLASS = "AndroidHorizontalScrollContentView";
public ReactHorizontalScrollContainerViewManager() {}

ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,7 +7,6 @@
package com.facebook.react.views.scroll;
-import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -42,7 +41,6 @@
/**
* Similar to {@link ReactScrollView} but only supports horizontal scrolling.
*/
-@TargetApi(16)
public class ReactHorizontalScrollView extends HorizontalScrollView implements
ReactClippingViewGroup {
@@ -70,6 +68,8 @@
private int mSnapInterval = 0;
private float mDecelerationRate = 0.985f;
private @Nullable List<Integer> mSnapOffsets;
+ private boolean mSnapToStart = true;
+ private boolean mSnapToEnd = true;
private ReactViewBackgroundManager mReactBackgroundManager;
public ReactHorizontalScrollView(Context context) {
@@ -169,6 +169,14 @@
mSnapOffsets = snapOffsets;
}
+ public void setSnapToStart(boolean snapToStart) {
+ mSnapToStart = snapToStart;
+ }
+
+ public void setSnapToEnd(boolean snapToEnd) {
+ mSnapToEnd = snapToEnd;
+ }
+
public void flashScrollIndicators() {
awakenScrollBars();
}
@@ -276,8 +284,18 @@
@Override
public void fling(int velocityX) {
+
+ // Workaround.
+ // On Android P if a ScrollView is inverted, we will get a wrong sign for
+ // velocityX (see https://issuetracker.google.com/issues/112385925).
+ // At the same time, mOnScrollDispatchHelper tracks the correct velocity direction.
+ //
+ // Hence, we can use the absolute value from whatever the OS gives
+ // us and use the sign of what mOnScrollDispatchHelper has tracked.
+ final int correctedVelocityX = (int)(Math.abs(velocityX) * Math.signum(mOnScrollDispatchHelper.getXFlingVelocity()));
+
if (mPagingEnabled) {
- flingAndSnap(velocityX);
+ flingAndSnap(correctedVelocityX);
} else if (mScroller != null) {
// FB SCROLLVIEW CHANGE
@@ -287,12 +305,12 @@
// as there is content. See #onOverScrolled() to see the second part of this change which properly
// aborts the scroller animation when we get to the bottom of the ScrollView content.
- int scrollWindowWidth = getWidth() - getPaddingStart() - getPaddingEnd();
+ int scrollWindowWidth = getWidth() - ViewCompat.getPaddingStart(this) - ViewCompat.getPaddingEnd(this);
mScroller.fling(
getScrollX(), // startX
getScrollY(), // startY
- velocityX, // velocityX
+ correctedVelocityX, // velocityX
0, // velocityY
0, // minX
Integer.MAX_VALUE, // maxX
@@ -306,9 +324,9 @@
// END FB SCROLLVIEW CHANGE
} else {
- super.fling(velocityX);
+ super.fling(correctedVelocityX);
}
- handlePostTouchScrolling(velocityX, 0);
+ handlePostTouchScrolling(correctedVelocityX, 0);
}
@Override
@@ -483,7 +501,7 @@
// predict where a fling would end up so we can scroll to the nearest snap offset
int maximumOffset = Math.max(0, computeHorizontalScrollRange() - getWidth());
- int width = getWidth() - getPaddingStart() - getPaddingEnd();
+ int width = getWidth() - ViewCompat.getPaddingStart(this) - ViewCompat.getPaddingEnd(this);
scroller.fling(
getScrollX(), // startX
getScrollY(), // startY
@@ -565,7 +583,7 @@
int largerOffset = maximumOffset;
int firstOffset = 0;
int lastOffset = maximumOffset;
- int width = getWidth() - getPaddingStart() - getPaddingEnd();
+ int width = getWidth() - ViewCompat.getPaddingStart(this) - ViewCompat.getPaddingEnd(this);
// offsets are from the right edge in RTL layouts
boolean isRTL = TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault()) == ViewCompat.LAYOUT_DIRECTION_RTL;
@@ -576,6 +594,9 @@
// get the nearest snap points to the target offset
if (mSnapOffsets != null) {
+ firstOffset = mSnapOffsets.get(0);
+ lastOffset = mSnapOffsets.get(mSnapOffsets.size() - 1);
+
for (int i = 0; i < mSnapOffsets.size(); i ++) {
int offset = mSnapOffsets.get(i);
@@ -603,10 +624,35 @@
? smallerOffset
: largerOffset;
- // Chose the correct snap offset based on velocity
- if (velocityX > 0) {
+ // if scrolling after the last snap offset and snapping to the
+ // end of the list is disabled, then we allow free scrolling
+ int currentOffset = getScrollX();
+ if (isRTL) {
+ currentOffset = maximumOffset - currentOffset;
+ }
+ if (!mSnapToEnd && targetOffset >= lastOffset) {
+ if (currentOffset >= lastOffset) {
+ // free scrolling
+ } else {
+ // snap to end
+ targetOffset = lastOffset;
+ }
+ } else if (!mSnapToStart && targetOffset <= firstOffset) {
+ if (currentOffset <= firstOffset) {
+ // free scrolling
+ } else {
+ // snap to beginning
+ targetOffset = firstOffset;
+ }
+ } else if (velocityX > 0) {
+ // when snapping velocity can feel sluggish for slow swipes
+ velocityX += (int) ((largerOffset - targetOffset) * 10.0);
+
targetOffset = largerOffset;
} else if (velocityX < 0) {
+ // when snapping velocity can feel sluggish for slow swipes
+ velocityX -= (int) ((targetOffset - smallerOffset) * 10.0);
+
targetOffset = smallerOffset;
} else {
targetOffset = nearestOffset;

ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -39,7 +39,7 @@
extends ViewGroupManager<ReactHorizontalScrollView>
implements ReactScrollViewCommandHelper.ScrollCommandHandler<ReactHorizontalScrollView> {
- protected static final String REACT_CLASS = "AndroidHorizontalScrollView";
+ public static final String REACT_CLASS = "AndroidHorizontalScrollView";
private static final int[] SPACING_TYPES = {
Spacing.ALL, Spacing.LEFT, Spacing.RIGHT, Spacing.TOP, Spacing.BOTTOM,
@@ -97,6 +97,16 @@
view.setSnapOffsets(offsets);
}
+ @ReactProp(name = "snapToStart")
+ public void setSnapToStart(ReactHorizontalScrollView view, boolean snapToStart) {
+ view.setSnapToStart(snapToStart);
+ }
+
+ @ReactProp(name = "snapToEnd")
+ public void setSnapToEnd(ReactHorizontalScrollView view, boolean snapToEnd) {
+ view.setSnapToEnd(snapToEnd);
+ }
+
@ReactProp(name = ReactClippingViewGroupHelper.PROP_REMOVE_CLIPPED_SUBVIEWS)
public void setRemoveClippedSubviews(ReactHorizontalScrollView view, boolean removeClippedSubviews) {
view.setRemoveClippedSubviews(removeClippedSubviews);
@@ -245,4 +255,9 @@
public void setOverflow(ReactHorizontalScrollView view, @Nullable String overflow) {
view.setOverflow(overflow);
}
+
+ @ReactProp(name = "persistentScrollbar")
+ public void setPersistentScrollbar(ReactHorizontalScrollView view, boolean value) {
+ view.setScrollbarFadingEnabled(!value);
+ }
}

ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewCommandHelper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,7 +7,6 @@
package com.facebook.react.views.scroll;
-import android.annotation.TargetApi;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
@@ -42,7 +41,6 @@
* <p>ReactScrollView only supports vertical scrolling. For horizontal scrolling,
* use {@link ReactHorizontalScrollView}.
*/
-@TargetApi(11)
public class ReactScrollView extends ScrollView implements ReactClippingViewGroup, ViewGroup.OnHierarchyChangeListener, View.OnLayoutChangeListener {
private static @Nullable Field sScrollerField;
@@ -69,6 +67,8 @@
private int mSnapInterval = 0;
private float mDecelerationRate = 0.985f;
private @Nullable List<Integer> mSnapOffsets;
+ private boolean mSnapToStart = true;
+ private boolean mSnapToEnd = true;
private View mContentView;
private ReactViewBackgroundManager mReactBackgroundManager;
@@ -157,6 +157,14 @@
mSnapOffsets = snapOffsets;
}
+ public void setSnapToStart(boolean snapToStart) {
+ mSnapToStart = snapToStart;
+ }
+
+ public void setSnapToEnd(boolean snapToEnd) {
+ mSnapToEnd = snapToEnd;
+ }
+
public void flashScrollIndicators() {
awakenScrollBars();
}
@@ -547,6 +555,9 @@
// get the nearest snap points to the target offset
if (mSnapOffsets != null) {
+ firstOffset = mSnapOffsets.get(0);
+ lastOffset = mSnapOffsets.get(mSnapOffsets.size() - 1);
+
for (int i = 0; i < mSnapOffsets.size(); i ++) {
int offset = mSnapOffsets.get(i);
@@ -574,10 +585,31 @@
? smallerOffset
: largerOffset;
- // Chose the correct snap offset based on velocity
- if (velocityY > 0) {
+ // if scrolling after the last snap offset and snapping to the
+ // end of the list is disabled, then we allow free scrolling
+ if (!mSnapToEnd && targetOffset >= lastOffset) {
+ if (getScrollY() >= lastOffset) {
+ // free scrolling
+ } else {
+ // snap to end
+ targetOffset = lastOffset;
+ }
+ } else if (!mSnapToStart && targetOffset <= firstOffset) {
+ if (getScrollY() <= firstOffset) {
+ // free scrolling
+ } else {
+ // snap to beginning
+ targetOffset = firstOffset;
+ }
+ } else if (velocityY > 0) {
+ // when snapping velocity can feel sluggish for slow swipes
+ velocityY += (int) ((largerOffset - targetOffset) * 10.0);
+
targetOffset = largerOffset;
} else if (velocityY < 0) {
+ // when snapping velocity can feel sluggish for slow swipes
+ velocityY -= (int) ((targetOffset - smallerOffset) * 10.0);
+
targetOffset = smallerOffset;
} else {
targetOffset = nearestOffset;

ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,7 +7,6 @@
package com.facebook.react.views.scroll;
-import android.annotation.TargetApi;
import android.graphics.Color;
import android.support.v4.view.ViewCompat;
import android.util.DisplayMetrics;
@@ -37,13 +36,12 @@
* <p>Note that {@link ReactScrollView} and {@link ReactScrollView} are exposed to JS
* as a single ScrollView component, configured via the {@code horizontal} boolean property.
*/
-@TargetApi(11)
@ReactModule(name = ReactScrollViewManager.REACT_CLASS)
public class ReactScrollViewManager
extends ViewGroupManager<ReactScrollView>
implements ReactScrollViewCommandHelper.ScrollCommandHandler<ReactScrollView> {
- protected static final String REACT_CLASS = "RCTScrollView";
+ public static final String REACT_CLASS = "RCTScrollView";
private static final int[] SPACING_TYPES = {
Spacing.ALL, Spacing.LEFT, Spacing.RIGHT, Spacing.TOP, Spacing.BOTTOM,
@@ -101,6 +99,16 @@
view.setSnapOffsets(offsets);
}
+ @ReactProp(name = "snapToStart")
+ public void setSnapToStart(ReactScrollView view, boolean snapToStart) {
+ view.setSnapToStart(snapToStart);
+ }
+
+ @ReactProp(name = "snapToEnd")
+ public void setSnapToEnd(ReactScrollView view, boolean snapToEnd) {
+ view.setSnapToEnd(snapToEnd);
+ }
+
@ReactProp(name = ReactClippingViewGroupHelper.PROP_REMOVE_CLIPPED_SUBVIEWS)
public void setRemoveClippedSubviews(ReactScrollView view, boolean removeClippedSubviews) {
view.setRemoveClippedSubviews(removeClippedSubviews);
@@ -254,6 +262,11 @@
}
}
+ @ReactProp(name = "persistentScrollbar")
+ public void setPersistentScrollbar(ReactScrollView view, boolean value) {
+ view.setScrollbarFadingEnabled(!value);
+ }
+
@Override
public @Nullable Map<String, Object> getExportedCustomDirectEventTypeConstants() {
return createExportedCustomDirectEventTypeConstants();

ReactAndroid/src/main/java/com/facebook/react/views/scroll/ScrollEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/scroll/ScrollEventType.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/scroll/VelocityHelper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2017-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/slider/BUCK

@@ -3,14 +3,13 @@
rn_android_library(
name = "slider",
srcs = glob(["*.java"]),
- provided_deps = [
- react_native_dep("third-party/android/support/v7/appcompat-orig:appcompat"),
- ],
visibility = [
"PUBLIC",
],
deps = [
YOGA_TARGET,
+ react_native_dep("third-party/android/support/v7/appcompat-orig:appcompat"),
+ react_native_dep("third-party/android/support/v4:lib-support-v4"),
react_native_dep("third-party/java/jsr-305:jsr-305"),
react_native_target("java/com/facebook/react/bridge:bridge"),
react_native_target("java/com/facebook/react/common:common"),

ReactAndroid/src/main/java/com/facebook/react/views/slider/ReactSliderEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/slider/ReactSlider.java

@@ -1,57 +1,64 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
+ * <p>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.views.slider;
import android.content.Context;
+import android.os.Build;
+import android.support.v7.widget.AppCompatSeekBar;
import android.util.AttributeSet;
-import android.widget.SeekBar;
-
import javax.annotation.Nullable;
/**
* Slider that behaves more like the iOS one, for consistency.
*
- * On iOS, the value is 0..1. Android SeekBar only supports integer values.
- * For consistency, we pretend in JS that the value is 0..1 but set the
- * SeekBar value to 0..100.
+ * <p>On iOS, the value is 0..1. Android SeekBar only supports integer values. For consistency, we
+ * pretend in JS that the value is 0..1 but set the SeekBar value to 0..100.
*
- * Note that the slider is _not_ a controlled component (setValue isn't called
- * during dragging).
+ * <p>Note that the slider is _not_ a controlled component (setValue isn't called during dragging).
*/
-public class ReactSlider extends SeekBar {
+public class ReactSlider extends AppCompatSeekBar {
/**
- * If step is 0 (unset) we default to this total number of steps.
- * Don't use 100 which leads to rounding errors (0.200000000001).
+ * If step is 0 (unset) we default to this total number of steps. Don't use 100 which leads to
+ * rounding errors (0.200000000001).
*/
private static int DEFAULT_TOTAL_STEPS = 128;
/**
- * We want custom min..max range.
- * Android only supports 0..max range so we implement this ourselves.
+ * We want custom min..max range. Android only supports 0..max range so we implement this
+ * ourselves.
*/
private double mMinValue = 0;
+
private double mMaxValue = 0;
/**
- * Value sent from JS (setState).
- * Doesn't get updated during drag (slider is not a controlled component).
+ * Value sent from JS (setState). Doesn't get updated during drag (slider is not a controlled
+ * component).
*/
private double mValue = 0;
- /**
- * If zero it's determined automatically.
- */
+ /** If zero it's determined automatically. */
private double mStep = 0;
+
private double mStepCalculated = 0;
public ReactSlider(Context context, @Nullable AttributeSet attrs, int style) {
super(context, attrs, style);
+ disableStateListAnimatorIfNeeded();
+ }
+
+ private void disableStateListAnimatorIfNeeded() {
+ // We disable the state list animator for Android 6 and 7; this is a hack to prevent T37452851
+ // and https://github.com/facebook/react-native/issues/9979
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
+ && Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
+ super.setStateListAnimator(null);
+ }
}
/* package */ void setMaxValue(double max) {
@@ -75,8 +82,7 @@
}
/**
- * Convert SeekBar's native progress value (e.g. 0..100) to a value
- * passed to JS (e.g. -1.0..2.5).
+ * Convert SeekBar's native progress value (e.g. 0..100) to a value passed to JS (e.g. -1.0..2.5).
*/
public double toRealProgress(int seekBarProgress) {
if (seekBarProgress == getMax()) {
@@ -85,9 +91,7 @@
return seekBarProgress * getStepValue() + mMinValue;
}
- /**
- * Update underlying native SeekBar's values.
- */
+ /** Update underlying native SeekBar's values. */
private void updateAll() {
if (mStep == 0) {
mStepCalculated = (mMaxValue - mMinValue) / (double) DEFAULT_TOTAL_STEPS;
@@ -96,12 +100,9 @@
updateValue();
}
- /**
- * Update value only (optimization in case only value is set).
- */
+ /** Update value only (optimization in case only value is set). */
private void updateValue() {
- setProgress((int) Math.round(
- (mValue - mMinValue) / (mMaxValue - mMinValue) * getTotalSteps()));
+ setProgress((int) Math.round((mValue - mMinValue) / (mMaxValue - mMinValue) * getTotalSteps()));
}
private int getTotalSteps() {

ReactAndroid/src/main/java/com/facebook/react/views/slider/ReactSliderManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -38,7 +38,7 @@
private static final int STYLE = android.R.attr.seekBarStyle;
- private static final String REACT_CLASS = "RCTSlider";
+ public static final String REACT_CLASS = "RCTSlider";
static class ReactSliderShadowNode extends LayoutShadowNode implements
YogaMeasureFunction {
@@ -51,37 +51,11 @@
initMeasureFunction();
}
- private ReactSliderShadowNode(ReactSliderShadowNode node) {
- super(node);
- mWidth = node.mWidth;
- mHeight = node.mHeight;
- mMeasured = node.mMeasured;
- }
-
private void initMeasureFunction() {
setMeasureFunction(this);
}
@Override
- public ReactShadowNodeImpl mutableCopy(long instanceHandle) {
- ReactSliderShadowNode reactShadowNode = (ReactSliderShadowNode) super.mutableCopy(instanceHandle);
- reactShadowNode.initMeasureFunction();
- return reactShadowNode;
- }
-
- @Override
- public ReactShadowNodeImpl mutableCopyWithNewChildren(long instanceHandle) {
- ReactSliderShadowNode reactShadowNode = (ReactSliderShadowNode) super.mutableCopyWithNewChildren(instanceHandle);
- reactShadowNode.initMeasureFunction();
- return reactShadowNode;
- }
-
- @Override
- protected ReactSliderShadowNode copy() {
- return new ReactSliderShadowNode(this);
- }
-
- @Override
public long measure(
YogaNode node,
float width,

ReactAndroid/src/main/java/com/facebook/react/views/slider/ReactSlidingCompleteEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/ReactSwipeRefreshLayout.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/RefreshEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/SwipeRefreshLayoutManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -31,7 +31,7 @@
@ReactModule(name = REACT_CLASS)
public class SwipeRefreshLayoutManager extends ViewGroupManager<ReactSwipeRefreshLayout> {
- protected static final String REACT_CLASS = "AndroidSwipeRefreshLayout";
+ public static final String REACT_CLASS = "AndroidSwipeRefreshLayout";
@Override
protected ReactSwipeRefreshLayout createViewInstance(ThemedReactContext reactContext) {

ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitch.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -8,7 +8,10 @@
package com.facebook.react.views.switchview;
import android.content.Context;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
import android.support.v7.widget.SwitchCompat;
+import javax.annotation.Nullable;
/**
* Switch that has its value controlled by JS. Whenever the value of the switch changes, we do not
@@ -18,10 +21,14 @@
/*package*/ class ReactSwitch extends SwitchCompat {
private boolean mAllowChange;
+ @Nullable private Integer mTrackColorForFalse;
+ @Nullable private Integer mTrackColorForTrue;
public ReactSwitch(Context context) {
super(context);
mAllowChange = true;
+ mTrackColorForFalse = null;
+ mTrackColorForTrue = null;
}
@Override
@@ -29,14 +36,63 @@
if (mAllowChange && isChecked() != checked) {
mAllowChange = false;
super.setChecked(checked);
+ setTrackColor(checked);
}
}
+ void setColor(Drawable drawable, @Nullable Integer color) {
+ if (color == null) {
+ drawable.clearColorFilter();
+ } else {
+ drawable.setColorFilter(color, PorterDuff.Mode.MULTIPLY);
+ }
+ }
+
+ public void setTrackColor(@Nullable Integer color) {
+ setColor(super.getTrackDrawable(), color);
+ }
+
+ public void setThumbColor(@Nullable Integer color) {
+ setColor(super.getThumbDrawable(), color);
+ }
+
/*package*/ void setOn(boolean on) {
// If the switch has a different value than the value sent by JS, we must change it.
if (isChecked() != on) {
super.setChecked(on);
+ setTrackColor(on);
}
mAllowChange = true;
}
+
+ public void setTrackColorForTrue(@Nullable Integer color) {
+ if (color == mTrackColorForTrue) {
+ return;
+ }
+
+ mTrackColorForTrue = color;
+ if (isChecked()) {
+ setTrackColor(mTrackColorForTrue);
+ }
+ }
+
+ public void setTrackColorForFalse(@Nullable Integer color) {
+ if (color == mTrackColorForFalse) {
+ return;
+ }
+
+ mTrackColorForFalse = color;
+ if (!isChecked()) {
+ 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);
+ }
+ }
}

ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -25,13 +25,14 @@
import com.facebook.yoga.YogaMeasureMode;
import com.facebook.yoga.YogaMeasureOutput;
import com.facebook.yoga.YogaNode;
+import javax.annotation.Nullable;
/**
* View manager for {@link ReactSwitch} components.
*/
public class ReactSwitchManager extends SimpleViewManager<ReactSwitch> {
- private static final String REACT_CLASS = "AndroidSwitch";
+ public static final String REACT_CLASS = "AndroidSwitch";
static class ReactSwitchShadowNode extends LayoutShadowNode implements
YogaMeasureFunction {
@@ -44,37 +45,11 @@
initMeasureFunction();
}
- private ReactSwitchShadowNode(ReactSwitchShadowNode node) {
- super(node);
- mWidth = node.mWidth;
- mHeight = node.mHeight;
- mMeasured = node.mMeasured;
- }
-
private void initMeasureFunction() {
setMeasureFunction(this);
}
@Override
- public ReactShadowNodeImpl mutableCopy(long instanceHandle) {
- ReactSwitchShadowNode reactShadowNode = (ReactSwitchShadowNode) super.mutableCopy(instanceHandle);
- reactShadowNode.initMeasureFunction();
- return reactShadowNode;
- }
-
- @Override
- public ReactShadowNodeImpl mutableCopyWithNewChildren(long instanceHandle) {
- ReactSwitchShadowNode reactShadowNode = (ReactSwitchShadowNode) super.mutableCopyWithNewChildren(instanceHandle);
- reactShadowNode.initMeasureFunction();
- return reactShadowNode;
- }
-
- @Override
- protected ReactSwitchShadowNode copy() {
- return new ReactSwitchShadowNode(this);
- }
-
- @Override
public long measure(
YogaNode node,
float width,
@@ -88,7 +63,7 @@
ReactSwitch reactSwitch = new ReactSwitch(getThemedContext());
reactSwitch.setShowText(false);
final int spec = View.MeasureSpec.makeMeasureSpec(
- ViewGroup.LayoutParams.WRAP_CONTENT,
+ 0,
View.MeasureSpec.UNSPECIFIED);
reactSwitch.measure(spec, spec);
mWidth = reactSwitch.getMeasuredWidth();
@@ -134,6 +109,11 @@
return view;
}
+ @ReactProp(name = "disabled", defaultBoolean = false)
+ public void setDisabled(ReactSwitch view, boolean disabled) {
+ view.setEnabled(!disabled);
+ }
+
@ReactProp(name = ViewProps.ENABLED, defaultBoolean = true)
public void setEnabled(ReactSwitch view, boolean enabled) {
view.setEnabled(enabled);
@@ -141,29 +121,41 @@
@ReactProp(name = ViewProps.ON)
public void setOn(ReactSwitch view, boolean on) {
+ this.setValue(view, on);
+ }
+
+ @ReactProp(name = "value")
+ public void setValue(ReactSwitch view, boolean value) {
// we set the checked change listener to null and then restore it so that we don't fire an
// onChange event to JS when JS itself is updating the value of the switch
view.setOnCheckedChangeListener(null);
- view.setOn(on);
+ view.setOn(value);
view.setOnCheckedChangeListener(ON_CHECKED_CHANGE_LISTENER);
}
@ReactProp(name = "thumbTintColor", customType = "Color")
- public void setThumbTintColor(ReactSwitch view, Integer color) {
- if (color == null) {
- view.getThumbDrawable().clearColorFilter();
- } else {
- view.getThumbDrawable().setColorFilter(color, PorterDuff.Mode.MULTIPLY);
+ public void setThumbTintColor(ReactSwitch view, @Nullable Integer color) {
+ this.setThumbColor(view, color);
+ }
+
+ @ReactProp(name = "thumbColor", customType = "Color")
+ public void setThumbColor(ReactSwitch view, @Nullable Integer color) {
+ view.setThumbColor(color);
}
+
+ @ReactProp(name = "trackColorForFalse", customType = "Color")
+ public void setTrackColorForFalse(ReactSwitch view, @Nullable Integer color) {
+ view.setTrackColorForFalse(color);
}
- @ReactProp(name = "trackTintColor", customType = "Color")
- public void setTrackTintColor(ReactSwitch view, Integer color) {
- if (color == null) {
- view.getTrackDrawable().clearColorFilter();
- } else {
- view.getTrackDrawable().setColorFilter(color, PorterDuff.Mode.MULTIPLY);
+ @ReactProp(name = "trackColorForTrue", customType = "Color")
+ public void setTrackColorForTrue(ReactSwitch view, @Nullable Integer color) {
+ view.setTrackColorForTrue(color);
}
+
+ @ReactProp(name = "trackTintColor", customType = "Color")
+ public void setTrackTintColor(ReactSwitch view, @Nullable Integer color) {
+ view.setTrackColor(color);
}
@Override

ReactAndroid/src/main/java/com/facebook/react/views/text/BUCK

@@ -9,6 +9,9 @@
],
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"),
react_native_target("java/com/facebook/react/bridge:bridge"),

ReactAndroid/src/main/java/com/facebook/react/views/text/CustomLetterSpacingSpan.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -23,7 +23,7 @@
* spans affecting font size.
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
-public class CustomLetterSpacingSpan extends MetricAffectingSpan {
+public class CustomLetterSpacingSpan extends MetricAffectingSpan implements ReactSpan {
private final float mLetterSpacing;
@@ -42,10 +42,8 @@
}
private void apply(TextPaint paint) {
- // mLetterSpacing and paint.getTextSize() are both in pixels,
- // yielding an accurate em value.
if (!Float.isNaN(mLetterSpacing)) {
- paint.setLetterSpacing(mLetterSpacing / paint.getTextSize());
+ paint.setLetterSpacing(mLetterSpacing);
}
}
}

ReactAndroid/src/main/java/com/facebook/react/views/text/CustomLineHeightSpan.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -14,7 +14,7 @@
* We use a custom {@link LineHeightSpan}, because `lineSpacingExtra` is broken. Details here:
* https://github.com/facebook/react-native/issues/7546
*/
-public class CustomLineHeightSpan implements LineHeightSpan {
+public class CustomLineHeightSpan implements LineHeightSpan, ReactSpan {
private final int mHeight;
CustomLineHeightSpan(float height) {

ReactAndroid/src/main/java/com/facebook/react/views/text/CustomStyleSpan.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -15,7 +15,7 @@
import android.text.TextPaint;
import android.text.style.MetricAffectingSpan;
-public class CustomStyleSpan extends MetricAffectingSpan {
+public class CustomStyleSpan extends MetricAffectingSpan implements ReactSpan {
/**
* A {@link MetricAffectingSpan} that allows to change the style of the displayed font.

ReactAndroid/src/main/java/com/facebook/react/views/text/CustomTextTransformSpan.java

@@ -1,83 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-package com.facebook.react.views.text;
-
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.text.style.ReplacementSpan;
-import java.text.BreakIterator;
-
-public class CustomTextTransformSpan extends ReplacementSpan {
-
- /**
- * A {@link ReplacementSpan} that allows declarative changing of text casing.
- * CustomTextTransformSpan will change e.g. "foo" to "FOO", when passed UPPERCASE.
- *
- * This needs to be a Span in order to achieve correctly nested transforms
- * (for Text nodes within Text nodes, each with separate needed transforms)
- */
-
- private final TextTransform mTransform;
-
- public CustomTextTransformSpan(TextTransform transform) {
- mTransform = transform;
- }
-
- @Override
- public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
- CharSequence transformedText = transformText(text);
- canvas.drawText(transformedText, start, end, x, y, paint);
- }
-
- @Override
- public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
- CharSequence transformedText = transformText(text);
- return Math.round(paint.measureText(transformedText, start, end));
- }
-
- private CharSequence transformText(CharSequence text) {
- CharSequence transformed;
-
- switch(mTransform) {
- case UPPERCASE:
- transformed = (CharSequence) text.toString().toUpperCase();
- break;
- case LOWERCASE:
- transformed = (CharSequence) text.toString().toLowerCase();
- break;
- case CAPITALIZE:
- transformed = (CharSequence) capitalize(text.toString());
- break;
- default:
- transformed = text;
- }
-
- return transformed;
- }
-
- private String capitalize(String text) {
- BreakIterator wordIterator = BreakIterator.getWordInstance();
- wordIterator.setText(text);
-
- StringBuilder res = new StringBuilder(text.length());
- int start = wordIterator.first();
- for (int end = wordIterator.next(); end != BreakIterator.DONE; end = wordIterator.next()) {
- String word = text.substring(start, end);
- if (Character.isLetterOrDigit(word.charAt(0))) {
- res.append(Character.toUpperCase(word.charAt(0)));
- res.append(word.substring(1).toLowerCase());
- } else {
- res.append(word);
- }
- start = end;
- }
-
- return res.toString();
- }
-
-}

ReactAndroid/src/main/java/com/facebook/react/views/text/DefaultStyleValuesUtil.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageShadowNode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -50,22 +50,6 @@
mCallerContext = callerContext;
}
- private FrescoBasedReactTextInlineImageShadowNode(FrescoBasedReactTextInlineImageShadowNode node) {
- super(node);
- mHeaders = node.mHeaders; // mHeaders is immutable
- mWidth = node.mWidth;
- mHeight = node.mHeight;
- mTintColor = node.mTintColor;
- mDraweeControllerBuilder = node.mDraweeControllerBuilder;
- mCallerContext = node.mCallerContext;
- mUri = node.mUri;
- }
-
- @Override
- protected FrescoBasedReactTextInlineImageShadowNode copy() {
- return new FrescoBasedReactTextInlineImageShadowNode(this);
- }
-
@ReactProp(name = "src")
public void setSource(@Nullable ReadableArray sources) {
final String source =

ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageSpan.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageViewManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -25,7 +25,7 @@
public class FrescoBasedReactTextInlineImageViewManager
extends ViewManager<View, FrescoBasedReactTextInlineImageShadowNode> {
- protected static final String REACT_CLASS = "RCTTextInlineImage";
+ public static final String REACT_CLASS = "RCTTextInlineImage";
private final @Nullable AbstractDraweeControllerBuilder mDraweeControllerBuilder;
private final @Nullable Object mCallerContext;

ReactAndroid/src/main/java/com/facebook/react/views/text/ReactAbsoluteSizeSpan.java

@@ -0,0 +1,19 @@
+/**
+ * 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.views.text;
+
+import android.text.style.AbsoluteSizeSpan;
+
+/*
+ * Wraps {@link AbsoluteSizeSpan} as a {@link ReactSpan}.
+ */
+public class ReactAbsoluteSizeSpan extends AbsoluteSizeSpan implements ReactSpan {
+ public ReactAbsoluteSizeSpan(int size) {
+ super(size);
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBackgroundColorSpan.java

@@ -0,0 +1,19 @@
+/**
+ * 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.views.text;
+
+import android.text.style.BackgroundColorSpan;
+
+/*
+ * Wraps {@link BackgroundColorSpan} as a {@link ReactSpan}.
+ */
+public class ReactBackgroundColorSpan extends BackgroundColorSpan implements ReactSpan {
+ public ReactBackgroundColorSpan(int color) {
+ super(color);
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java

@@ -1,22 +1,18 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.views.text;
+import android.annotation.TargetApi;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Build;
import android.text.Layout;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
-import android.text.style.AbsoluteSizeSpan;
-import android.text.style.BackgroundColorSpan;
-import android.text.style.ForegroundColorSpan;
-import android.text.style.StrikethroughSpan;
-import android.text.style.UnderlineSpan;
import android.view.Gravity;
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
import com.facebook.react.bridge.ReadableMap;
@@ -24,7 +20,6 @@
import com.facebook.react.uimanager.LayoutShadowNode;
import com.facebook.react.uimanager.PixelUtil;
import com.facebook.react.uimanager.ReactShadowNode;
-import com.facebook.react.uimanager.ViewDefaults;
import com.facebook.react.uimanager.ViewProps;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.yoga.YogaDirection;
@@ -42,6 +38,7 @@
* <p>This also node calculates {@link Spannable} object based on subnodes of the same type, which
* can be used in concrete classes to feed native views and compute layout.
*/
+@TargetApi(Build.VERSION_CODES.M)
public abstract class ReactBaseTextShadowNode extends LayoutShadowNode {
private static final String INLINE_IMAGE_PLACEHOLDER = "I";
@@ -59,9 +56,9 @@
private static class SetSpanOperation {
protected int start, end;
- protected Object what;
+ protected ReactSpan what;
- SetSpanOperation(int start, int end, Object what) {
+ SetSpanOperation(int start, int end, ReactSpan what) {
this.start = start;
this.end = end;
this.what = what;
@@ -85,17 +82,27 @@
private static void buildSpannedFromShadowNode(
ReactBaseTextShadowNode textShadowNode,
SpannableStringBuilder sb,
- List<SetSpanOperation> ops) {
-
- int start = sb.length();
+ List<SetSpanOperation> ops,
+ TextAttributes parentTextAttributes,
+ int start) {
+
+ TextAttributes textAttributes;
+ if (parentTextAttributes != null) {
+ textAttributes = parentTextAttributes.applyChild(textShadowNode.mTextAttributes);
+ } else {
+ textAttributes = textShadowNode.mTextAttributes;
+ }
for (int i = 0, length = textShadowNode.getChildCount(); i < length; i++) {
ReactShadowNode child = textShadowNode.getChildAt(i);
if (child instanceof ReactRawTextShadowNode) {
- sb.append(((ReactRawTextShadowNode) child).getText());
+ sb.append(
+ TextTransform.apply(
+ ((ReactRawTextShadowNode) child).getText(),
+ textAttributes.getTextTransform()));
} else if (child instanceof ReactBaseTextShadowNode) {
- buildSpannedFromShadowNode((ReactBaseTextShadowNode) child, sb, ops);
+ buildSpannedFromShadowNode((ReactBaseTextShadowNode) child, sb, ops, textAttributes, sb.length());
} else if (child instanceof ReactTextInlineImageShadowNode) {
// We make the image take up 1 character in the span and put a corresponding character into
// the text so that the image doesn't run over any following text.
@@ -114,23 +121,28 @@
int end = sb.length();
if (end >= start) {
if (textShadowNode.mIsColorSet) {
- ops.add(new SetSpanOperation(start, end, new ForegroundColorSpan(textShadowNode.mColor)));
+ ops.add(new SetSpanOperation(start, end, new ReactForegroundColorSpan(textShadowNode.mColor)));
}
if (textShadowNode.mIsBackgroundColorSet) {
ops.add(
new SetSpanOperation(
- start, end, new BackgroundColorSpan(textShadowNode.mBackgroundColor)));
+ start, end, new ReactBackgroundColorSpan(textShadowNode.mBackgroundColor)));
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- if (!Float.isNaN(textShadowNode.mLetterSpacing)) {
+ float effectiveLetterSpacing = textAttributes.getEffectiveLetterSpacing();
+ if (!Float.isNaN(effectiveLetterSpacing)
+ && (parentTextAttributes == null || parentTextAttributes.getEffectiveLetterSpacing() != effectiveLetterSpacing)) {
ops.add(new SetSpanOperation(
start,
end,
- new CustomLetterSpacingSpan(textShadowNode.mLetterSpacing)));
+ new CustomLetterSpacingSpan(effectiveLetterSpacing)));
}
}
- if (textShadowNode.mFontSize != UNSET) {
- ops.add(new SetSpanOperation(start, end, new AbsoluteSizeSpan(textShadowNode.mFontSize)));
+ int effectiveFontSize = textAttributes.getEffectiveFontSize();
+ if (// `getEffectiveFontSize` always returns a value so don't need to check for anything like
+ // `Float.NaN`.
+ parentTextAttributes == null || parentTextAttributes.getEffectiveFontSize() != effectiveFontSize) {
+ ops.add(new SetSpanOperation(start, end, new ReactAbsoluteSizeSpan(effectiveFontSize)));
}
if (textShadowNode.mFontStyle != UNSET
|| textShadowNode.mFontWeight != UNSET
@@ -146,10 +158,10 @@
textShadowNode.getThemedContext().getAssets())));
}
if (textShadowNode.mIsUnderlineTextDecorationSet) {
- ops.add(new SetSpanOperation(start, end, new UnderlineSpan()));
+ ops.add(new SetSpanOperation(start, end, new ReactUnderlineSpan()));
}
if (textShadowNode.mIsLineThroughTextDecorationSet) {
- ops.add(new SetSpanOperation(start, end, new StrikethroughSpan()));
+ ops.add(new SetSpanOperation(start, end, new ReactStrikethroughSpan()));
}
if (
(
@@ -169,27 +181,17 @@
textShadowNode.mTextShadowRadius,
textShadowNode.mTextShadowColor)));
}
- if (!Float.isNaN(textShadowNode.getEffectiveLineHeight())) {
+ float effectiveLineHeight = textAttributes.getEffectiveLineHeight();
+ if (!Float.isNaN(effectiveLineHeight)
+ && (parentTextAttributes == null || parentTextAttributes.getEffectiveLineHeight() != effectiveLineHeight)) {
ops.add(
new SetSpanOperation(
- start, end, new CustomLineHeightSpan(textShadowNode.getEffectiveLineHeight())));
- }
- if (textShadowNode.mTextTransform != TextTransform.UNSET) {
- ops.add(
- new SetSpanOperation(
- start,
- end,
- new CustomTextTransformSpan(textShadowNode.mTextTransform)));
+ start, end, new CustomLineHeightSpan(effectiveLineHeight)));
}
ops.add(new SetSpanOperation(start, end, new ReactTagSpan(textShadowNode.getReactTag())));
}
}
- protected int getDefaultFontSize() {
- return mAllowFontScaling ? (int) Math.ceil(PixelUtil.toPixelFromSP(ViewDefaults.FONT_SIZE_SP))
- : (int) Math.ceil(PixelUtil.toPixelFromDIP(ViewDefaults.FONT_SIZE_SP));
- }
-
protected static Spannable spannedFromShadowNode(
ReactBaseTextShadowNode textShadowNode, String text) {
SpannableStringBuilder sb = new SpannableStringBuilder();
@@ -201,20 +203,16 @@
// a new spannable will be wiped out
List<SetSpanOperation> ops = new ArrayList<>();
- buildSpannedFromShadowNode(textShadowNode, sb, ops);
-
if (text != null) {
- sb.append(text);
+ // Handle text that is provided via a prop (e.g. the `value` and `defaultValue` props on
+ // TextInput).
+ sb.append(TextTransform.apply(text, textShadowNode.mTextAttributes.getTextTransform()));
}
- if (textShadowNode.mFontSize == UNSET) {
- int defaultFontSize = textShadowNode.getDefaultFontSize();
-
- ops.add(new SetSpanOperation(0, sb.length(), new AbsoluteSizeSpan(defaultFontSize)));
- }
+ buildSpannedFromShadowNode(textShadowNode, sb, ops, null, 0);
textShadowNode.mContainsImages = false;
- textShadowNode.mHeightOfTallestInlineImage = Float.NaN;
+ float heightOfTallestInlineImage = Float.NaN;
// While setting the Spans on the final text, we also check whether any of them are images.
int priority = 0;
@@ -222,9 +220,9 @@
if (op.what instanceof TextInlineImageSpan) {
int height = ((TextInlineImageSpan) op.what).getHeight();
textShadowNode.mContainsImages = true;
- if (Float.isNaN(textShadowNode.mHeightOfTallestInlineImage)
- || height > textShadowNode.mHeightOfTallestInlineImage) {
- textShadowNode.mHeightOfTallestInlineImage = height;
+ if (Float.isNaN(heightOfTallestInlineImage)
+ || height > heightOfTallestInlineImage) {
+ heightOfTallestInlineImage = height;
}
}
@@ -234,6 +232,8 @@
priority++;
}
+ textShadowNode.mTextAttributes.setHeightOfTallestInlineImage(heightOfTallestInlineImage);
+
return sb;
}
@@ -254,22 +254,19 @@
: -1;
}
- protected float mLineHeight = Float.NaN;
- protected float mLetterSpacing = Float.NaN;
+ protected TextAttributes mTextAttributes;
+
protected boolean mIsColorSet = false;
- protected boolean mAllowFontScaling = true;
protected int mColor;
protected boolean mIsBackgroundColorSet = false;
protected int mBackgroundColor;
protected int mNumberOfLines = UNSET;
- protected int mFontSize = UNSET;
- protected float mFontSizeInput = UNSET;
- protected float mLineHeightInput = UNSET;
- protected float mLetterSpacingInput = Float.NaN;
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;
@@ -310,58 +307,18 @@
protected boolean mContainsImages = false;
protected float mHeightOfTallestInlineImage = Float.NaN;
- public ReactBaseTextShadowNode() {}
-
- public ReactBaseTextShadowNode(ReactBaseTextShadowNode node) {
- super(node);
- mLineHeight = node.mLineHeight;
- mIsColorSet = node.mIsColorSet;
- mAllowFontScaling = node.mAllowFontScaling;
- mColor = node.mColor;
- mIsBackgroundColorSet = node.mIsBackgroundColorSet;
- mBackgroundColor = node.mBackgroundColor;
-
- mNumberOfLines = node.mNumberOfLines;
- mFontSize = node.mFontSize;
- mFontSizeInput = node.mFontSizeInput;
- mLineHeightInput = node.mLineHeightInput;
- mTextAlign = node.mTextAlign;
- mTextBreakStrategy = node.mTextBreakStrategy;
- mTextTransform = node.mTextTransform;
-
- mTextShadowOffsetDx = node.mTextShadowOffsetDx;
- mTextShadowOffsetDy = node.mTextShadowOffsetDy;
- mTextShadowRadius = node.mTextShadowRadius;
- mTextShadowColor = node.mTextShadowColor;
-
- mIsUnderlineTextDecorationSet = node.mIsUnderlineTextDecorationSet;
- mIsLineThroughTextDecorationSet = node.mIsLineThroughTextDecorationSet;
- mIncludeFontPadding = node.mIncludeFontPadding;
- mFontStyle = node.mFontStyle;
- mFontWeight = node.mFontWeight;
- mFontFamily = node.mFontFamily;
- mContainsImages = node.mContainsImages;
- mHeightOfTallestInlineImage = node.mHeightOfTallestInlineImage;
- }
-
- // Returns a line height which takes into account the requested line height
- // and the height of the inline images.
- public float getEffectiveLineHeight() {
- boolean useInlineViewHeight =
- !Float.isNaN(mLineHeight)
- && !Float.isNaN(mHeightOfTallestInlineImage)
- && mHeightOfTallestInlineImage > mLineHeight;
- return useInlineViewHeight ? mHeightOfTallestInlineImage : mLineHeight;
+ public ReactBaseTextShadowNode() {
+ mTextAttributes = new TextAttributes();
}
// Return text alignment according to LTR or RTL style
private int getTextAlign() {
int textAlign = mTextAlign;
if (getLayoutDirection() == YogaDirection.RTL) {
- if (textAlign == Gravity.RIGHT) {
- textAlign = Gravity.LEFT;
- } else if (textAlign == Gravity.LEFT) {
- textAlign = Gravity.RIGHT;
+ if (textAlign == Gravity.END) {
+ textAlign = Gravity.START;
+ } else if (textAlign == Gravity.START) {
+ textAlign = Gravity.END;
}
}
return textAlign;
@@ -373,69 +330,65 @@
markUpdated();
}
- @ReactProp(name = ViewProps.LINE_HEIGHT, defaultFloat = UNSET)
+ @ReactProp(name = ViewProps.LINE_HEIGHT, defaultFloat = Float.NaN)
public void setLineHeight(float lineHeight) {
- mLineHeightInput = lineHeight;
- if (lineHeight == UNSET) {
- mLineHeight = Float.NaN;
- } else {
- mLineHeight =
- mAllowFontScaling
- ? PixelUtil.toPixelFromSP(lineHeight)
- : PixelUtil.toPixelFromDIP(lineHeight);
- }
+ mTextAttributes.setLineHeight(lineHeight);
markUpdated();
}
@ReactProp(name = ViewProps.LETTER_SPACING, defaultFloat = Float.NaN)
public void setLetterSpacing(float letterSpacing) {
- mLetterSpacingInput = letterSpacing;
- mLetterSpacing = mAllowFontScaling
- ? PixelUtil.toPixelFromSP(mLetterSpacingInput)
- : PixelUtil.toPixelFromDIP(mLetterSpacingInput);
+ mTextAttributes.setLetterSpacing(letterSpacing);
markUpdated();
}
@ReactProp(name = ViewProps.ALLOW_FONT_SCALING, defaultBoolean = true)
public void setAllowFontScaling(boolean allowFontScaling) {
- if (allowFontScaling != mAllowFontScaling) {
- mAllowFontScaling = allowFontScaling;
- setFontSize(mFontSizeInput);
- setLineHeight(mLineHeightInput);
- setLetterSpacing(mLetterSpacingInput);
+ if (allowFontScaling != mTextAttributes.getAllowFontScaling()) {
+ mTextAttributes.setAllowFontScaling(allowFontScaling);
+ markUpdated();
+ }
+ }
+
+ @ReactProp(name = ViewProps.MAX_FONT_SIZE_MULTIPLIER, defaultFloat = Float.NaN)
+ public void setMaxFontSizeMultiplier(float maxFontSizeMultiplier) {
+ if (maxFontSizeMultiplier != mTextAttributes.getMaxFontSizeMultiplier()) {
+ mTextAttributes.setMaxFontSizeMultiplier(maxFontSizeMultiplier);
markUpdated();
}
}
@ReactProp(name = ViewProps.TEXT_ALIGN)
public void setTextAlign(@Nullable String textAlign) {
+ if ("justify".equals(textAlign)) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ mJustificationMode = Layout.JUSTIFICATION_MODE_INTER_WORD;
+ }
+ mTextAlign = Gravity.START;
+ } else {
+ 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;
+ mTextAlign = Gravity.START;
} else if ("right".equals(textAlign)) {
- mTextAlign = Gravity.RIGHT;
+ mTextAlign = Gravity.END;
} else if ("center".equals(textAlign)) {
mTextAlign = Gravity.CENTER_HORIZONTAL;
- } else if ("justify".equals(textAlign)) {
- // Fallback gracefully for cross-platform compat instead of error
- mTextAlign = Gravity.LEFT;
} else {
throw new JSApplicationIllegalArgumentException("Invalid textAlign: " + textAlign);
}
+
+ }
markUpdated();
}
- @ReactProp(name = ViewProps.FONT_SIZE, defaultFloat = UNSET)
+ @ReactProp(name = ViewProps.FONT_SIZE, defaultFloat = Float.NaN)
public void setFontSize(float fontSize) {
- mFontSizeInput = fontSize;
- if (fontSize != UNSET) {
- fontSize =
- mAllowFontScaling
- ? (float) Math.ceil(PixelUtil.toPixelFromSP(fontSize))
- : (float) Math.ceil(PixelUtil.toPixelFromDIP(fontSize));
- }
- mFontSize = (int) fontSize;
+ mTextAttributes.setFontSize(fontSize);
markUpdated();
}
@@ -585,14 +538,16 @@
@ReactProp(name = PROP_TEXT_TRANSFORM)
public void setTextTransform(@Nullable String textTransform) {
- if (textTransform == null || "none".equals(textTransform)) {
- mTextTransform = TextTransform.NONE;
+ if (textTransform == null) {
+ mTextAttributes.setTextTransform(TextTransform.UNSET);
+ } else if ("none".equals(textTransform)) {
+ mTextAttributes.setTextTransform(TextTransform.NONE);
} else if ("uppercase".equals(textTransform)) {
- mTextTransform = TextTransform.UPPERCASE;
+ mTextAttributes.setTextTransform(TextTransform.UPPERCASE);
} else if ("lowercase".equals(textTransform)) {
- mTextTransform = TextTransform.LOWERCASE;
+ mTextAttributes.setTextTransform(TextTransform.LOWERCASE);
} else if ("capitalize".equals(textTransform)) {
- mTextTransform = TextTransform.CAPITALIZE;
+ mTextAttributes.setTextTransform(TextTransform.CAPITALIZE);
} else {
throw new JSApplicationIllegalArgumentException("Invalid textTransform: " + textTransform);
}

ReactAndroid/src/main/java/com/facebook/react/views/text/ReactFontManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/text/ReactForegroundColorSpan.java

@@ -0,0 +1,19 @@
+/**
+ * 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.views.text;
+
+import android.text.style.ForegroundColorSpan;
+
+/*
+ * Wraps {@link ForegroundColorSpan} as a {@link ReactSpan}.
+ */
+public class ReactForegroundColorSpan extends ForegroundColorSpan implements ReactSpan {
+ public ReactForegroundColorSpan(int color) {
+ super(color);
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/views/text/ReactRawTextManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/text/ReactRawTextShadowNode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -24,16 +24,6 @@
public ReactRawTextShadowNode() { }
- private ReactRawTextShadowNode(ReactRawTextShadowNode node) {
- super(node);
- this.mText = node.mText;
- }
-
- @Override
- protected ReactShadowNodeImpl copy() {
- return new ReactRawTextShadowNode(this);
- }
-
@ReactProp(name = PROP_TEXT)
public void setText(@Nullable String text) {
mText = text;

ReactAndroid/src/main/java/com/facebook/react/views/text/ReactSpan.java

@@ -0,0 +1,15 @@
+/**
+ * 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.views.text;
+
+/*
+ * Enables us to distinguish between spans that were added by React Native and spans that were
+ * added by something else. All spans that React Native adds should implement this interface.
+ */
+public interface ReactSpan {
+}

ReactAndroid/src/main/java/com/facebook/react/views/text/ReactStrikethroughSpan.java

@@ -0,0 +1,16 @@
+/**
+ * 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.views.text;
+
+import android.text.style.StrikethroughSpan;
+
+/*
+ * Wraps {@link StrikethroughSpan} as a {@link ReactSpan}.
+ */
+public class ReactStrikethroughSpan extends StrikethroughSpan implements ReactSpan {
+}

ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTagSpan.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,7 +11,7 @@
* Instances of this class are used to place reactTag information of nested text react nodes
* into spannable text rendered by single {@link TextView}
*/
-public class ReactTagSpan {
+public class ReactTagSpan implements ReactSpan {
private final int mReactTag;

ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextAnchorViewManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextInlineImageShadowNode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -23,8 +23,4 @@
public ReactTextInlineImageShadowNode() {}
- protected ReactTextInlineImageShadowNode(ReactTextInlineImageShadowNode node) {
- super(node);
- }
-
}

ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java

@@ -1,13 +1,12 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
+ * <p>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.views.text;
-import android.graphics.Rect;
+import android.annotation.TargetApi;
import android.os.Build;
import android.text.BoringLayout;
import android.text.Layout;
@@ -15,15 +14,12 @@
import android.text.Spanned;
import android.text.StaticLayout;
import android.text.TextPaint;
-import android.util.DisplayMetrics;
import android.view.Gravity;
import android.widget.TextView;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
-import com.facebook.react.uimanager.LayoutShadowNode;
-import com.facebook.react.uimanager.ReactShadowNodeImpl;
import com.facebook.react.uimanager.Spacing;
import com.facebook.react.uimanager.UIViewOperationQueue;
import com.facebook.react.uimanager.annotations.ReactProp;
@@ -42,6 +38,7 @@
* <p>The class measures text in {@code <Text>} view and feeds native {@link TextView} using {@code
* Spannable} object constructed in superclass.
*/
+@TargetApi(Build.VERSION_CODES.M)
public class ReactTextShadowNode extends ReactBaseTextShadowNode {
// It's important to pass the ANTI_ALIAS_FLAG flag to the constructor rather than setting it
@@ -62,26 +59,27 @@
YogaMeasureMode widthMode,
float height,
YogaMeasureMode heightMode) {
+
// TODO(5578671): Handle text direction (see View#getTextDirectionHeuristic)
TextPaint textPaint = sTextPaintInstance;
- textPaint.setTextSize(mFontSize != UNSET ? mFontSize : getDefaultFontSize());
+ textPaint.setTextSize(mTextAttributes.getEffectiveFontSize());
Layout layout;
- Spanned text = Assertions.assertNotNull(
+ Spanned text =
+ Assertions.assertNotNull(
mPreparedSpannableText,
"Spannable element has not been prepared in onBeforeLayout");
BoringLayout.Metrics boring = BoringLayout.isBoring(text, textPaint);
- float desiredWidth = boring == null ?
- Layout.getDesiredWidth(text, textPaint) : Float.NaN;
+ float desiredWidth = boring == null ? Layout.getDesiredWidth(text, textPaint) : Float.NaN;
// technically, width should never be negative, but there is currently a bug in
boolean unconstrainedWidth = widthMode == YogaMeasureMode.UNDEFINED || width < 0;
Layout.Alignment alignment = Layout.Alignment.ALIGN_NORMAL;
switch (getTextAlign()) {
- case Gravity.LEFT:
+ case Gravity.START:
alignment = Layout.Alignment.ALIGN_NORMAL;
break;
- case Gravity.RIGHT:
+ case Gravity.END:
alignment = Layout.Alignment.ALIGN_OPPOSITE;
break;
case Gravity.CENTER_HORIZONTAL:
@@ -89,36 +87,37 @@
break;
}
- if (boring == null &&
- (unconstrainedWidth ||
- (!YogaConstants.isUndefined(desiredWidth) && desiredWidth <= width))) {
+ if (boring == null
+ && (unconstrainedWidth
+ || (!YogaConstants.isUndefined(desiredWidth) && desiredWidth <= width))) {
// Is used when the width is not known and the text is not boring, ie. if it contains
// unicode characters.
int hintWidth = (int) Math.ceil(desiredWidth);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
- layout = new StaticLayout(
- text,
- textPaint,
- hintWidth,
- alignment,
- 1.f,
- 0.f,
- mIncludeFontPadding);
+ layout =
+ new StaticLayout(
+ text, textPaint, hintWidth, alignment, 1.f, 0.f, mIncludeFontPadding);
} else {
- layout = StaticLayout.Builder.obtain(text, 0, text.length(), textPaint, hintWidth)
+ 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();
+ .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)) {
// Is used for single-line, boring text when the width is either unknown or bigger
// than the width of the text.
- layout = BoringLayout.make(
+ layout =
+ BoringLayout.make(
text,
textPaint,
boring.width,
@@ -131,16 +130,12 @@
// Is used for multiline, boring text and the width is known.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
- layout = new StaticLayout(
- text,
- textPaint,
- (int) width,
- alignment,
- 1.f,
- 0.f,
- mIncludeFontPadding);
+ layout =
+ new StaticLayout(
+ text, textPaint, (int) width, alignment, 1.f, 0.f, mIncludeFontPadding);
} else {
- layout = StaticLayout.Builder.obtain(text, 0, text.length(), textPaint, (int) width)
+ layout =
+ StaticLayout.Builder.obtain(text, 0, text.length(), textPaint, (int) width)
.setAlignment(alignment)
.setLineSpacing(0.f, 1.f)
.setIncludePad(mIncludeFontPadding)
@@ -152,7 +147,8 @@
if (mShouldNotifyOnTextLayout) {
WritableArray lines =
- FontMetricsUtil.getFontMetrics(text, layout, sTextPaintInstance, getThemedContext());
+ FontMetricsUtil.getFontMetrics(
+ text, layout, sTextPaintInstance, getThemedContext());
WritableMap event = Arguments.createMap();
event.putArray("lines", lines);
getThemedContext()
@@ -161,7 +157,8 @@
}
if (mNumberOfLines != UNSET && mNumberOfLines < layout.getLineCount()) {
- return YogaMeasureOutput.make(layout.getWidth(), layout.getLineBottom(mNumberOfLines - 1));
+ return YogaMeasureOutput.make(
+ layout.getWidth(), layout.getLineBottom(mNumberOfLines - 1));
} else {
return YogaMeasureOutput.make(layout.getWidth(), layout.getHeight());
}
@@ -172,44 +169,20 @@
initMeasureFunction();
}
- private ReactTextShadowNode(ReactTextShadowNode node) {
- super(node);
- this.mPreparedSpannableText = node.mPreparedSpannableText;
- }
-
private void initMeasureFunction() {
if (!isVirtual()) {
setMeasureFunction(mTextMeasureFunction);
}
}
- @Override
- protected LayoutShadowNode copy() {
- return new ReactTextShadowNode(this);
- }
-
- @Override
- public ReactShadowNodeImpl mutableCopy(long instanceHandle) {
- ReactTextShadowNode copy = (ReactTextShadowNode) super.mutableCopy(instanceHandle);
- copy.initMeasureFunction();
- return copy;
- }
-
- @Override
- public ReactShadowNodeImpl mutableCopyWithNewChildren(long instanceHandle) {
- ReactTextShadowNode copy = (ReactTextShadowNode) super.mutableCopyWithNewChildren(instanceHandle);
- copy.initMeasureFunction();
- return copy;
- }
-
// Return text alignment according to LTR or RTL style
private int getTextAlign() {
int textAlign = mTextAlign;
if (getLayoutDirection() == YogaDirection.RTL) {
- if (textAlign == Gravity.RIGHT) {
- textAlign = Gravity.LEFT;
- } else if (textAlign == Gravity.LEFT) {
- textAlign = Gravity.RIGHT;
+ if (textAlign == Gravity.END) {
+ textAlign = Gravity.START;
+ } else if (textAlign == Gravity.START) {
+ textAlign = Gravity.END;
}
}
return textAlign;
@@ -248,8 +221,8 @@
getPadding(Spacing.END),
getPadding(Spacing.BOTTOM),
getTextAlign(),
- mTextBreakStrategy
- );
+ mTextBreakStrategy,
+ mJustificationMode);
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
}
}

ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextUpdate.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -26,6 +26,7 @@
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 @@
paddingEnd,
paddingBottom,
textAlign,
- Layout.BREAK_STRATEGY_HIGH_QUALITY);
+ Layout.BREAK_STRATEGY_HIGH_QUALITY,
+ Layout.JUSTIFICATION_MODE_NONE);
}
public ReactTextUpdate(
@@ -61,7 +63,8 @@
float paddingEnd,
float paddingBottom,
int textAlign,
- int textBreakStrategy) {
+ int textBreakStrategy,
+ int justificationMode) {
mText = text;
mJsEventCounter = jsEventCounter;
mContainsImages = containsImages;
@@ -71,6 +74,7 @@
mPaddingBottom = paddingBottom;
mTextAlign = textAlign;
mTextBreakStrategy = textBreakStrategy;
+ mJustificationMode = justificationMode;
}
public Spannable getText() {
@@ -108,4 +112,8 @@
public int getTextBreakStrategy() {
return mTextBreakStrategy;
}
+
+ public int getJustificationMode() {
+ return mJustificationMode;
+ }
}

ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,18 +10,21 @@
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;
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);
@@ -29,13 +32,12 @@
private boolean mContainsImages;
private int mDefaultGravityHorizontal;
private int mDefaultGravityVertical;
- private boolean mTextIsSelectable;
- private float mLineHeight = Float.NaN;
private int mTextAlign = Gravity.NO_GRAVITY;
private int mNumberOfLines = ViewDefaults.NUMBER_OF_LINES;
private TextUtils.TruncateAt mEllipsizeLocation = TextUtils.TruncateAt.END;
private ReactViewBackgroundManager mReactBackgroundManager;
+ private Spannable mSpanned;
public ReactTextView(Context context) {
super(context);
@@ -70,6 +72,11 @@
setBreakStrategy(update.getTextBreakStrategy());
}
}
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ if (getJustificationMode() != update.getJustificationMode()) {
+ setJustificationMode(update.getJustificationMode());
+ }
+ }
}
@Override
@@ -94,7 +101,14 @@
// TODO(5966918): Consider extending touchable area for text spans by some DP constant
if (text instanceof Spanned && x >= lineStartX && x <= lineEndX) {
Spanned spannedText = (Spanned) text;
- int index = layout.getOffsetForHorizontal(line, x);
+ int index = -1;
+ try {
+ index = layout.getOffsetForHorizontal(line, x);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // https://issuetracker.google.com/issues/113348914
+ FLog.e(ReactConstants.TAG, "Crash in HorizontalMeasurementProvider: " + e.getMessage());
+ return target;
+ }
// We choose the most inner span (shortest) containing character at the given index
// if no such span can be found we will send the textview's react id as a touch handler
@@ -119,12 +133,6 @@
}
@Override
- public void setTextIsSelectable(boolean selectable) {
- mTextIsSelectable = selectable;
- super.setTextIsSelectable(selectable);
- }
-
- @Override
protected boolean verifyDrawable(Drawable drawable) {
if (mContainsImages && getText() instanceof Spanned) {
Spanned text = (Spanned) getText();
@@ -200,6 +208,11 @@
}
}
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+
/* package */ void setGravityHorizontal(int gravityHorizontal) {
if (gravityHorizontal == 0) {
gravityHorizontal = mDefaultGravityHorizontal;
@@ -255,4 +268,12 @@
public void setBorderStyle(@Nullable String style) {
mReactBackgroundManager.setBorderStyle(style);
}
+
+ public void setSpanned(Spannable spanned) {
+ mSpanned = spanned;
+ }
+
+ public Spannable getSpanned() {
+ return mSpanned;
+ }
}

ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextViewManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,11 +7,18 @@
package com.facebook.react.views.text;
+import android.text.Layout;
import android.text.Spannable;
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.ReadableNativeMap;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.common.annotations.VisibleForTesting;
import com.facebook.react.module.annotations.ReactModule;
+import com.facebook.react.uimanager.ReactStylesDiffMap;
import com.facebook.react.uimanager.ThemedReactContext;
+import com.facebook.yoga.YogaMeasureMode;
import java.util.Map;
import javax.annotation.Nullable;
@@ -63,7 +70,55 @@
}
@Override
+ public Object updateLocalData(ReactTextView view, ReactStylesDiffMap props, ReactStylesDiffMap localData) {
+ ReadableMap attributedString = localData.getMap("attributedString");
+
+ Spannable spanned = TextLayoutManager.getOrCreateSpannableForText(view.getContext(),
+ attributedString);
+ view.setSpanned(spanned);
+
+ TextAttributeProps textViewProps = new TextAttributeProps(props);
+
+ // TODO add textBreakStrategy prop into local Data
+ int textBreakStrategy = Layout.BREAK_STRATEGY_HIGH_QUALITY;
+
+ // 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
+ textViewProps.getStartPadding(),
+ textViewProps.getTopPadding(),
+ textViewProps.getEndPadding(),
+ textViewProps.getBottomPadding(),
+ textViewProps.getTextAlign(),
+ textBreakStrategy,
+ justificationMode
+ );
+ }
+
+ @Override
public @Nullable Map getExportedCustomDirectEventTypeConstants() {
return MapBuilder.of("topTextLayout", MapBuilder.of("registrationName", "onTextLayout"));
}
+
+ public long measure(
+ ReactContext context,
+ ReadableNativeMap localData,
+ ReadableNativeMap props,
+ float width,
+ YogaMeasureMode widthMode,
+ float height,
+ YogaMeasureMode heightMode) {
+
+ return TextLayoutManager.measureText(context,
+ localData,
+ props,
+ width,
+ widthMode,
+ height,
+ heightMode);
+ }
}

ReactAndroid/src/main/java/com/facebook/react/views/text/ReactUnderlineSpan.java

@@ -0,0 +1,16 @@
+/**
+ * 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.views.text;
+
+import android.text.style.UnderlineSpan;
+
+/*
+ * Wraps {@link UnderlineSpan} as a {@link ReactSpan}.
+ */
+public class ReactUnderlineSpan extends UnderlineSpan implements ReactSpan {
+}

ReactAndroid/src/main/java/com/facebook/react/views/text/ReactVirtualTextShadowNode.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -17,12 +17,4 @@
public ReactVirtualTextShadowNode() { }
- private ReactVirtualTextShadowNode(ReactVirtualTextShadowNode node) {
- super(node);
- }
-
- @Override
- protected ReactVirtualTextShadowNode copy() {
- return new ReactVirtualTextShadowNode(this);
- }
}

ReactAndroid/src/main/java/com/facebook/react/views/text/ReactVirtualTextViewManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/text/ShadowStyleSpan.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,7 +11,7 @@
import android.text.TextPaint;
import android.text.style.CharacterStyle;
-public class ShadowStyleSpan extends CharacterStyle {
+public class ShadowStyleSpan extends CharacterStyle implements ReactSpan {
private final float mDx, mDy, mRadius;
private final int mColor;

ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.java

@@ -0,0 +1,434 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+package com.facebook.react.views.text;
+
+import android.graphics.Typeface;
+import android.os.Build;
+import android.text.Layout;
+import android.view.Gravity;
+import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.uimanager.PixelUtil;
+import com.facebook.react.uimanager.ReactStylesDiffMap;
+import com.facebook.react.uimanager.ViewProps;
+import com.facebook.yoga.YogaDirection;
+import javax.annotation.Nullable;
+
+public class TextAttributeProps {
+
+ private static final String INLINE_IMAGE_PLACEHOLDER = "I";
+ public static final int UNSET = -1;
+
+ private static final String PROP_SHADOW_OFFSET = "textShadowOffset";
+ private static final String PROP_SHADOW_OFFSET_WIDTH = "width";
+ private static final String PROP_SHADOW_OFFSET_HEIGHT = "height";
+ private static final String PROP_SHADOW_RADIUS = "textShadowRadius";
+ private static final String PROP_SHADOW_COLOR = "textShadowColor";
+
+ private static final String PROP_TEXT_TRANSFORM = "textTransform";
+
+ private static final int DEFAULT_TEXT_SHADOW_COLOR = 0x55000000;
+
+ protected float mLineHeight = Float.NaN;
+ protected float mLetterSpacing = Float.NaN;
+ protected boolean mIsColorSet = false;
+ protected boolean mAllowFontScaling = true;
+ protected int mColor;
+ protected boolean mIsBackgroundColorSet = false;
+ protected int mBackgroundColor;
+
+ protected int mNumberOfLines = UNSET;
+ protected int mFontSize = UNSET;
+ protected float mFontSizeInput = UNSET;
+ protected float mLineHeightInput = UNSET;
+ protected float mLetterSpacingInput = Float.NaN;
+ 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;
+ protected float mTextShadowRadius = 1;
+ protected int mTextShadowColor = DEFAULT_TEXT_SHADOW_COLOR;
+
+ protected boolean mIsUnderlineTextDecorationSet = false;
+ protected boolean mIsLineThroughTextDecorationSet = false;
+ protected boolean mIncludeFontPadding = true;
+
+ /**
+ * mFontStyle can be {@link Typeface#NORMAL} or {@link Typeface#ITALIC}.
+ * mFontWeight can be {@link Typeface#NORMAL} or {@link Typeface#BOLD}.
+ */
+ protected int mFontStyle = UNSET;
+
+ protected int mFontWeight = UNSET;
+ /**
+ * NB: If a font family is used that does not have a style in a certain Android version (ie.
+ * monospace bold pre Android 5.0), that style (ie. bold) will not be inherited by nested Text
+ * nodes. To retain that style, you have to add it to those nodes explicitly.
+ * Example, Android 4.4:
+ * <Text style={{fontFamily="serif" fontWeight="bold"}}>Bold Text</Text>
+ * <Text style={{fontFamily="sans-serif"}}>Bold Text</Text>
+ * <Text style={{fontFamily="serif}}>Bold Text</Text>
+ *
+ * <Text style={{fontFamily="monospace" fontWeight="bold"}}>Not Bold Text</Text>
+ * <Text style={{fontFamily="sans-serif"}}>Not Bold Text</Text>
+ * <Text style={{fontFamily="serif}}>Not Bold Text</Text>
+ *
+ * <Text style={{fontFamily="monospace" fontWeight="bold"}}>Not Bold Text</Text>
+ * <Text style={{fontFamily="sans-serif" fontWeight="bold"}}>Bold Text</Text>
+ * <Text style={{fontFamily="serif}}>Bold Text</Text>
+ */
+ protected @Nullable String mFontFamily = null;
+
+ protected boolean mContainsImages = false;
+ protected float mHeightOfTallestInlineImage = Float.NaN;
+
+ private final ReactStylesDiffMap mProps;
+
+
+ public TextAttributeProps(ReactStylesDiffMap props) {
+ mProps = props;
+ setNumberOfLines(getIntProp(ViewProps.NUMBER_OF_LINES, UNSET));
+ setLineHeight(getFloatProp(ViewProps.LINE_HEIGHT, UNSET));
+ setLetterSpacing(getFloatProp(ViewProps.LETTER_SPACING, Float.NaN));
+ setAllowFontScaling(getBooleanProp(ViewProps.ALLOW_FONT_SCALING, true));
+ setTextAlign(getStringProp(ViewProps.TEXT_ALIGN));
+ setFontSize(getFloatProp(ViewProps.FONT_SIZE, UNSET));
+ setColor(props.hasKey(ViewProps.COLOR) ? props.getInt(ViewProps.COLOR, 0) : null);
+ setColor(props.hasKey("foregroundColor") ? props.getInt("foregroundColor", 0) : null);
+ setBackgroundColor(props.hasKey(ViewProps.BACKGROUND_COLOR) ? props.getInt(ViewProps.BACKGROUND_COLOR, 0) : null);
+ setFontFamily(getStringProp(ViewProps.FONT_FAMILY));
+ setFontWeight(getStringProp(ViewProps.FONT_WEIGHT));
+ setFontStyle(getStringProp(ViewProps.FONT_STYLE));
+ setIncludeFontPadding(getBooleanProp(ViewProps.INCLUDE_FONT_PADDING, true));
+ setTextDecorationLine(getStringProp(ViewProps.TEXT_DECORATION_LINE));
+ setTextBreakStrategy(getStringProp(ViewProps.TEXT_BREAK_STRATEGY));
+ setTextShadowOffset(props.hasKey(PROP_SHADOW_OFFSET) ? props.getMap(PROP_SHADOW_OFFSET) : null);
+ setTextShadowRadius(getIntProp(PROP_SHADOW_RADIUS, 1));
+ setTextShadowColor(getIntProp(PROP_SHADOW_COLOR, DEFAULT_TEXT_SHADOW_COLOR));
+ setTextTransform(getStringProp(PROP_TEXT_TRANSFORM));
+ }
+
+ private boolean getBooleanProp(String name, boolean defaultValue) {
+ if (mProps.hasKey(name)) {
+ return mProps.getBoolean(name, defaultValue);
+ } else {
+ return defaultValue;
+ }
+ }
+
+ private String getStringProp(String name) {
+ if (mProps.hasKey(name)) {
+ return mProps.getString(name);
+ } else {
+ return null;
+ }
+ }
+
+ private int getIntProp(String name, int defaultvalue) {
+ if (mProps.hasKey(name)) {
+ return mProps.getInt(name, defaultvalue);
+ } else {
+ return defaultvalue;
+ }
+ }
+
+ private float getFloatProp(String name, float defaultvalue) {
+ if (mProps.hasKey(name)) {
+ return mProps.getFloat(name, defaultvalue);
+ } else {
+ return defaultvalue;
+ }
+ }
+
+ // Returns a line height which takes into account the requested line height
+ // and the height of the inline images.
+ public float getEffectiveLineHeight() {
+ boolean useInlineViewHeight =
+ !Float.isNaN(mLineHeight)
+ && !Float.isNaN(mHeightOfTallestInlineImage)
+ && mHeightOfTallestInlineImage > mLineHeight;
+ return useInlineViewHeight ? mHeightOfTallestInlineImage : mLineHeight;
+ }
+
+ // Return text alignment according to LTR or RTL style
+ public int getTextAlign() {
+ int textAlign = mTextAlign;
+ if (getLayoutDirection() == YogaDirection.RTL) {
+ if (textAlign == Gravity.END) {
+ textAlign = Gravity.START;
+ } else if (textAlign == Gravity.START) {
+ textAlign = Gravity.END;
+ }
+ }
+ return textAlign;
+ }
+
+ public void setNumberOfLines(int numberOfLines) {
+ mNumberOfLines = numberOfLines == 0 ? UNSET : numberOfLines;
+ }
+
+ public void setLineHeight(float lineHeight) {
+ mLineHeightInput = lineHeight;
+ if (lineHeight == UNSET) {
+ mLineHeight = Float.NaN;
+ } else {
+ mLineHeight =
+ mAllowFontScaling
+ ? PixelUtil.toPixelFromSP(lineHeight)
+ : PixelUtil.toPixelFromDIP(lineHeight);
+ }
+ }
+
+ public void setLetterSpacing(float letterSpacing) {
+ mLetterSpacingInput = letterSpacing;
+ mLetterSpacing = mAllowFontScaling
+ ? PixelUtil.toPixelFromSP(mLetterSpacingInput)
+ : PixelUtil.toPixelFromDIP(mLetterSpacingInput);
+ }
+
+ public void setAllowFontScaling(boolean allowFontScaling) {
+ if (allowFontScaling != mAllowFontScaling) {
+ mAllowFontScaling = allowFontScaling;
+ setFontSize(mFontSizeInput);
+ setLineHeight(mLineHeightInput);
+ setLetterSpacing(mLetterSpacingInput);
+ }
+ }
+
+ public void setTextAlign(@Nullable String textAlign) {
+ if ("justify".equals(textAlign)) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ mJustificationMode = Layout.JUSTIFICATION_MODE_INTER_WORD;
+ }
+ mTextAlign = Gravity.START;
+ } else {
+ 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.START;
+ } else if ("right".equals(textAlign)) {
+ mTextAlign = Gravity.END;
+ } else if ("center".equals(textAlign)) {
+ mTextAlign = Gravity.CENTER_HORIZONTAL;
+ } else {
+ throw new JSApplicationIllegalArgumentException("Invalid textAlign: " + textAlign);
+ }
+
+ }
+ }
+
+ public void setFontSize(float fontSize) {
+ mFontSizeInput = fontSize;
+ if (fontSize != UNSET) {
+ fontSize =
+ mAllowFontScaling
+ ? (float) Math.ceil(PixelUtil.toPixelFromSP(fontSize))
+ : (float) Math.ceil(PixelUtil.toPixelFromDIP(fontSize));
+ }
+ mFontSize = (int) fontSize;
+ }
+
+ public void setColor(@Nullable Integer color) {
+ mIsColorSet = (color != null);
+ if (mIsColorSet) {
+ mColor = color;
+ }
+ }
+
+ public void setBackgroundColor(Integer color) {
+ //TODO: Don't apply background color to anchor TextView since it will be applied on the View directly
+ //if (!isVirtualAnchor()) {
+ mIsBackgroundColorSet = (color != null);
+ if (mIsBackgroundColorSet) {
+ mBackgroundColor = color;
+ }
+ //}
+ }
+
+ public void setFontFamily(@Nullable String fontFamily) {
+ mFontFamily = fontFamily;
+ }
+
+ /**
+ /* This code is duplicated in ReactTextInputManager
+ /* TODO: Factor into a common place they can both use
+ */
+ public void setFontWeight(@Nullable String fontWeightString) {
+ int fontWeightNumeric =
+ fontWeightString != null ? parseNumericFontWeight(fontWeightString) : -1;
+ int fontWeight = UNSET;
+ if (fontWeightNumeric >= 500 || "bold".equals(fontWeightString)) {
+ fontWeight = Typeface.BOLD;
+ } else if ("normal".equals(fontWeightString)
+ || (fontWeightNumeric != -1 && fontWeightNumeric < 500)) {
+ fontWeight = Typeface.NORMAL;
+ }
+ if (fontWeight != mFontWeight) {
+ mFontWeight = fontWeight;
+ }
+ }
+
+ /**
+ /* This code is duplicated in ReactTextInputManager
+ /* TODO: Factor into a common place they can both use
+ */
+ public void setFontStyle(@Nullable String fontStyleString) {
+ int fontStyle = UNSET;
+ if ("italic".equals(fontStyleString)) {
+ fontStyle = Typeface.ITALIC;
+ } else if ("normal".equals(fontStyleString)) {
+ fontStyle = Typeface.NORMAL;
+ }
+ if (fontStyle != mFontStyle) {
+ mFontStyle = fontStyle;
+ }
+ }
+
+ public void setIncludeFontPadding(boolean includepad) {
+ mIncludeFontPadding = includepad;
+ }
+
+ public void setTextDecorationLine(@Nullable String textDecorationLineString) {
+ mIsUnderlineTextDecorationSet = false;
+ mIsLineThroughTextDecorationSet = false;
+ if (textDecorationLineString != null) {
+ for (String textDecorationLineSubString : textDecorationLineString.split(" ")) {
+ if ("underline".equals(textDecorationLineSubString)) {
+ mIsUnderlineTextDecorationSet = true;
+ } else if ("line-through".equals(textDecorationLineSubString)) {
+ mIsLineThroughTextDecorationSet = true;
+ }
+ }
+ }
+ }
+
+ public void setTextBreakStrategy(@Nullable String textBreakStrategy) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ return;
+ }
+
+ if (textBreakStrategy == null || "highQuality".equals(textBreakStrategy)) {
+ mTextBreakStrategy = Layout.BREAK_STRATEGY_HIGH_QUALITY;
+ } else if ("simple".equals(textBreakStrategy)) {
+ mTextBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE;
+ } else if ("balanced".equals(textBreakStrategy)) {
+ mTextBreakStrategy = Layout.BREAK_STRATEGY_BALANCED;
+ } else {
+ throw new JSApplicationIllegalArgumentException(
+ "Invalid textBreakStrategy: " + textBreakStrategy);
+ }
+ }
+
+ public void setTextShadowOffset(ReadableMap offsetMap) {
+ mTextShadowOffsetDx = 0;
+ mTextShadowOffsetDy = 0;
+
+ if (offsetMap != null) {
+ if (offsetMap.hasKey(PROP_SHADOW_OFFSET_WIDTH)
+ && !offsetMap.isNull(PROP_SHADOW_OFFSET_WIDTH)) {
+ mTextShadowOffsetDx =
+ PixelUtil.toPixelFromDIP(offsetMap.getDouble(PROP_SHADOW_OFFSET_WIDTH));
+ }
+ if (offsetMap.hasKey(PROP_SHADOW_OFFSET_HEIGHT)
+ && !offsetMap.isNull(PROP_SHADOW_OFFSET_HEIGHT)) {
+ mTextShadowOffsetDy =
+ PixelUtil.toPixelFromDIP(offsetMap.getDouble(PROP_SHADOW_OFFSET_HEIGHT));
+ }
+ }
+ }
+
+ public void setTextShadowRadius(float textShadowRadius) {
+ if (textShadowRadius != mTextShadowRadius) {
+ mTextShadowRadius = textShadowRadius;
+ }
+ }
+
+ public void setTextShadowColor(int textShadowColor) {
+ if (textShadowColor != mTextShadowColor) {
+ mTextShadowColor = textShadowColor;
+
+ }
+ }
+
+ public void setTextTransform(@Nullable String textTransform) {
+ if (textTransform == null || "none".equals(textTransform)) {
+ mTextTransform = TextTransform.NONE;
+ } else if ("uppercase".equals(textTransform)) {
+ mTextTransform = TextTransform.UPPERCASE;
+ } else if ("lowercase".equals(textTransform)) {
+ mTextTransform = TextTransform.LOWERCASE;
+ } else if ("capitalize".equals(textTransform)) {
+ mTextTransform = TextTransform.CAPITALIZE;
+ } else {
+ throw new JSApplicationIllegalArgumentException("Invalid textTransform: " + textTransform);
+ }
+ }
+
+ /**
+ * Return -1 if the input string is not a valid numeric fontWeight (100, 200, ..., 900), otherwise
+ * return the weight.
+ *
+ * This code is duplicated in ReactTextInputManager
+ * TODO: Factor into a common place they can both use
+ */
+ private static int parseNumericFontWeight(String fontWeightString) {
+ // This should be much faster than using regex to verify input and Integer.parseInt
+ return fontWeightString.length() == 3
+ && fontWeightString.endsWith("00")
+ && fontWeightString.charAt(0) <= '9'
+ && fontWeightString.charAt(0) >= '1'
+ ? 100 * (fontWeightString.charAt(0) - '0')
+ : -1;
+ }
+
+ //TODO T31905686 remove this from here and add support to RTL
+ private YogaDirection getLayoutDirection() {
+ return YogaDirection.LTR;
+ }
+
+ public float getBottomPadding() {
+ return getPaddingProp(ViewProps.PADDING_BOTTOM);
+ }
+
+ public float getLeftPadding() {
+ return getPaddingProp(ViewProps.PADDING_LEFT);
+ }
+
+ public float getStartPadding() {
+ return getPaddingProp(ViewProps.PADDING_START);
+ }
+
+ public float getEndPadding() {
+ return getPaddingProp(ViewProps.PADDING_END);
+ }
+
+ public float getTopPadding() {
+ return getPaddingProp(ViewProps.PADDING_TOP);
+ }
+
+ public float getRightPadding() {
+ return getPaddingProp(ViewProps.PADDING_RIGHT);
+ }
+
+ private float getPaddingProp(String paddingType) {
+ if (mProps.hasKey(ViewProps.PADDING)) {
+ return PixelUtil.toPixelFromDIP(getFloatProp(ViewProps.PADDING, 0f));
+ }
+
+ return PixelUtil.toPixelFromDIP(getFloatProp(paddingType, 0f));
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributes.java

@@ -0,0 +1,183 @@
+/**
+ * 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.views.text;
+
+import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
+import com.facebook.react.uimanager.PixelUtil;
+import com.facebook.react.uimanager.ViewDefaults;
+
+/*
+ * Currently, TextAttributes consists of a subset of text props that need to be passed from parent
+ * to child so inheritance can be implemented correctly. An example complexity that causes a prop
+ * to end up in TextAttributes is when multiple props need to be considered together to determine
+ * the rendered aka effective value. For example, to figure out the rendered/effective font size,
+ * you need to take into account the fontSize, maxFontSizeMultiplier, and allowFontScaling props.
+ */
+public class TextAttributes {
+ // Setting the default to 0 indicates that there is no max.
+ public static final float DEFAULT_MAX_FONT_SIZE_MULTIPLIER = 0.0f;
+
+ private boolean mAllowFontScaling = true;
+ private float mFontSize = Float.NaN;
+ private float mLineHeight = Float.NaN;
+ private float mLetterSpacing = Float.NaN;
+ private float mMaxFontSizeMultiplier = Float.NaN;
+ private float mHeightOfTallestInlineImage = Float.NaN;
+ private TextTransform mTextTransform = TextTransform.UNSET;
+
+ public TextAttributes() {
+ }
+
+ public TextAttributes applyChild(TextAttributes child) {
+ TextAttributes result = new TextAttributes();
+
+ // allowFontScaling is always determined by the root Text
+ // component so don't allow the child to overwrite it.
+ result.mAllowFontScaling = mAllowFontScaling;
+
+ result.mFontSize = !Float.isNaN(child.mFontSize) ? child.mFontSize : mFontSize;
+ result.mLineHeight = !Float.isNaN(child.mLineHeight) ? child.mLineHeight : mLineHeight;
+ result.mLetterSpacing = !Float.isNaN(child.mLetterSpacing) ? child.mLetterSpacing : mLetterSpacing;
+ result.mMaxFontSizeMultiplier = !Float.isNaN(child.mMaxFontSizeMultiplier) ? child.mMaxFontSizeMultiplier : mMaxFontSizeMultiplier;
+ result.mHeightOfTallestInlineImage = !Float.isNaN(child.mHeightOfTallestInlineImage) ? child.mHeightOfTallestInlineImage : mHeightOfTallestInlineImage;
+ result.mTextTransform = child.mTextTransform != TextTransform.UNSET ? child.mTextTransform : mTextTransform;
+
+ return result;
+ }
+
+ // Getters and setters
+ //
+
+ public boolean getAllowFontScaling() {
+ return mAllowFontScaling;
+ }
+
+ public void setAllowFontScaling(boolean value) {
+ mAllowFontScaling = value;
+ }
+
+ public float getFontSize() {
+ return mFontSize;
+ }
+
+ public void setFontSize(float value) {
+ mFontSize = value;
+ }
+
+ public float getLineHeight() {
+ return mLineHeight;
+ }
+
+ public void setLineHeight(float value) {
+ mLineHeight = value;
+ }
+
+ public float getLetterSpacing() {
+ return mLetterSpacing;
+ }
+
+ public void setLetterSpacing(float value) {
+ mLetterSpacing = value;
+ }
+
+ public float getMaxFontSizeMultiplier() {
+ return mMaxFontSizeMultiplier;
+ }
+
+ public void setMaxFontSizeMultiplier(float maxFontSizeMultiplier) {
+ if (maxFontSizeMultiplier != 0 && maxFontSizeMultiplier < 1) {
+ throw new JSApplicationIllegalArgumentException("maxFontSizeMultiplier must be NaN, 0, or >= 1");
+ }
+ mMaxFontSizeMultiplier = maxFontSizeMultiplier;
+ }
+
+ public float getHeightOfTallestInlineImage() {
+ return mHeightOfTallestInlineImage;
+ }
+
+ public void setHeightOfTallestInlineImage(float value) {
+ mHeightOfTallestInlineImage = value;
+ }
+
+ public TextTransform getTextTransform() {
+ return mTextTransform;
+ }
+
+ public void setTextTransform(TextTransform textTransform) {
+ mTextTransform = textTransform;
+ }
+
+ // Getters for effective values
+ //
+ // In general, these return `Float.NaN` if the property doesn't have a value.
+ //
+
+ // Always returns a value because uses a hardcoded default as a fallback.
+ public int getEffectiveFontSize() {
+ float fontSize = !Float.isNaN(mFontSize) ? mFontSize : ViewDefaults.FONT_SIZE_SP;
+ return mAllowFontScaling
+ ? (int) Math.ceil(PixelUtil.toPixelFromSP(fontSize, getEffectiveMaxFontSizeMultiplier()))
+ : (int) Math.ceil(PixelUtil.toPixelFromDIP(fontSize));
+ }
+
+ public float getEffectiveLineHeight() {
+ if (Float.isNaN(mLineHeight)) {
+ return Float.NaN;
+ }
+
+ float lineHeight = mAllowFontScaling
+ ? PixelUtil.toPixelFromSP(mLineHeight, getEffectiveMaxFontSizeMultiplier())
+ : PixelUtil.toPixelFromDIP(mLineHeight);
+
+ // Take into account the requested line height
+ // and the height of the inline images.
+ boolean useInlineViewHeight =
+ !Float.isNaN(mHeightOfTallestInlineImage)
+ && mHeightOfTallestInlineImage > lineHeight;
+ return useInlineViewHeight ? mHeightOfTallestInlineImage : lineHeight;
+ }
+
+ public float getEffectiveLetterSpacing() {
+ if (Float.isNaN(mLetterSpacing)) {
+ return Float.NaN;
+ }
+
+ float letterSpacingPixels = mAllowFontScaling
+ ? PixelUtil.toPixelFromSP(mLetterSpacing, getEffectiveMaxFontSizeMultiplier())
+ : PixelUtil.toPixelFromDIP(mLetterSpacing);
+
+ // `letterSpacingPixels` and `getEffectiveFontSize` are both in pixels,
+ // yielding an accurate em value.
+ return letterSpacingPixels / getEffectiveFontSize();
+ }
+
+ // Never returns NaN
+ public float getEffectiveMaxFontSizeMultiplier() {
+ return !Float.isNaN(mMaxFontSizeMultiplier)
+ ? mMaxFontSizeMultiplier
+ : DEFAULT_MAX_FONT_SIZE_MULTIPLIER;
+ }
+
+ public String toString() {
+ return (
+ "TextAttributes {"
+ + "\n getAllowFontScaling(): " + getAllowFontScaling()
+ + "\n getFontSize(): " + getFontSize()
+ + "\n getEffectiveFontSize(): " + getEffectiveFontSize()
+ + "\n getHeightOfTallestInlineImage(): " + getHeightOfTallestInlineImage()
+ + "\n getLetterSpacing(): " + getLetterSpacing()
+ + "\n getEffectiveLetterSpacing(): " + getEffectiveLetterSpacing()
+ + "\n getLineHeight(): " + getLineHeight()
+ + "\n getEffectiveLineHeight(): " + getEffectiveLineHeight()
+ + "\n getTextTransform(): " + getTextTransform()
+ + "\n getMaxFontSizeMultiplier(): " + getMaxFontSizeMultiplier()
+ + "\n getEffectiveMaxFontSizeMultiplier(): " + getEffectiveMaxFontSizeMultiplier()
+ + "\n}"
+ );
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/views/text/TextInlineImageSpan.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -18,7 +18,7 @@
/**
* Base class for inline image spans.
*/
- public abstract class TextInlineImageSpan extends ReplacementSpan {
+ public abstract class TextInlineImageSpan extends ReplacementSpan implements ReactSpan {
/**
* For TextInlineImageSpan we need to update the Span to know that the window is attached and

ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java

@@ -0,0 +1,341 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+package com.facebook.react.views.text;
+
+import static com.facebook.react.views.text.TextAttributeProps.UNSET;
+
+import android.content.Context;
+import android.os.Build;
+import android.text.BoringLayout;
+import android.text.Layout;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.StaticLayout;
+import android.text.TextPaint;
+import android.util.LruCache;
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.ReadableNativeMap;
+import com.facebook.react.uimanager.PixelUtil;
+import com.facebook.react.uimanager.ReactStylesDiffMap;
+import com.facebook.yoga.YogaConstants;
+import com.facebook.yoga.YogaMeasureMode;
+import com.facebook.yoga.YogaMeasureOutput;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class responsible of creating {@link Spanned} object for the JS representation of Text
+ */
+public class TextLayoutManager {
+
+ // It's important to pass the ANTI_ALIAS_FLAG flag to the constructor rather than setting it
+ // later by calling setFlags. This is because the latter approach triggers a bug on Android 4.4.2.
+ // The bug is that unicode emoticons aren't measured properly which causes text to be clipped.
+ private static final TextPaint sTextPaintInstance = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
+
+ // Specifies the amount of spannable that are stored into the {@link sSpannableCache}.
+ private static final int spannableCacheSize = 100;
+
+ private static final Object sSpannableCacheLock = new Object();
+ private static LruCache<String, Spannable> sSpannableCache = new LruCache<>(spannableCacheSize);
+
+ private static void buildSpannableFromFragment(
+ Context context,
+ ReadableArray fragments,
+ SpannableStringBuilder sb,
+ List<SetSpanOperation> ops) {
+
+ for (int i = 0, length = fragments.size(); i < length; i++) {
+ ReadableMap fragment = fragments.getMap(i);
+ int start = sb.length();
+
+ // ReactRawText
+ TextAttributeProps textAttributes = new TextAttributeProps(new ReactStylesDiffMap(fragment.getMap("textAttributes")));
+
+ sb.append(TextTransform.apply(
+ fragment.getString("string"),
+ textAttributes.mTextTransform));
+
+// TODO: add support for TextInlineImage and BaseText
+// if (child instanceof ReactRawTextShadowNode) {
+// sb.append(((ReactRawTextShadowNode) child).getText());
+// } else if (child instanceof ReactBaseTextShadowNode) {
+// buildSpannableFromFragment((ReactBaseTextShadowNode) child, sb, ops);
+// } else if (child instanceof ReactTextInlineImageShadowNode) {
+// // We make the image take up 1 character in the span and put a corresponding character into
+// // the text so that the image doesn't run over any following text.
+// sb.append(INLINE_IMAGE_PLACEHOLDER);
+// ops.add(
+// new SetSpanOperation(
+// sb.length() - INLINE_IMAGE_PLACEHOLDER.length(),
+// sb.length(),
+// ((ReactTextInlineImageShadowNode) child).buildInlineImageSpan()));
+// } else {
+// throw new IllegalViewOperationException(
+// "Unexpected view type nested under text node: " + child.getClass());
+// }
+
+ int end = sb.length();
+ if (end >= start) {
+ if (textAttributes.mIsColorSet) {
+ ops.add(new SetSpanOperation(start, end, new ReactForegroundColorSpan(textAttributes.mColor)));
+ }
+ if (textAttributes.mIsBackgroundColorSet) {
+ ops.add(
+ new SetSpanOperation(
+ start, end, new ReactBackgroundColorSpan(textAttributes.mBackgroundColor)));
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ if (!Float.isNaN(textAttributes.mLetterSpacing)) {
+ ops.add(new SetSpanOperation(
+ start,
+ end,
+ new CustomLetterSpacingSpan(textAttributes.mLetterSpacing)));
+ }
+ }
+ ops.add(
+ new SetSpanOperation(
+ start, end, new ReactAbsoluteSizeSpan(textAttributes.mFontSize)));
+ if (textAttributes.mFontStyle != UNSET
+ || textAttributes.mFontWeight != UNSET
+ || textAttributes.mFontFamily != null) {
+ ops.add(
+ new SetSpanOperation(
+ start,
+ end,
+ new CustomStyleSpan(
+ textAttributes.mFontStyle,
+ textAttributes.mFontWeight,
+ textAttributes.mFontFamily,
+ context.getAssets())));
+ }
+ if (textAttributes.mIsUnderlineTextDecorationSet) {
+ ops.add(new SetSpanOperation(start, end, new ReactUnderlineSpan()));
+ }
+ if (textAttributes.mIsLineThroughTextDecorationSet) {
+ ops.add(new SetSpanOperation(start, end, new ReactStrikethroughSpan()));
+ }
+ if (textAttributes.mTextShadowOffsetDx != 0 || textAttributes.mTextShadowOffsetDy != 0) {
+ ops.add(
+ new SetSpanOperation(
+ start,
+ end,
+ new ShadowStyleSpan(
+ textAttributes.mTextShadowOffsetDx,
+ textAttributes.mTextShadowOffsetDy,
+ textAttributes.mTextShadowRadius,
+ textAttributes.mTextShadowColor)));
+ }
+ if (!Float.isNaN(textAttributes.getEffectiveLineHeight())) {
+ ops.add(
+ new SetSpanOperation(
+ start, end, new CustomLineHeightSpan(textAttributes.getEffectiveLineHeight())));
+ }
+
+ int reactTag = fragment.getInt("reactTag");
+ ops.add(new SetSpanOperation(start, end, new ReactTagSpan(reactTag)));
+ }
+ }
+ }
+
+ protected static Spannable getOrCreateSpannableForText(
+ Context context,
+ ReadableMap attributedString) {
+
+ Spannable preparedSpannableText;
+ String attributedStringPayload = attributedString.toString();
+ synchronized (sSpannableCacheLock) {
+ preparedSpannableText = sSpannableCache.get(attributedStringPayload);
+ //TODO: T31905686 implement proper equality of attributedStrings
+ if (preparedSpannableText != null) {
+ return preparedSpannableText;
+ }
+ }
+
+ preparedSpannableText = createSpannableFromAttributedString(context, attributedString);
+ synchronized (sSpannableCacheLock) {
+ sSpannableCache.put(attributedStringPayload, preparedSpannableText);
+ }
+ return preparedSpannableText;
+ }
+
+ private static Spannable createSpannableFromAttributedString(
+ Context context,
+ ReadableMap attributedString) {
+
+ SpannableStringBuilder sb = new SpannableStringBuilder();
+
+ // The {@link SpannableStringBuilder} implementation require setSpan operation to be called
+ // up-to-bottom, otherwise all the spannables that are withing the region for which one may set
+ // a new spannable will be wiped out
+ List<SetSpanOperation> ops = new ArrayList<>();
+
+ buildSpannableFromFragment(context, attributedString.getArray("fragments"), sb, ops);
+
+// TODO T31905686: add support for inline Images
+// textShadowNode.mContainsImages = false;
+// textShadowNode.mHeightOfTallestInlineImage = Float.NaN;
+
+ // While setting the Spans on the final text, we also check whether any of them are images.
+ int priority = 0;
+ for (SetSpanOperation op : ops) {
+// TODO T31905686: add support for TextInlineImage in C++
+// if (op.what instanceof TextInlineImageSpan) {
+// int height = ((TextInlineImageSpan) op.what).getHeight();
+// textShadowNode.mContainsImages = true;
+// if (Float.isNaN(textShadowNode.mHeightOfTallestInlineImage)
+// || height > textShadowNode.mHeightOfTallestInlineImage) {
+// textShadowNode.mHeightOfTallestInlineImage = height;
+// }
+// }
+
+ // Actual order of calling {@code execute} does NOT matter,
+ // but the {@code priority} DOES matter.
+ op.execute(sb, priority);
+ priority++;
+ }
+
+ return sb;
+ }
+
+ public static long measureText(
+ ReactContext context,
+ ReadableNativeMap attributedString,
+ ReadableNativeMap paragraphAttributes,
+ float width,
+ YogaMeasureMode widthYogaMeasureMode,
+ float height,
+ YogaMeasureMode heightYogaMeasureMode) {
+
+ // TODO(5578671): Handle text direction (see View#getTextDirectionHeuristic)
+ TextPaint textPaint = sTextPaintInstance;
+ Spannable preparedSpannableText = getOrCreateSpannableForText(context, attributedString);
+
+ // TODO add these props to paragraph attributes
+ int textBreakStrategy = Layout.BREAK_STRATEGY_HIGH_QUALITY;
+ boolean includeFontPadding = true;
+
+ if (preparedSpannableText == null) {
+ throw new IllegalStateException("Spannable element has not been prepared in onBeforeLayout");
+ }
+ Spanned text = preparedSpannableText;
+ BoringLayout.Metrics boring = BoringLayout.isBoring(text, textPaint);
+ float desiredWidth = boring == null ?
+ Layout.getDesiredWidth(text, textPaint) : Float.NaN;
+
+ // technically, width should never be negative, but there is currently a bug in
+ boolean unconstrainedWidth = widthYogaMeasureMode == YogaMeasureMode.UNDEFINED || width < 0;
+
+ Layout layout;
+ if (boring == null &&
+ (unconstrainedWidth ||
+ (!YogaConstants.isUndefined(desiredWidth) && desiredWidth <= width))) {
+ // Is used when the width is not known and the text is not boring, ie. if it contains
+ // unicode characters.
+
+ int hintWidth = (int) Math.ceil(desiredWidth);
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ layout = new StaticLayout(
+ text,
+ textPaint,
+ hintWidth,
+ Layout.Alignment.ALIGN_NORMAL,
+ 1.f,
+ 0.f,
+ includeFontPadding);
+ } else {
+ layout = StaticLayout.Builder.obtain(text, 0, text.length(), textPaint, hintWidth)
+ .setAlignment(Layout.Alignment.ALIGN_NORMAL)
+ .setLineSpacing(0.f, 1.f)
+ .setIncludePad(includeFontPadding)
+ .setBreakStrategy(textBreakStrategy)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
+ .build();
+ }
+
+ } else if (boring != null && (unconstrainedWidth || boring.width <= width)) {
+ // Is used for single-line, boring text when the width is either unknown or bigger
+ // than the width of the text.
+ layout = BoringLayout.make(
+ text,
+ textPaint,
+ boring.width,
+ Layout.Alignment.ALIGN_NORMAL,
+ 1.f,
+ 0.f,
+ boring,
+ includeFontPadding);
+ } else {
+ // Is used for multiline, boring text and the width is known.
+
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ layout = new StaticLayout(
+ text,
+ textPaint,
+ (int) width,
+ Layout.Alignment.ALIGN_NORMAL,
+ 1.f,
+ 0.f,
+ includeFontPadding);
+ } else {
+ layout = StaticLayout.Builder.obtain(text, 0, text.length(), textPaint, (int) width)
+ .setAlignment(Layout.Alignment.ALIGN_NORMAL)
+ .setLineSpacing(0.f, 1.f)
+ .setIncludePad(includeFontPadding)
+ .setBreakStrategy(textBreakStrategy)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
+ .build();
+ }
+ }
+
+ int maximumNumberOfLines =
+ paragraphAttributes.hasKey("maximumNumberOfLines")
+ ? paragraphAttributes.getInt("maximumNumberOfLines")
+ : UNSET;
+
+ width = layout.getWidth();
+ if (maximumNumberOfLines != UNSET
+ && maximumNumberOfLines != 0
+ && maximumNumberOfLines < layout.getLineCount()) {
+ height = layout.getLineBottom(maximumNumberOfLines - 1);
+ } else {
+ height = layout.getHeight();
+ }
+
+ return YogaMeasureOutput.make(PixelUtil.toSPFromPixel(width), PixelUtil.toSPFromPixel(height));
+ }
+
+ // TODO T31905686: This class should be private
+ public static class SetSpanOperation {
+ protected int start, end;
+ protected ReactSpan what;
+
+ SetSpanOperation(int start, int end, ReactSpan what) {
+ this.start = start;
+ this.end = end;
+ this.what = what;
+ }
+
+ public void execute(SpannableStringBuilder sb, int priority) {
+ // All spans will automatically extend to the right of the text, but not the left - except
+ // for spans that start at the beginning of the text.
+ int spanFlags = Spannable.SPAN_EXCLUSIVE_INCLUSIVE;
+ if (start == 0) {
+ spanFlags = Spannable.SPAN_INCLUSIVE_INCLUSIVE;
+ }
+
+ spanFlags &= ~Spannable.SPAN_PRIORITY;
+ spanFlags |= (priority << Spannable.SPAN_PRIORITY_SHIFT) & Spannable.SPAN_PRIORITY;
+
+ sb.setSpan(what, start, end, spanFlags);
+ }
+ }
+}

ReactAndroid/src/main/java/com/facebook/react/views/text/TextTransform.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,7 +7,54 @@
package com.facebook.react.views.text;
+import java.text.BreakIterator;
+
/**
* Types of text transforms for CustomTextTransformSpan
*/
-public enum TextTransform { NONE, UPPERCASE, LOWERCASE, CAPITALIZE, UNSET };
+public enum TextTransform {
+ NONE, UPPERCASE, LOWERCASE, CAPITALIZE, UNSET;
+
+ public static String apply(String text, TextTransform textTransform) {
+ if (text == null) {
+ return null;
+ }
+
+ String transformed;
+ switch(textTransform) {
+ case UPPERCASE:
+ transformed = text.toUpperCase();
+ break;
+ case LOWERCASE:
+ transformed = text.toLowerCase();
+ break;
+ case CAPITALIZE:
+ transformed = capitalize(text);
+ break;
+ default:
+ transformed = text;
+ }
+
+ return transformed;
+ }
+
+ private static String capitalize(String text) {
+ BreakIterator wordIterator = BreakIterator.getWordInstance();
+ wordIterator.setText(text);
+
+ StringBuilder res = new StringBuilder(text.length());
+ int start = wordIterator.first();
+ for (int end = wordIterator.next(); end != BreakIterator.DONE; end = wordIterator.next()) {
+ String word = text.substring(start, end);
+ if (Character.isLetterOrDigit(word.charAt(0))) {
+ res.append(Character.toUpperCase(word.charAt(0)));
+ res.append(word.substring(1).toLowerCase());
+ } else {
+ res.append(word);
+ }
+ start = end;
+ }
+
+ return res.toString();
+ }
+};

ReactAndroid/src/main/java/com/facebook/react/views/textinput/BUCK

@@ -12,6 +12,7 @@
],
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"),

ReactAndroid/src/main/java/com/facebook/react/views/textinput/ContentSizeWatcher.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactContentSizeChangedEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditTextInputConnectionWrapper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -20,9 +20,7 @@
import android.text.TextUtils;
import android.text.method.KeyListener;
import android.text.method.QwertyKeyListener;
-import android.text.style.AbsoluteSizeSpan;
-import android.text.style.BackgroundColorSpan;
-import android.text.style.ForegroundColorSpan;
+import android.util.TypedValue;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -33,11 +31,10 @@
import android.widget.EditText;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.ReactContext;
-import com.facebook.react.uimanager.PixelUtil;
import com.facebook.react.uimanager.UIManagerModule;
-import com.facebook.react.views.text.CustomStyleSpan;
-import com.facebook.react.views.text.ReactTagSpan;
+import com.facebook.react.views.text.ReactSpan;
import com.facebook.react.views.text.ReactTextUpdate;
+import com.facebook.react.views.text.TextAttributes;
import com.facebook.react.views.text.TextInlineImageSpan;
import com.facebook.react.views.view.ReactViewBackgroundManager;
import java.util.ArrayList;
@@ -82,7 +79,7 @@
private final InternalKeyListener mKeyListener;
private boolean mDetectScrollMovement = false;
private boolean mOnKeyPress = false;
- private float mLetterSpacingPt = 0;
+ private TextAttributes mTextAttributes;
private ReactViewBackgroundManager mReactBackgroundManager;
@@ -109,6 +106,9 @@
mStagedInputType = getInputType();
mKeyListener = new InternalKeyListener();
mScrollWatcher = null;
+ mTextAttributes = new TextAttributes();
+
+ applyTextAttributes();
}
// After the text changes inside an EditText, TextView checks if a layout() has been requested.
@@ -397,11 +397,7 @@
Object[] spans = getText().getSpans(0, length(), Object.class);
for (int spanIdx = 0; spanIdx < spans.length; spanIdx++) {
// Remove all styling spans we might have previously set
- if (ForegroundColorSpan.class.isInstance(spans[spanIdx]) ||
- BackgroundColorSpan.class.isInstance(spans[spanIdx]) ||
- AbsoluteSizeSpan.class.isInstance(spans[spanIdx]) ||
- CustomStyleSpan.class.isInstance(spans[spanIdx]) ||
- ReactTagSpan.class.isInstance(spans[spanIdx])) {
+ if (spans[spanIdx] instanceof ReactSpan) {
getText().removeSpan(spans[spanIdx]);
}
@@ -635,25 +631,42 @@
}
public void setLetterSpacingPt(float letterSpacingPt) {
- mLetterSpacingPt = letterSpacingPt;
- updateLetterSpacing();
+ mTextAttributes.setLetterSpacing(letterSpacingPt);
+ applyTextAttributes();
}
- @Override
- public void setTextSize (float size) {
- super.setTextSize(size);
- updateLetterSpacing();
+ public void setAllowFontScaling(boolean allowFontScaling) {
+ if (mTextAttributes.getAllowFontScaling() != allowFontScaling) {
+ mTextAttributes.setAllowFontScaling(allowFontScaling);
+ applyTextAttributes();
+ }
}
- @Override
- public void setTextSize (int unit, float size) {
- super.setTextSize(unit, size);
- updateLetterSpacing();
+ public void setFontSize(float fontSize) {
+ mTextAttributes.setFontSize(fontSize);
+ applyTextAttributes();
+ }
+
+ public void setMaxFontSizeMultiplier(float maxFontSizeMultiplier) {
+ if (maxFontSizeMultiplier != mTextAttributes.getMaxFontSizeMultiplier()) {
+ mTextAttributes.setMaxFontSizeMultiplier(maxFontSizeMultiplier);
+ applyTextAttributes();
+ }
}
- protected void updateLetterSpacing() {
+ protected void applyTextAttributes() {
+ // In general, the `getEffective*` functions return `Float.NaN` if the
+ // property hasn't been set.
+
+ // `getEffectiveFontSize` always returns a value so don't need to check for anything like
+ // `Float.NaN`.
+ setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextAttributes.getEffectiveFontSize());
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- setLetterSpacing(PixelUtil.toPixelFromSP(mLetterSpacingPt) / getTextSize());
+ float effectiveLetterSpacing = mTextAttributes.getEffectiveLetterSpacing();
+ if (!Float.isNaN(effectiveLetterSpacing)) {
+ setLetterSpacing(effectiveLetterSpacing);
+ }
}
}

ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextChangedEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputBlurEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputEndEditingEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputFocusEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputKeyPressEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputLocalData.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -28,14 +28,8 @@
mTextSize = editText.getTextSize();
mInputType = editText.getInputType();
mPlaceholder = editText.getHint();
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
mMinLines = editText.getMinLines();
mMaxLines = editText.getMaxLines();
- } else {
- mMinLines = 1;
- mMaxLines = 1;
- }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mBreakStrategy = editText.getBreakStrategy();

ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,13 +7,18 @@
package com.facebook.react.views.textinput;
+import static android.view.View.FOCUS_FORWARD;
+
+import android.annotation.TargetApi;
import android.graphics.PorterDuff;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.support.v4.content.ContextCompat;
import android.text.Editable;
import android.text.InputFilter;
import android.text.InputType;
+import android.text.Layout;
import android.text.Spannable;
import android.text.TextWatcher;
import android.util.TypedValue;
@@ -22,6 +27,7 @@
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.TextView;
+import com.facebook.common.logging.FLog;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
import com.facebook.react.bridge.ReactContext;
@@ -59,7 +65,7 @@
*/
@ReactModule(name = ReactTextInputManager.REACT_CLASS)
public class ReactTextInputManager extends BaseViewManager<ReactEditText, LayoutShadowNode> {
-
+ public static final String TAG = ReactTextInputManager.class.getSimpleName();
protected static final String REACT_CLASS = "AndroidTextInput";
private static final int[] SPACING_TYPES = {
@@ -101,9 +107,6 @@
int inputType = editText.getInputType();
editText.setInputType(inputType & (~InputType.TYPE_TEXT_FLAG_MULTI_LINE));
editText.setReturnKeyType("done");
- editText.setTextSize(
- TypedValue.COMPLEX_UNIT_PX,
- (int) Math.ceil(PixelUtil.toPixelFromSP(ViewDefaults.FONT_SIZE_SP)));
return editText;
}
@@ -204,9 +207,7 @@
@ReactProp(name = ViewProps.FONT_SIZE, defaultFloat = ViewDefaults.FONT_SIZE_SP)
public void setFontSize(ReactEditText view, float fontSize) {
- view.setTextSize(
- TypedValue.COMPLEX_UNIT_PX,
- (int) Math.ceil(PixelUtil.toPixelFromSP(fontSize)));
+ view.setFontSize(fontSize);
}
@ReactProp(name = ViewProps.FONT_FAMILY)
@@ -222,6 +223,11 @@
view.setTypeface(newTypeface);
}
+ @ReactProp(name = ViewProps.MAX_FONT_SIZE_MULTIPLIER, defaultFloat = Float.NaN)
+ public void setMaxFontSizeMultiplier(ReactEditText view, float maxFontSizeMultiplier) {
+ view.setMaxFontSizeMultiplier(maxFontSizeMultiplier);
+ }
+
/**
/* This code was taken from the method setFontWeight of the class ReactTextShadowNode
/* TODO: Factor into a common place they can both use
@@ -279,6 +285,24 @@
}
}
+ @ReactProp(name = "importantForAutofill")
+ public void setImportantForAutofill(ReactEditText view, @Nullable String value) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
+ return;
+ }
+ int mode = View.IMPORTANT_FOR_AUTOFILL_AUTO;
+ if ("no".equals(value)) {
+ mode = View.IMPORTANT_FOR_AUTOFILL_NO;
+ } else if ("noExcludeDescendants".equals(value)) {
+ mode = View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS;
+ } else if ("yes".equals(value)) {
+ mode = View.IMPORTANT_FOR_AUTOFILL_YES;
+ } else if ("yesExcludeDescendants".equals(value)) {
+ mode = View.IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS;
+ }
+ view.setImportantForAutofill(mode);
+ }
+
@ReactProp(name = "onSelectionChange", defaultBoolean = false)
public void setOnSelectionChange(final ReactEditText view, boolean onSelectionChange) {
if (onSelectionChange) {
@@ -324,6 +348,11 @@
view.setLetterSpacingPt(letterSpacing);
}
+ @ReactProp(name = ViewProps.ALLOW_FONT_SCALING, defaultBoolean = true)
+ public void setAllowFontScaling(ReactEditText view, boolean allowFontScaling) {
+ view.setAllowFontScaling(allowFontScaling);
+ }
+
@ReactProp(name = "placeholder")
public void setPlaceholder(ReactEditText view, @Nullable String placeholder) {
view.setHint(placeholder);
@@ -417,9 +446,14 @@
// Drawable.mutate() can sometimes crash due to an AOSP bug:
// See https://code.google.com/p/android/issues/detail?id=191754 for more info
Drawable background = view.getBackground();
- Drawable drawableToMutate = background.getConstantState() != null ?
- background.mutate() :
- background;
+ Drawable drawableToMutate = background;
+ if (background.getConstantState() != null) {
+ try {
+ drawableToMutate = background.mutate();
+ } catch (NullPointerException e) {
+ FLog.e(TAG, "NullPointerException when setting underlineColorAndroid for TextInput", e);
+ }
+ }
if (underlineColor == null) {
drawableToMutate.clearColorFilter();
@@ -430,20 +464,29 @@
@ReactProp(name = ViewProps.TEXT_ALIGN)
public void setTextAlign(ReactEditText view, @Nullable String textAlign) {
+ if ("justify".equals(textAlign)) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ view.setJustificationMode(Layout.JUSTIFICATION_MODE_INTER_WORD);
+ }
+ view.setGravityHorizontal(Gravity.START);
+ } else {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ view.setJustificationMode(Layout.JUSTIFICATION_MODE_NONE);
+ }
+
if (textAlign == null || "auto".equals(textAlign)) {
view.setGravityHorizontal(Gravity.NO_GRAVITY);
} else if ("left".equals(textAlign)) {
- view.setGravityHorizontal(Gravity.LEFT);
+ view.setGravityHorizontal(Gravity.START);
} else if ("right".equals(textAlign)) {
- view.setGravityHorizontal(Gravity.RIGHT);
+ view.setGravityHorizontal(Gravity.END);
} else if ("center".equals(textAlign)) {
view.setGravityHorizontal(Gravity.CENTER_HORIZONTAL);
- } else if ("justify".equals(textAlign)) {
- // Fallback gracefully for cross-platform compat instead of error
- view.setGravityHorizontal(Gravity.LEFT);
} else {
throw new JSApplicationIllegalArgumentException("Invalid textAlign: " + textAlign);
}
+
+ }
}
@ReactProp(name = ViewProps.TEXT_ALIGN_VERTICAL)
@@ -523,6 +566,46 @@
view.setFilters(newFilters);
}
+ @ReactProp(name = "autoComplete")
+ public void setTextContentType(ReactEditText view, @Nullable String autocomplete) {
+ // Autofill hints were added in Android API 26.
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
+ return;
+ }
+
+ if (autocomplete == null) {
+ view.setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO);
+ } else if ("username".equals(autocomplete)) {
+ view.setAutofillHints(View.AUTOFILL_HINT_USERNAME);
+ } else if ("password".equals(autocomplete)) {
+ view.setAutofillHints(View.AUTOFILL_HINT_PASSWORD);
+ } else if ("email".equals(autocomplete)) {
+ view.setAutofillHints(View.AUTOFILL_HINT_EMAIL_ADDRESS);
+ } else if ("name".equals(autocomplete)) {
+ view.setAutofillHints(View.AUTOFILL_HINT_NAME);
+ } else if ("tel".equals(autocomplete)) {
+ view.setAutofillHints(View.AUTOFILL_HINT_PHONE);
+ } else if ("street-address".equals(autocomplete)) {
+ view.setAutofillHints(View.AUTOFILL_HINT_POSTAL_ADDRESS);
+ } else if ("postal-code".equals(autocomplete)) {
+ view.setAutofillHints(View.AUTOFILL_HINT_POSTAL_CODE);
+ } else if ("cc-number".equals(autocomplete)) {
+ view.setAutofillHints(View.AUTOFILL_HINT_CREDIT_CARD_NUMBER);
+ } else if ("cc-csc".equals(autocomplete)) {
+ view.setAutofillHints(View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE);
+ } else if ("cc-exp".equals(autocomplete)) {
+ view.setAutofillHints(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE);
+ } else if ("cc-exp-month".equals(autocomplete)) {
+ view.setAutofillHints(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH);
+ } else if ("cc-exp-year".equals(autocomplete)) {
+ view.setAutofillHints(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR);
+ } else if ("off".equals(autocomplete)) {
+ view.setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO);
+ } else {
+ throw new JSApplicationIllegalArgumentException("Invalid autocomplete option: " + autocomplete);
+ }
+ }
+
@ReactProp(name = "autoCorrect")
public void setAutoCorrect(ReactEditText view, @Nullable Boolean autoCorrect) {
// clear auto correct flags, set SUGGESTIONS or NO_SUGGESTIONS depending on value
@@ -807,6 +890,12 @@
// Prevent default behavior except when we want it to insert a newline.
return blurOnSubmit || !isMultiline;
+ } else if (actionId == EditorInfo.IME_ACTION_NEXT) {
+ View v1 = v.focusSearch(FOCUS_FORWARD);
+ if (v1 != null && !v.requestFocus(FOCUS_FORWARD)) {
+ return true;
+ }
+ return false;
}
return true;

ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputSelectionEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,7 +7,9 @@
package com.facebook.react.views.textinput;
+import android.annotation.TargetApi;
import android.os.Build;
+import android.support.v4.view.ViewCompat;
import android.text.Layout;
import android.util.TypedValue;
import android.view.ViewGroup;
@@ -33,6 +35,7 @@
import javax.annotation.Nullable;
@VisibleForTesting
+@TargetApi(Build.VERSION_CODES.M)
public class ReactTextInputShadowNode extends ReactBaseTextShadowNode
implements YogaMeasureFunction {
@@ -49,50 +52,16 @@
public ReactTextInputShadowNode() {
mTextBreakStrategy = (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) ?
- 0 : Layout.BREAK_STRATEGY_SIMPLE;
+ Layout.BREAK_STRATEGY_SIMPLE : Layout.BREAK_STRATEGY_HIGH_QUALITY;
initMeasureFunction();
}
- private ReactTextInputShadowNode(ReactTextInputShadowNode node) {
- super(node);
- mMostRecentEventCount = node.mMostRecentEventCount;
- mText = node.mText;
- mLocalData = node.mLocalData;
- }
-
- @Override
- protected ReactTextInputShadowNode copy() {
- return new ReactTextInputShadowNode(this);
- }
-
- @Override
- public ReactTextInputShadowNode mutableCopy(long instanceHandle) {
- ReactTextInputShadowNode node = (ReactTextInputShadowNode) super.mutableCopy(instanceHandle);
- node.initMeasureFunction();
- ThemedReactContext themedContext = getThemedContext();
- if (themedContext != null) {
- node.setThemedContext(themedContext);
- }
- return node;
- }
-
private void initMeasureFunction() {
setMeasureFunction(this);
}
@Override
- public ReactTextInputShadowNode mutableCopyWithNewChildren(long instanceHandle) {
- ReactTextInputShadowNode node = (ReactTextInputShadowNode) super.mutableCopyWithNewChildren(instanceHandle);
- node.initMeasureFunction();
- ThemedReactContext themedContext = getThemedContext();
- if (themedContext != null) {
- node.setThemedContext(themedContext);
- }
- return node;
- }
-
- @Override
public void setThemedContext(ThemedReactContext themedContext) {
super.setThemedContext(themedContext);
@@ -105,9 +74,9 @@
// So, we have to enforce it as a default padding.
// TODO #7120264: Cache this stuff better.
EditText editText = new EditText(getThemedContext());
- setDefaultPadding(Spacing.START, editText.getPaddingStart());
+ setDefaultPadding(Spacing.START, ViewCompat.getPaddingStart(editText));
setDefaultPadding(Spacing.TOP, editText.getPaddingTop());
- setDefaultPadding(Spacing.END, editText.getPaddingEnd());
+ setDefaultPadding(Spacing.END, ViewCompat.getPaddingEnd(editText));
setDefaultPadding(Spacing.BOTTOM, editText.getPaddingBottom());
mDummyEditText = editText;
@@ -135,10 +104,7 @@
if (mLocalData != null) {
mLocalData.apply(editText);
} else {
- editText.setTextSize(
- TypedValue.COMPLEX_UNIT_PX,
- mFontSize == UNSET ?
- (int) Math.ceil(PixelUtil.toPixelFromSP(ViewDefaults.FONT_SIZE_SP)) : mFontSize);
+ editText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextAttributes.getEffectiveFontSize());
if (mNumberOfLines != UNSET) {
editText.setLines(mNumberOfLines);
@@ -238,7 +204,8 @@
getPadding(Spacing.RIGHT),
getPadding(Spacing.BOTTOM),
mTextAlign,
- mTextBreakStrategy);
+ mTextBreakStrategy,
+ mJustificationMode);
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
}
}

ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputSubmitEditingEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/textinput/ScrollWatcher.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/textinput/SelectionWatcher.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/toolbar/DrawableWithIntrinsicSize.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/toolbar/events/ToolbarClickEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbar.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbarManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,6 +11,7 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
+import android.support.v4.view.ViewCompat;
import android.util.LayoutDirection;
import android.view.MenuItem;
import android.view.View;
@@ -62,7 +63,7 @@
@ReactProp(name = "rtl")
public void setRtl(ReactToolbar view, boolean rtl) {
- view.setLayoutDirection(rtl ? LayoutDirection.RTL : LayoutDirection.LTR);
+ ViewCompat.setLayoutDirection(view, rtl ? ViewCompat.LAYOUT_DIRECTION_RTL : ViewCompat.LAYOUT_DIRECTION_LTR);
}
@ReactProp(name = "subtitle")

ReactAndroid/src/main/java/com/facebook/react/views/view/BUCK

@@ -6,8 +6,12 @@
visibility = [
"PUBLIC",
],
+ provided_deps = [
+ react_native_dep("third-party/android/support/v4:lib-support-v4"),
+ ],
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"),

ReactAndroid/src/main/java/com/facebook/react/views/view/ColorUtil.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/view/MeasureUtil.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/react/views/view/ReactDrawableHelper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,6 +7,7 @@
package com.facebook.react.views.view;
+import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Color;
@@ -29,6 +30,7 @@
private static final TypedValue sResolveOutValue = new TypedValue();
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
public static Drawable createDrawableFromJSDescription(
Context context,
ReadableMap drawableDescriptionDict) {
@@ -42,8 +44,7 @@
" couldn't be found in the resource list");
}
if (context.getTheme().resolveAttribute(attrID, sResolveOutValue, true)) {
- final int version = Build.VERSION.SDK_INT;
- if (version >= 21) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return context.getResources()
.getDrawable(sResolveOutValue.resourceId, context.getTheme());
} else {
@@ -54,7 +55,7 @@
" couldn't be resolved into a drawable");
}
} else if ("RippleAndroid".equals(type)) {
- if (Build.VERSION.SDK_INT < 21) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
throw new JSApplicationIllegalArgumentException("Ripple drawable is not available on " +
"android API <21");
}

ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundManager.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -8,8 +8,8 @@
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
+import android.support.v4.view.ViewCompat;
import android.view.View;
-import com.facebook.react.views.common.ViewHelper;
import javax.annotation.Nullable;
/** Class that manages the background for views and borders. */
@@ -26,15 +26,15 @@
if (mReactBackgroundDrawable == null) {
mReactBackgroundDrawable = new ReactViewBackgroundDrawable(mView.getContext());
Drawable backgroundDrawable = mView.getBackground();
- ViewHelper.setBackground(
+ ViewCompat.setBackground(
mView, null); // required so that drawable callback is cleared before we add the
// drawable back as a part of LayerDrawable
if (backgroundDrawable == null) {
- ViewHelper.setBackground(mView, mReactBackgroundDrawable);
+ ViewCompat.setBackground(mView, mReactBackgroundDrawable);
} else {
LayerDrawable layerDrawable =
new LayerDrawable(new Drawable[] {mReactBackgroundDrawable, backgroundDrawable});
- ViewHelper.setBackground(mView, layerDrawable);
+ ViewCompat.setBackground(mView, layerDrawable);
}
}
return mReactBackgroundDrawable;

ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,6 +7,8 @@
package com.facebook.react.views.view;
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -19,10 +21,13 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewStructure;
import android.view.animation.Animation;
+import com.facebook.common.logging.FLog;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.common.annotations.VisibleForTesting;
+import com.facebook.react.common.ReactConstants;
import com.facebook.react.modules.i18nmanager.I18nUtil;
import com.facebook.react.touch.OnInterceptTouchEventListener;
import com.facebook.react.touch.ReactHitSlopView;
@@ -39,10 +44,10 @@
import com.facebook.react.uimanager.ViewGroupDrawingOrderHelper;
import com.facebook.react.uimanager.ViewProps;
import com.facebook.yoga.YogaConstants;
-import java.util.ArrayList;
-import java.util.List;
import javax.annotation.Nullable;
+import static com.facebook.react.common.ReactConstants.TAG;
+
/**
* Backing for a React View. Has support for borders, but since borders aren't common, lazy
* initializes most of the storage needed for them.
@@ -108,11 +113,12 @@
private @Nullable ChildrenLayoutChangeListener mChildrenLayoutChangeListener;
private @Nullable ReactViewBackgroundDrawable mReactBackgroundDrawable;
private @Nullable OnInterceptTouchEventListener mOnInterceptTouchEventListener;
- private @Nullable List<View> mTransitioningViews;
private boolean mNeedsOffscreenAlphaCompositing = false;
private final ViewGroupDrawingOrderHelper mDrawingOrderHelper;
private @Nullable Path mPath;
private int mLayoutDirection;
+ private float mBackfaceOpacity = 1.f;
+ private String mBackfaceVisibility = "visible";
public ReactViewGroup(Context context) {
super(context);
@@ -144,11 +150,22 @@
}
@Override
+ @SuppressLint("MissingSuperCall")
public void requestLayout() {
// No-op, terminate `requestLayout` here, UIManagerModule handles laying out children and
// `layout` is called on all RN-managed views by `NativeViewHierarchyManager`
}
+ @TargetApi(23)
+ @Override
+ public void dispatchProvideStructure(ViewStructure structure) {
+ try {
+ super.dispatchProvideStructure(structure);
+ } catch (NullPointerException e) {
+ FLog.e(TAG, "NullPointerException when executing dispatchProvideStructure", e);
+ }
+ }
+
@Override
public void setBackgroundColor(int color) {
if (color == Color.TRANSPARENT && mReactBackgroundDrawable == null) {
@@ -239,8 +256,7 @@
ReactViewBackgroundDrawable backgroundDrawable = getOrCreateReactViewBackground();
backgroundDrawable.setRadius(borderRadius);
- if (Build.VERSION_CODES.HONEYCOMB < Build.VERSION.SDK_INT
- && Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
final int UPDATED_LAYER_TYPE =
backgroundDrawable.hasRoundedBorders()
? View.LAYER_TYPE_SOFTWARE
@@ -256,8 +272,7 @@
ReactViewBackgroundDrawable backgroundDrawable = getOrCreateReactViewBackground();
backgroundDrawable.setRadius(borderRadius, position);
- if (Build.VERSION_CODES.HONEYCOMB < Build.VERSION.SDK_INT
- && Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
final int UPDATED_LAYER_TYPE =
backgroundDrawable.hasRoundedBorders()
? View.LAYER_TYPE_SOFTWARE
@@ -334,16 +349,16 @@
private void updateClippingToRect(Rect clippingRect) {
Assertions.assertNotNull(mAllChildren);
- int childIndexOffset = 0;
+ int clippedSoFar = 0;
for (int i = 0; i < mAllChildrenCount; i++) {
- updateSubviewClipStatus(clippingRect, i, childIndexOffset);
- if (!isChildInViewGroup(mAllChildren[i])) {
- childIndexOffset++;
+ updateSubviewClipStatus(clippingRect, i, clippedSoFar);
+ if (mAllChildren[i].getParent() == null) {
+ clippedSoFar++;
}
}
}
- private void updateSubviewClipStatus(Rect clippingRect, int idx, int childIndexOffset) {
+ private void updateSubviewClipStatus(Rect clippingRect, int idx, int clippedSoFar) {
View child = Assertions.assertNotNull(mAllChildren)[idx];
sHelperRect.set(child.getLeft(), child.getTop(), child.getRight(), child.getBottom());
boolean intersects = clippingRect
@@ -360,10 +375,10 @@
if (!intersects && child.getParent() != null && !isAnimating) {
// We can try saving on invalidate call here as the view that we remove is out of visible area
// therefore invalidation is not necessary.
- super.removeViewsInLayout(idx - childIndexOffset, 1);
+ super.removeViewsInLayout(idx - clippedSoFar, 1);
needUpdateClippingRecursive = true;
} else if (intersects && child.getParent() == null) {
- super.addViewInLayout(child, idx - childIndexOffset, sDefaultLayoutParam, true);
+ super.addViewInLayout(child, idx - clippedSoFar, sDefaultLayoutParam, true);
invalidate();
needUpdateClippingRecursive = true;
} else if (intersects) {
@@ -399,23 +414,17 @@
boolean oldIntersects = (subview.getParent() != null);
if (intersects != oldIntersects) {
- int childIndexOffset = 0;
+ int clippedSoFar = 0;
for (int i = 0; i < mAllChildrenCount; i++) {
if (mAllChildren[i] == subview) {
- updateSubviewClipStatus(mClippingRect, i, childIndexOffset);
+ updateSubviewClipStatus(mClippingRect, i, clippedSoFar);
break;
}
- if (!isChildInViewGroup(mAllChildren[i])) {
- childIndexOffset++;
- }
+ if (mAllChildren[i].getParent() == null) {
+ clippedSoFar++;
}
}
}
-
- private boolean isChildInViewGroup(View view) {
- // A child is in the group if it's not clipped and it's not transitioning.
- return view.getParent() != null
- && (mTransitioningViews == null || !mTransitioningViews.contains(view));
}
@Override
@@ -515,13 +524,13 @@
addInArray(child, index);
// we add view as "clipped" and then run {@link #updateSubviewClipStatus} to conditionally
// attach it
- int childIndexOffset = 0;
+ int clippedSoFar = 0;
for (int i = 0; i < index; i++) {
- if (!isChildInViewGroup(mAllChildren[i])) {
- childIndexOffset++;
+ if (mAllChildren[i].getParent() == null) {
+ clippedSoFar++;
}
}
- updateSubviewClipStatus(mClippingRect, index, childIndexOffset);
+ updateSubviewClipStatus(mClippingRect, index, clippedSoFar);
child.addOnLayoutChangeListener(mChildrenLayoutChangeListener);
}
@@ -531,14 +540,14 @@
Assertions.assertNotNull(mAllChildren);
view.removeOnLayoutChangeListener(mChildrenLayoutChangeListener);
int index = indexOfChildInAllChildren(view);
- if (isChildInViewGroup(mAllChildren[index])) {
- int childIndexOffset = 0;
+ if (mAllChildren[index].getParent() != null) {
+ int clippedSoFar = 0;
for (int i = 0; i < index; i++) {
- if (!isChildInViewGroup(mAllChildren[i])) {
- childIndexOffset++;
+ if (mAllChildren[i].getParent() == null) {
+ clippedSoFar++;
}
}
- super.removeViewsInLayout(index - childIndexOffset, 1);
+ super.removeViewsInLayout(index - clippedSoFar, 1);
}
removeFromArray(index);
}
@@ -553,26 +562,6 @@
mAllChildrenCount = 0;
}
- /*package*/ void startViewTransitionWithSubviewClippingEnabled(View view) {
- // We're mirroring ViewGroup's mTransitioningViews since when a transitioning child is removed,
- // its parent is not set to null unlike a regular child. Normally this wouldn't be an issue as
- // ViewGroup pretends the transitioning child doesn't exist when calling any methods that expose
- // child views, but we keep track of our children directly when subview clipping is enabled and
- // need to be aware of these.
- if (mTransitioningViews == null) {
- mTransitioningViews = new ArrayList<>();
- }
- mTransitioningViews.add(view);
- startViewTransition(view);
- }
-
- /*package*/ void endViewTransitionWithSubviewClippingEnabled(View view) {
- if (mTransitioningViews != null) {
- mTransitioningViews.remove(view);
- }
- endViewTransition(view);
- }
-
private int indexOfChildInAllChildren(View child) {
final int count = mAllChildrenCount;
final View[] children = Assertions.assertNotNull(mAllChildren);
@@ -685,11 +674,7 @@
* background
*/
private void updateBackgroundDrawable(Drawable drawable) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
super.setBackground(drawable);
- } else {
- super.setBackgroundDrawable(drawable);
- }
}
@Override
@@ -697,6 +682,8 @@
try {
dispatchOverflowDraw(canvas);
super.dispatchDraw(canvas);
+ } catch (NullPointerException e) {
+ FLog.e(TAG, "NullPointerException when executing ViewGroup.dispatchDraw method", e);
} catch (StackOverflowError e) {
// Adding special exception management for StackOverflowError for logging purposes.
// This will be removed in the future.
@@ -866,4 +853,36 @@
}
}
}
+
+ public void setOpacityIfPossible(float opacity) {
+ mBackfaceOpacity = opacity;
+ setBackfaceVisibilityDependantOpacity();
+ }
+
+ public void setBackfaceVisibility(String backfaceVisibility) {
+ mBackfaceVisibility = backfaceVisibility;
+ setBackfaceVisibilityDependantOpacity();
+ }
+
+ public void setBackfaceVisibilityDependantOpacity() {
+ boolean isBackfaceVisible = mBackfaceVisibility.equals("visible");
+
+ if (isBackfaceVisible) {
+ setAlpha(mBackfaceOpacity);
+ return;
+ }
+
+ float rotationX = getRotationX();
+ float rotationY = getRotationY();
+
+ boolean isFrontfaceVisible = (rotationX >= -90.f && rotationX < 90.f) &&
+ (rotationY >= -90.f && rotationY < 90.f);
+
+ if (isFrontfaceVisible) {
+ setAlpha(mBackfaceOpacity);
+ return;
+ }
+
+ setAlpha(0);
+ }
}

ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -203,6 +203,22 @@
view.setOverflow(overflow);
}
+ @ReactProp(name = "backfaceVisibility")
+ public void setBackfaceVisibility(ReactViewGroup view, String backfaceVisibility) {
+ view.setBackfaceVisibility(backfaceVisibility);
+ }
+
+ @Override
+ public void setOpacity(ReactViewGroup view, float opacity) {
+ view.setOpacityIfPossible(opacity);
+ }
+
+ @Override
+ public void setTransform(ReactViewGroup view, ReadableArray matrix) {
+ super.setTransform(view, matrix);
+ view.setBackfaceVisibilityDependantOpacity();
+ }
+
@Override
public String getName() {
return REACT_CLASS;
@@ -226,7 +242,7 @@
throw new JSApplicationIllegalArgumentException(
"Illegal number of arguments for 'updateHotspot' command");
}
- if (Build.VERSION.SDK_INT >= 21) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
float x = PixelUtil.toPixelFromDIP(args.getDouble(0));
float y = PixelUtil.toPixelFromDIP(args.getDouble(1));
root.drawableHotspotChanged(x, y);
@@ -297,24 +313,4 @@
parent.removeAllViews();
}
}
-
- @Override
- public void startViewTransition(ReactViewGroup parent, View view) {
- boolean removeClippedSubviews = parent.getRemoveClippedSubviews();
- if (removeClippedSubviews) {
- parent.startViewTransitionWithSubviewClippingEnabled(view);
- } else {
- parent.startViewTransition(view);
- }
- }
-
- @Override
- public void endViewTransition(ReactViewGroup parent, View view) {
- boolean removeClippedSubviews = parent.getRemoveClippedSubviews();
- if (removeClippedSubviews) {
- parent.endViewTransitionWithSubviewClippingEnabled(view);
- } else {
- parent.endViewTransition(view);
- }
- }
}

ReactAndroid/src/main/java/com/facebook/react/views/viewpager/BUCK

@@ -11,6 +11,7 @@
"PUBLIC",
],
deps = [
+ 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"),

ReactAndroid/src/main/java/com/facebook/react/views/viewpager/PageScrollEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/viewpager/PageScrollStateChangedEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/viewpager/PageSelectedEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/viewpager/ReactViewPager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,10 +9,10 @@
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
-import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import com.facebook.common.logging.FLog;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.common.ReactConstants;
import com.facebook.react.uimanager.UIManagerModule;
@@ -185,7 +185,7 @@
// Log and ignore the error. This seems to be a bug in the android SDK and
// this is the commonly accepted workaround.
// https://tinyurl.com/mw6qkod (Stack Overflow)
- Log.w(ReactConstants.TAG, "Error intercepting touch event.", e);
+ FLog.w(ReactConstants.TAG, "Error intercepting touch event.", e);
}
return false;
@@ -197,7 +197,16 @@
return false;
}
+ try {
return super.onTouchEvent(ev);
+ } catch (IllegalArgumentException e) {
+ // Log and ignore the error. This seems to be a bug in the android SDK and
+ // this is the commonly accepted workaround.
+ // https://fburl.com/5d3iw7d9
+ FLog.w(ReactConstants.TAG, "Error handling touch event.", e);
+ }
+
+ return false;
}
public void setCurrentItemFromJs(int item, boolean animated) {

ReactAndroid/src/main/java/com/facebook/react/views/viewpager/ReactViewPagerManager.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -28,7 +28,7 @@
@ReactModule(name = ReactViewPagerManager.REACT_CLASS)
public class ReactViewPagerManager extends ViewGroupManager<ReactViewPager> {
- protected static final String REACT_CLASS = "AndroidViewPager";
+ public static final String REACT_CLASS = "AndroidViewPager";
public static final int COMMAND_SET_PAGE = 1;
public static final int COMMAND_SET_PAGE_WITHOUT_ANIMATION = 2;

ReactAndroid/src/main/java/com/facebook/react/views/webview/events/TopLoadingErrorEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/webview/events/TopLoadingFinishEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/webview/events/TopLoadingStartEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/webview/events/TopMessageEvent.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java

@@ -1,21 +1,23 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
+ * <p>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.views.webview;
import android.annotation.TargetApi;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.graphics.Bitmap;
import android.graphics.Picture;
import android.net.Uri;
import android.os.Build;
import android.text.TextUtils;
+import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.webkit.ConsoleMessage;
import android.webkit.CookieManager;
@@ -50,6 +52,7 @@
import com.facebook.react.views.webview.events.TopLoadingStartEvent;
import com.facebook.react.views.webview.events.TopMessageEvent;
import java.io.UnsupportedEncodingException;
+import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
@@ -65,28 +68,20 @@
/**
* Manages instances of {@link WebView}
*
- * Can accept following commands:
- * - GO_BACK
- * - GO_FORWARD
- * - RELOAD
+ * <p>Can accept following commands: - GO_BACK - GO_FORWARD - RELOAD
*
- * {@link WebView} instances could emit following direct events:
- * - topLoadingFinish
- * - topLoadingStart
- * - topLoadingError
+ * <p>{@link WebView} instances could emit following direct events: - topLoadingFinish -
+ * topLoadingStart - topLoadingError
*
- * Each event will carry the following properties:
- * - target - view's react tag
- * - url - url set for the webview
- * - loading - whether webview is in a loading state
- * - title - title of the current page
- * - canGoBack - boolean, whether there is anything on a history stack to go back
- * - canGoForward - boolean, whether it is possible to request GO_FORWARD command
+ * <p>Each event will carry the following properties: - target - view's react tag - url - url set
+ * for the webview - loading - whether webview is in a loading state - title - title of the current
+ * page - canGoBack - boolean, whether there is anything on a history stack to go back -
+ * canGoForward - boolean, whether it is possible to request GO_FORWARD command
*/
@ReactModule(name = ReactWebViewManager.REACT_CLASS)
public class ReactWebViewManager extends SimpleViewManager<WebView> {
- protected static final String REACT_CLASS = "RCTWebView";
+ public static final String REACT_CLASS = "RCTWebView";
protected static final String HTML_ENCODING = "UTF-8";
protected static final String HTML_MIME_TYPE = "text/html";
@@ -105,6 +100,9 @@
// state and release page resources (including any running JavaScript).
protected static final String BLANK_URL = "about:blank";
+ // Intent urls are a type of deeplinks which start with: intent://
+ private static final String INTENT_URL_PREFIX = "intent://";
+
protected WebViewConfig mWebViewConfig;
protected @Nullable WebView.PictureListener mPictureListener;
@@ -132,10 +130,7 @@
mLastLoadFailed = false;
dispatchEvent(
- webView,
- new TopLoadingStartEvent(
- webView.getId(),
- createWebViewEvent(webView, url)));
+ webView, new TopLoadingStartEvent(webView.getId(), createWebViewEvent(webView, url)));
}
@Override
@@ -144,8 +139,7 @@
// url blacklisting
if (mUrlPrefixesForDefaultIntent != null && mUrlPrefixesForDefaultIntent.size() > 0) {
- ArrayList<Object> urlPrefixesForDefaultIntent =
- mUrlPrefixesForDefaultIntent.toArrayList();
+ ArrayList<Object> urlPrefixesForDefaultIntent = mUrlPrefixesForDefaultIntent.toArrayList();
for (Object urlPrefix : urlPrefixesForDefaultIntent) {
if (url.startsWith((String) urlPrefix)) {
launchIntent(view.getContext(), url);
@@ -163,8 +157,38 @@
}
private void launchIntent(Context context, String url) {
+ Intent intent = null;
+
+ // URLs starting with 'intent://' require special handling.
+ if (url.startsWith(INTENT_URL_PREFIX)) {
+ try {
+ intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
+ } catch (URISyntaxException e) {
+ FLog.e(ReactConstants.TAG, "Can't parse intent:// URI", e);
+ }
+ }
+
+ if (intent != null) {
+ // This is needed to prevent security issue where non-exported activities from the same process can be started with intent:// URIs.
+ // See: T10607927/S136245
+ intent.addCategory(Intent.CATEGORY_BROWSABLE);
+ intent.setComponent(null);
+ intent.setSelector(null);
+
+ PackageManager packageManager = context.getPackageManager();
+ ResolveInfo info = packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+ if (info != null) {
+ // App is installed.
+ context.startActivity(intent);
+ } else {
+ String fallbackUrl = intent.getStringExtra("browser_fallback_url");
+ intent = new Intent(Intent.ACTION_VIEW, Uri.parse(fallbackUrl));
+ }
+ } else {
+ intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+ }
+
try {
- Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addCategory(Intent.CATEGORY_BROWSABLE);
context.startActivity(intent);
@@ -188,10 +212,7 @@
@Override
public void onReceivedError(
- WebView webView,
- int errorCode,
- String description,
- String failingUrl) {
+ WebView webView, int errorCode, String description, String failingUrl) {
super.onReceivedError(webView, errorCode, description, failingUrl);
mLastLoadFailed = true;
@@ -203,17 +224,12 @@
eventData.putDouble("code", errorCode);
eventData.putString("description", description);
- dispatchEvent(
- webView,
- new TopLoadingErrorEvent(webView.getId(), eventData));
+ dispatchEvent(webView, new TopLoadingErrorEvent(webView.getId(), eventData));
}
protected void emitFinishEvent(WebView webView, String url) {
dispatchEvent(
- webView,
- new TopLoadingFinishEvent(
- webView.getId(),
- createWebViewEvent(webView, url)));
+ webView, new TopLoadingFinishEvent(webView.getId(), createWebViewEvent(webView, url)));
}
protected WritableMap createWebViewEvent(WebView webView, String url) {
@@ -263,9 +279,8 @@
/**
* WebView must be created with an context of the current activity
*
- * Activity Context is required for creation of dialogs internally by WebView
- * Reactive Native needed for access to ReactNative internal system functionality
- *
+ * <p>Activity Context is required for creation of dialogs internally by WebView Reactive Native
+ * needed for access to ReactNative internal system functionality
*/
public ReactWebView(ThemedReactContext reactContext) {
super(reactContext);
@@ -289,7 +304,7 @@
@Override
public void setWebViewClient(WebViewClient client) {
super.setWebViewClient(client);
- mReactWebViewClient = (ReactWebViewClient)client;
+ mReactWebViewClient = (ReactWebViewClient) client;
}
public @Nullable ReactWebViewClient getReactWebViewClient() {
@@ -333,9 +348,9 @@
}
public void callInjectedJavaScript() {
- if (getSettings().getJavaScriptEnabled() &&
- injectedJS != null &&
- !TextUtils.isEmpty(injectedJS)) {
+ if (getSettings().getJavaScriptEnabled()
+ && injectedJS != null
+ && !TextUtils.isEmpty(injectedJS)) {
evaluateJavascriptWithFallback("(function() {\n" + injectedJS + ";\n})();");
}
}
@@ -344,23 +359,30 @@
if (messagingEnabled) {
if (ReactBuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// See isNative in lodash
- String testPostMessageNative = "String(window.postMessage) === String(Object.hasOwnProperty).replace('hasOwnProperty', 'postMessage')";
- evaluateJavascript(testPostMessageNative, new ValueCallback<String>() {
+ String testPostMessageNative =
+ "String(window.postMessage) === String(Object.hasOwnProperty).replace('hasOwnProperty', 'postMessage')";
+ evaluateJavascript(
+ testPostMessageNative,
+ new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
if (value.equals("true")) {
- FLog.w(ReactConstants.TAG, "Setting onMessage on a WebView overrides existing values of window.postMessage, but a previous value was defined");
+ FLog.w(
+ ReactConstants.TAG,
+ "Setting onMessage on a WebView overrides existing values of window.postMessage, but a previous value was defined");
}
}
});
}
- evaluateJavascriptWithFallback("(" +
- "window.originalPostMessage = window.postMessage," +
- "window.postMessage = function(data) {" +
- BRIDGE_NAME + ".postMessage(String(data));" +
- "}" +
- ")");
+ evaluateJavascriptWithFallback(
+ "("
+ + "window.originalPostMessage = window.postMessage,"
+ + "window.postMessage = function(data) {"
+ + BRIDGE_NAME
+ + ".postMessage(String(data));"
+ + "}"
+ + ")");
}
}
@@ -375,9 +397,9 @@
}
public ReactWebViewManager() {
- mWebViewConfig = new WebViewConfig() {
- public void configWebView(WebView webView) {
- }
+ mWebViewConfig =
+ new WebViewConfig() {
+ public void configWebView(WebView webView) {}
};
}
@@ -398,7 +420,8 @@
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
protected WebView createViewInstance(ThemedReactContext reactContext) {
ReactWebView webView = createReactWebViewInstance(reactContext);
- webView.setWebChromeClient(new WebChromeClient() {
+ webView.setWebChromeClient(
+ new WebChromeClient() {
@Override
public boolean onConsoleMessage(ConsoleMessage message) {
if (ReactBuildConfig.DEBUG) {
@@ -409,7 +432,8 @@
}
@Override
- public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
+ public void onGeolocationPermissionsShowPrompt(
+ String origin, GeolocationPermissions.Callback callback) {
callback.invoke(origin, true, false);
}
});
@@ -422,16 +446,12 @@
settings.setAllowFileAccess(false);
settings.setAllowContentAccess(false);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
settings.setAllowFileAccessFromFileURLs(false);
setAllowUniversalAccessFromFileURLs(webView, false);
- }
setMixedContentMode(webView, "never");
// Fixes broken full-screen modals/galleries due to body height being 0.
- webView.setLayoutParams(
- new LayoutParams(LayoutParams.MATCH_PARENT,
- LayoutParams.MATCH_PARENT));
+ webView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
setGeolocationEnabled(webView, false);
if (ReactBuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
@@ -437,10 +457,22 @@
if (ReactBuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}
-
return webView;
}
+ @ReactProp(name = "hardwareAccelerationEnabledExperimental", defaultBoolean = true)
+ public void sethardwareAccelerationEnabledExperimental(WebView view, boolean enabled) {
+ // Hardware acceleration can not be enabled at view level but it can be disabled
+ // see: https://developer.android.com/guide/topics/graphics/hardware-accel
+ //
+ // Disabling hardware acceleration is sometimes required to workaround chromium bugs:
+ // https://bugs.chromium.org/p/chromium/issues/detail?id=501901
+ //
+ if (!enabled) {
+ view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+ }
+ }
+
@ReactProp(name = "javaScriptEnabled")
public void setJavaScriptEnabled(WebView view, boolean enabled) {
view.getSettings().setJavaScriptEnabled(enabled);
@@ -472,6 +504,7 @@
}
@ReactProp(name = "mediaPlaybackRequiresUserAction")
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public void setMediaPlaybackRequiresUserAction(WebView view, boolean requires) {
view.getSettings().setMediaPlaybackRequiresUserGesture(requires);
}
@@ -517,7 +550,7 @@
}
if (source.hasKey("method")) {
String method = source.getString("method");
- if (method.equals(HTTP_METHOD_POST)) {
+ if (method.equalsIgnoreCase(HTTP_METHOD_POST)) {
byte[] postData = null;
if (source.hasKey("body")) {
String body = source.getString("body");
@@ -580,8 +613,7 @@
@ReactProp(name = "urlPrefixesForDefaultIntent")
public void setUrlPrefixesForDefaultIntent(
- WebView view,
- @Nullable ReadableArray urlPrefixesForDefaultIntent) {
+ WebView view, @Nullable ReadableArray urlPrefixesForDefaultIntent) {
ReactWebViewClient client = ((ReactWebView) view).getReactWebViewClient();
if (client != null && urlPrefixesForDefaultIntent != null) {
client.setUrlPrefixesForDefaultIntent(urlPrefixesForDefaultIntent);
@@ -589,27 +621,21 @@
}
@ReactProp(name = "allowFileAccess")
- public void setAllowFileAccess(
- WebView view,
- @Nullable Boolean allowFileAccess) {
+ public void setAllowFileAccess(WebView view, @Nullable Boolean allowFileAccess) {
view.getSettings().setAllowFileAccess(allowFileAccess != null && allowFileAccess);
}
@ReactProp(name = "geolocationEnabled")
- public void setGeolocationEnabled(
- WebView view,
- @Nullable Boolean isGeolocationEnabled) {
+ public void setGeolocationEnabled(WebView view, @Nullable Boolean isGeolocationEnabled) {
view.getSettings().setGeolocationEnabled(isGeolocationEnabled != null && isGeolocationEnabled);
}
@ReactProp(name = "originWhitelist")
- public void setOriginWhitelist(
- WebView view,
- @Nullable ReadableArray originWhitelist) {
+ public void setOriginWhitelist(WebView view, @Nullable ReadableArray originWhitelist) {
ReactWebViewClient client = ((ReactWebView) view).getReactWebViewClient();
if (client != null && originWhitelist != null) {
List<Pattern> whiteList = new LinkedList<>();
- for (int i = 0 ; i < originWhitelist.size() ; i++) {
+ for (int i = 0; i < originWhitelist.size(); i++) {
whiteList.add(Pattern.compile(originWhitelist.getString(i)));
}
client.setOriginWhitelist(whiteList);
@@ -630,8 +656,7 @@
"reload", COMMAND_RELOAD,
"stopLoading", COMMAND_STOP_LOADING,
"postMessage", COMMAND_POST_MESSAGE,
- "injectJavaScript", COMMAND_INJECT_JAVASCRIPT
- );
+ "injectJavaScript", COMMAND_INJECT_JAVASCRIPT);
}
@Override
@@ -654,17 +679,20 @@
ReactWebView reactWebView = (ReactWebView) root;
JSONObject eventInitDict = new JSONObject();
eventInitDict.put("data", args.getString(0));
- reactWebView.evaluateJavascriptWithFallback("(function () {" +
- "var event;" +
- "var data = " + eventInitDict.toString() + ";" +
- "try {" +
- "event = new MessageEvent('message', data);" +
- "} catch (e) {" +
- "event = document.createEvent('MessageEvent');" +
- "event.initMessageEvent('message', true, true, data.data, data.origin, data.lastEventId, data.source);" +
- "}" +
- "document.dispatchEvent(event);" +
- "})();");
+ reactWebView.evaluateJavascriptWithFallback(
+ "(function () {"
+ + "var event;"
+ + "var data = "
+ + eventInitDict.toString()
+ + ";"
+ + "try {"
+ + "event = new MessageEvent('message', data);"
+ + "} catch (e) {"
+ + "event = document.createEvent('MessageEvent');"
+ + "event.initMessageEvent('message', true, true, data.data, data.origin, data.lastEventId, data.source);"
+ + "}"
+ + "document.dispatchEvent(event);"
+ + "})();");
} catch (JSONException e) {
throw new RuntimeException(e);
}
@@ -679,21 +707,21 @@
@Override
public void onDropViewInstance(WebView webView) {
super.onDropViewInstance(webView);
- ((ThemedReactContext) webView.getContext()).removeLifecycleEventListener((ReactWebView) webView);
+ ((ThemedReactContext) webView.getContext())
+ .removeLifecycleEventListener((ReactWebView) webView);
((ReactWebView) webView).cleanupCallbacksAndDestroy();
}
protected WebView.PictureListener getPictureListener() {
if (mPictureListener == null) {
- mPictureListener = new WebView.PictureListener() {
+ mPictureListener =
+ new WebView.PictureListener() {
@Override
public void onNewPicture(WebView webView, Picture picture) {
dispatchEvent(
webView,
new ContentSizeChangeEvent(
- webView.getId(),
- webView.getWidth(),
- webView.getContentHeight()));
+ webView.getId(), webView.getWidth(), webView.getContentHeight()));
}
};
}

ReactAndroid/src/main/java/com/facebook/react/views/webview/WebViewConfig.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/systrace/Systrace.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -55,13 +55,13 @@
}
public static void beginSection(long tag, final String sectionName) {
- if (Build.VERSION.SDK_INT >= 18) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
Trace.beginSection(sectionName);
}
}
public static void endSection(long tag) {
- if (Build.VERSION.SDK_INT >= 18) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
Trace.endSection();
}
}

ReactAndroid/src/main/java/com/facebook/systrace/SystraceMessage.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/systrace/TraceListener.java

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/java/com/facebook/yoga/YogaAlign.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

ReactAndroid/src/main/java/com/facebook/yoga/YogaBaselineFunction.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/yoga/YogaConfig.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
@@ -54,6 +54,11 @@
jni_YGConfigSetUseWebDefaults(mNativePointer, useWebDefaults);
}
+ private native void jni_YGConfigSetPrintTreeFlag(long nativePointer, boolean enable);
+ public void setPrintTreeFlag(boolean enable) {
+ jni_YGConfigSetPrintTreeFlag(mNativePointer, enable);
+ }
+
private native void jni_YGConfigSetPointScaleFactor(long nativePointer, float pixelsInPoint);
public void setPointScaleFactor(float pixelsInPoint) {
jni_YGConfigSetPointScaleFactor(mNativePointer, pixelsInPoint);

ReactAndroid/src/main/java/com/facebook/yoga/YogaConstants.java

@@ -1,38 +1,24 @@
-/*
- * Copyright (c) 2014-present, Facebook, Inc.
+/**
+ * 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.yoga;
public class YogaConstants {
- /**
- * Large positive number signifies that the property(float) is undefined. Earlier we used to have
- * YGundefined as NAN, but the downside of this is that we can't use -ffast-math compiler flag as
- * it assumes all floating-point calculation involve and result into finite numbers. For more
- * information regarding -ffast-math compiler flag in clang, have a look at
- * https://clang.llvm.org/docs/UsersManual.html#cmdoption-ffast-math
- */
- public static final float UNDEFINED = (float) (10E20);
+ public static final float UNDEFINED = Float.NaN;
public static boolean isUndefined(float value) {
- // Value of a float in the case of it being not defined is 10.1E20. Earlier it used to be NAN,
- // the benefit of which
- // was that if NAN is involved in any mathematical expression the result was NAN. But since we
- // want to have `-ffast-math`
- // flag being used by compiler which assumes that the floating point values are not NAN and Inf,
- // we represent YGUndefined as 10.1E20.
- // But now if YGUndefined is involved in any mathematical operations this value(10.1E20) would
- // change.
- // So the following check makes sure that if the value is outside a range (-10E8, 10E8) then it
- // is undefined.
- return (Float.compare(value, (float) 10E8) >= 0 || Float.compare(value, (float) -10E8) <= 0);
+ return Float.compare(value, UNDEFINED) == 0;
}
public static boolean isUndefined(YogaValue value) {
return value.unit == YogaUnit.UNDEFINED;
}
+
+ public static float getUndefined() {
+ return UNDEFINED;
+ }
}

ReactAndroid/src/main/java/com/facebook/yoga/YogaDimension.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

ReactAndroid/src/main/java/com/facebook/yoga/YogaDirection.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

ReactAndroid/src/main/java/com/facebook/yoga/YogaDisplay.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

ReactAndroid/src/main/java/com/facebook/yoga/YogaEdge.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

ReactAndroid/src/main/java/com/facebook/yoga/YogaExperimentalFeature.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

ReactAndroid/src/main/java/com/facebook/yoga/YogaFlexDirection.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

ReactAndroid/src/main/java/com/facebook/yoga/YogaJustify.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

ReactAndroid/src/main/java/com/facebook/yoga/YogaLogger.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/yoga/YogaLogLevel.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

ReactAndroid/src/main/java/com/facebook/yoga/YogaMeasureFunction.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/yoga/YogaMeasureMode.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

ReactAndroid/src/main/java/com/facebook/yoga/YogaMeasureOutput.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeCloneFunction.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java

@@ -1,11 +1,9 @@
-/*
- * Copyright (c) 2014-present, Facebook, Inc.
+/**
+ * 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.yoga;
import com.facebook.proguard.annotations.DoNotStrip;
@@ -117,7 +115,7 @@
}
}
- private native void jni_YGNodeReset(long nativePointer);
+ private static native void jni_YGNodeReset(long nativePointer);
public void reset() {
mEdgeSetFlag = 0;
mHasSetPosition = false;
@@ -160,7 +158,8 @@
return mChildren.get(i);
}
- private native void jni_YGNodeInsertChild(long nativePointer, long childPointer, int index);
+ private static native void jni_YGNodeInsertChild(long nativePointer, long childPointer, int index);
+
public void addChildAt(YogaNode child, int i) {
if (child.mOwner != null) {
throw new IllegalStateException("Child already has a parent, it must be removed first.");
@@ -174,18 +173,19 @@
jni_YGNodeInsertChild(mNativePointer, child.mNativePointer, i);
}
- private native void jni_YGNodeInsertSharedChild(long nativePointer, long childPointer, int index);
+ private static native void jni_YGNodeSetIsReferenceBaseline(long nativePointer, boolean isReferenceBaseline);
- public void addSharedChildAt(YogaNode child, int i) {
- if (mChildren == null) {
- mChildren = new ArrayList<>(4);
+ public void setIsReferenceBaseline(boolean isReferenceBaseline) {
+ jni_YGNodeSetIsReferenceBaseline(mNativePointer, isReferenceBaseline);
}
- mChildren.add(i, child);
- child.mOwner = null;
- jni_YGNodeInsertSharedChild(mNativePointer, child.mNativePointer, i);
+
+ private static native boolean jni_YGNodeIsReferenceBaseline(long nativePointer);
+
+ public boolean isReferenceBaseline() {
+ return jni_YGNodeIsReferenceBaseline(mNativePointer);
}
- private native void jni_YGNodeSetOwner(long nativePointer, long newOwnerNativePointer);
+ private static native void jni_YGNodeSetOwner(long nativePointer, long newOwnerNativePointer);
private native long jni_YGNodeClone(long nativePointer, Object newNode);
@@ -197,7 +197,7 @@
if (mChildren != null) {
for (YogaNode child : mChildren) {
- child.jni_YGNodeSetOwner(child.mNativePointer, 0);
+ YogaNode.jni_YGNodeSetOwner(child.mNativePointer, 0);
child.mOwner = null;
}
}
@@ -232,14 +232,14 @@
}
}
- private native void jni_YGNodeClearChildren(long nativePointer);
+ private static native void jni_YGNodeClearChildren(long nativePointer);
private void clearChildren() {
mChildren = null;
jni_YGNodeClearChildren(mNativePointer);
}
- private native void jni_YGNodeRemoveChild(long nativePointer, long childPointer);
+ private static native void jni_YGNodeRemoveChild(long nativePointer, long childPointer);
public YogaNode removeChildAt(int i) {
if (mChildren == null) {
throw new IllegalStateException(
@@ -275,7 +275,7 @@
return mChildren == null ? -1 : mChildren.indexOf(child);
}
- private native void jni_YGNodeCalculateLayout(long nativePointer, float width, float height);
+ private static native void jni_YGNodeCalculateLayout(long nativePointer, float width, float height);
public void calculateLayout(float width, float height) {
jni_YGNodeCalculateLayout(mNativePointer, width, height);
}
@@ -284,23 +284,23 @@
return mHasNewLayout;
}
- private native void jni_YGNodeMarkDirty(long nativePointer);
+ private static native void jni_YGNodeMarkDirty(long nativePointer);
public void dirty() {
jni_YGNodeMarkDirty(mNativePointer);
}
- private native void jni_YGNodeMarkDirtyAndPropogateToDescendants(long nativePointer);
+ private static native void jni_YGNodeMarkDirtyAndPropogateToDescendants(long nativePointer);
public void dirtyAllDescendants() {
jni_YGNodeMarkDirtyAndPropogateToDescendants(mNativePointer);
}
- private native boolean jni_YGNodeIsDirty(long nativePointer);
+ private static native boolean jni_YGNodeIsDirty(long nativePointer);
public boolean isDirty() {
return jni_YGNodeIsDirty(mNativePointer);
}
- private native void jni_YGNodeCopyStyle(long dstNativePointer, long srcNativePointer);
+ private static native void jni_YGNodeCopyStyle(long dstNativePointer, long srcNativePointer);
public void copyStyle(YogaNode srcNode) {
jni_YGNodeCopyStyle(mNativePointer, srcNode.mNativePointer);
}
@@ -309,147 +309,147 @@
mHasNewLayout = false;
}
- private native int jni_YGNodeStyleGetDirection(long nativePointer);
+ private static native int jni_YGNodeStyleGetDirection(long nativePointer);
public YogaDirection getStyleDirection() {
return YogaDirection.fromInt(jni_YGNodeStyleGetDirection(mNativePointer));
}
- private native void jni_YGNodeStyleSetDirection(long nativePointer, int direction);
+ private static native void jni_YGNodeStyleSetDirection(long nativePointer, int direction);
public void setDirection(YogaDirection direction) {
jni_YGNodeStyleSetDirection(mNativePointer, direction.intValue());
}
- private native int jni_YGNodeStyleGetFlexDirection(long nativePointer);
+ private static native int jni_YGNodeStyleGetFlexDirection(long nativePointer);
public YogaFlexDirection getFlexDirection() {
return YogaFlexDirection.fromInt(jni_YGNodeStyleGetFlexDirection(mNativePointer));
}
- private native void jni_YGNodeStyleSetFlexDirection(long nativePointer, int flexDirection);
+ private static native void jni_YGNodeStyleSetFlexDirection(long nativePointer, int flexDirection);
public void setFlexDirection(YogaFlexDirection flexDirection) {
jni_YGNodeStyleSetFlexDirection(mNativePointer, flexDirection.intValue());
}
- private native int jni_YGNodeStyleGetJustifyContent(long nativePointer);
+ private static native int jni_YGNodeStyleGetJustifyContent(long nativePointer);
public YogaJustify getJustifyContent() {
return YogaJustify.fromInt(jni_YGNodeStyleGetJustifyContent(mNativePointer));
}
- private native void jni_YGNodeStyleSetJustifyContent(long nativePointer, int justifyContent);
+ private static native void jni_YGNodeStyleSetJustifyContent(long nativePointer, int justifyContent);
public void setJustifyContent(YogaJustify justifyContent) {
jni_YGNodeStyleSetJustifyContent(mNativePointer, justifyContent.intValue());
}
- private native int jni_YGNodeStyleGetAlignItems(long nativePointer);
+ private static native int jni_YGNodeStyleGetAlignItems(long nativePointer);
public YogaAlign getAlignItems() {
return YogaAlign.fromInt(jni_YGNodeStyleGetAlignItems(mNativePointer));
}
- private native void jni_YGNodeStyleSetAlignItems(long nativePointer, int alignItems);
+ private static native void jni_YGNodeStyleSetAlignItems(long nativePointer, int alignItems);
public void setAlignItems(YogaAlign alignItems) {
jni_YGNodeStyleSetAlignItems(mNativePointer, alignItems.intValue());
}
- private native int jni_YGNodeStyleGetAlignSelf(long nativePointer);
+ private static native int jni_YGNodeStyleGetAlignSelf(long nativePointer);
public YogaAlign getAlignSelf() {
return YogaAlign.fromInt(jni_YGNodeStyleGetAlignSelf(mNativePointer));
}
- private native void jni_YGNodeStyleSetAlignSelf(long nativePointer, int alignSelf);
+ private static native void jni_YGNodeStyleSetAlignSelf(long nativePointer, int alignSelf);
public void setAlignSelf(YogaAlign alignSelf) {
jni_YGNodeStyleSetAlignSelf(mNativePointer, alignSelf.intValue());
}
- private native int jni_YGNodeStyleGetAlignContent(long nativePointer);
+ private static native int jni_YGNodeStyleGetAlignContent(long nativePointer);
public YogaAlign getAlignContent() {
return YogaAlign.fromInt(jni_YGNodeStyleGetAlignContent(mNativePointer));
}
- private native void jni_YGNodeStyleSetAlignContent(long nativePointer, int alignContent);
+ private static native void jni_YGNodeStyleSetAlignContent(long nativePointer, int alignContent);
public void setAlignContent(YogaAlign alignContent) {
jni_YGNodeStyleSetAlignContent(mNativePointer, alignContent.intValue());
}
- private native int jni_YGNodeStyleGetPositionType(long nativePointer);
+ private static native int jni_YGNodeStyleGetPositionType(long nativePointer);
public YogaPositionType getPositionType() {
return YogaPositionType.fromInt(jni_YGNodeStyleGetPositionType(mNativePointer));
}
- private native void jni_YGNodeStyleSetPositionType(long nativePointer, int positionType);
+ private static native void jni_YGNodeStyleSetPositionType(long nativePointer, int positionType);
public void setPositionType(YogaPositionType positionType) {
jni_YGNodeStyleSetPositionType(mNativePointer, positionType.intValue());
}
- private native void jni_YGNodeStyleSetFlexWrap(long nativePointer, int wrapType);
+ private static native void jni_YGNodeStyleSetFlexWrap(long nativePointer, int wrapType);
public void setWrap(YogaWrap flexWrap) {
jni_YGNodeStyleSetFlexWrap(mNativePointer, flexWrap.intValue());
}
- private native int jni_YGNodeStyleGetOverflow(long nativePointer);
+ private static native int jni_YGNodeStyleGetOverflow(long nativePointer);
public YogaOverflow getOverflow() {
return YogaOverflow.fromInt(jni_YGNodeStyleGetOverflow(mNativePointer));
}
- private native void jni_YGNodeStyleSetOverflow(long nativePointer, int overflow);
+ private static native void jni_YGNodeStyleSetOverflow(long nativePointer, int overflow);
public void setOverflow(YogaOverflow overflow) {
jni_YGNodeStyleSetOverflow(mNativePointer, overflow.intValue());
}
- private native int jni_YGNodeStyleGetDisplay(long nativePointer);
+ private static native int jni_YGNodeStyleGetDisplay(long nativePointer);
public YogaDisplay getDisplay() {
return YogaDisplay.fromInt(jni_YGNodeStyleGetDisplay(mNativePointer));
}
- private native void jni_YGNodeStyleSetDisplay(long nativePointer, int display);
+ private static native void jni_YGNodeStyleSetDisplay(long nativePointer, int display);
public void setDisplay(YogaDisplay display) {
jni_YGNodeStyleSetDisplay(mNativePointer, display.intValue());
}
- private native void jni_YGNodeStyleSetFlex(long nativePointer, float flex);
+ private static native void jni_YGNodeStyleSetFlex(long nativePointer, float flex);
public void setFlex(float flex) {
jni_YGNodeStyleSetFlex(mNativePointer, flex);
}
- private native float jni_YGNodeStyleGetFlexGrow(long nativePointer);
+ private static native float jni_YGNodeStyleGetFlexGrow(long nativePointer);
public float getFlexGrow() {
return jni_YGNodeStyleGetFlexGrow(mNativePointer);
}
- private native void jni_YGNodeStyleSetFlexGrow(long nativePointer, float flexGrow);
+ private static native void jni_YGNodeStyleSetFlexGrow(long nativePointer, float flexGrow);
public void setFlexGrow(float flexGrow) {
jni_YGNodeStyleSetFlexGrow(mNativePointer, flexGrow);
}
- private native float jni_YGNodeStyleGetFlexShrink(long nativePointer);
+ private static native float jni_YGNodeStyleGetFlexShrink(long nativePointer);
public float getFlexShrink() {
return jni_YGNodeStyleGetFlexShrink(mNativePointer);
}
- private native void jni_YGNodeStyleSetFlexShrink(long nativePointer, float flexShrink);
+ private static native void jni_YGNodeStyleSetFlexShrink(long nativePointer, float flexShrink);
public void setFlexShrink(float flexShrink) {
jni_YGNodeStyleSetFlexShrink(mNativePointer, flexShrink);
}
- private native Object jni_YGNodeStyleGetFlexBasis(long nativePointer);
+ private static native Object jni_YGNodeStyleGetFlexBasis(long nativePointer);
public YogaValue getFlexBasis() {
return (YogaValue) jni_YGNodeStyleGetFlexBasis(mNativePointer);
}
- private native void jni_YGNodeStyleSetFlexBasis(long nativePointer, float flexBasis);
+ private static native void jni_YGNodeStyleSetFlexBasis(long nativePointer, float flexBasis);
public void setFlexBasis(float flexBasis) {
jni_YGNodeStyleSetFlexBasis(mNativePointer, flexBasis);
}
- private native void jni_YGNodeStyleSetFlexBasisPercent(long nativePointer, float percent);
+ private static native void jni_YGNodeStyleSetFlexBasisPercent(long nativePointer, float percent);
public void setFlexBasisPercent(float percent) {
jni_YGNodeStyleSetFlexBasisPercent(mNativePointer, percent);
}
- private native void jni_YGNodeStyleSetFlexBasisAuto(long nativePointer);
+ private static native void jni_YGNodeStyleSetFlexBasisAuto(long nativePointer);
public void setFlexBasisAuto() {
jni_YGNodeStyleSetFlexBasisAuto(mNativePointer);
}
- private native Object jni_YGNodeStyleGetMargin(long nativePointer, int edge);
+ private static native Object jni_YGNodeStyleGetMargin(long nativePointer, int edge);
public YogaValue getMargin(YogaEdge edge) {
if (!((mEdgeSetFlag & MARGIN) == MARGIN)) {
return YogaValue.UNDEFINED;
@@ -457,25 +457,25 @@
return (YogaValue) jni_YGNodeStyleGetMargin(mNativePointer, edge.intValue());
}
- private native void jni_YGNodeStyleSetMargin(long nativePointer, int edge, float margin);
+ private static native void jni_YGNodeStyleSetMargin(long nativePointer, int edge, float margin);
public void setMargin(YogaEdge edge, float margin) {
mEdgeSetFlag |= MARGIN;
jni_YGNodeStyleSetMargin(mNativePointer, edge.intValue(), margin);
}
- private native void jni_YGNodeStyleSetMarginPercent(long nativePointer, int edge, float percent);
+ private static native void jni_YGNodeStyleSetMarginPercent(long nativePointer, int edge, float percent);
public void setMarginPercent(YogaEdge edge, float percent) {
mEdgeSetFlag |= MARGIN;
jni_YGNodeStyleSetMarginPercent(mNativePointer, edge.intValue(), percent);
}
- private native void jni_YGNodeStyleSetMarginAuto(long nativePointer, int edge);
+ private static native void jni_YGNodeStyleSetMarginAuto(long nativePointer, int edge);
public void setMarginAuto(YogaEdge edge) {
mEdgeSetFlag |= MARGIN;
jni_YGNodeStyleSetMarginAuto(mNativePointer, edge.intValue());
}
- private native Object jni_YGNodeStyleGetPadding(long nativePointer, int edge);
+ private static native Object jni_YGNodeStyleGetPadding(long nativePointer, int edge);
public YogaValue getPadding(YogaEdge edge) {
if (!((mEdgeSetFlag & PADDING) == PADDING)) {
return YogaValue.UNDEFINED;
@@ -483,19 +483,19 @@
return (YogaValue) jni_YGNodeStyleGetPadding(mNativePointer, edge.intValue());
}
- private native void jni_YGNodeStyleSetPadding(long nativePointer, int edge, float padding);
+ private static native void jni_YGNodeStyleSetPadding(long nativePointer, int edge, float padding);
public void setPadding(YogaEdge edge, float padding) {
mEdgeSetFlag |= PADDING;
jni_YGNodeStyleSetPadding(mNativePointer, edge.intValue(), padding);
}
- private native void jni_YGNodeStyleSetPaddingPercent(long nativePointer, int edge, float percent);
+ private static native void jni_YGNodeStyleSetPaddingPercent(long nativePointer, int edge, float percent);
public void setPaddingPercent(YogaEdge edge, float percent) {
mEdgeSetFlag |= PADDING;
jni_YGNodeStyleSetPaddingPercent(mNativePointer, edge.intValue(), percent);
}
- private native float jni_YGNodeStyleGetBorder(long nativePointer, int edge);
+ private static native float jni_YGNodeStyleGetBorder(long nativePointer, int edge);
public float getBorder(YogaEdge edge) {
if (!((mEdgeSetFlag & BORDER) == BORDER)) {
return YogaConstants.UNDEFINED;
@@ -503,13 +503,13 @@
return jni_YGNodeStyleGetBorder(mNativePointer, edge.intValue());
}
- private native void jni_YGNodeStyleSetBorder(long nativePointer, int edge, float border);
+ private static native void jni_YGNodeStyleSetBorder(long nativePointer, int edge, float border);
public void setBorder(YogaEdge edge, float border) {
mEdgeSetFlag |= BORDER;
jni_YGNodeStyleSetBorder(mNativePointer, edge.intValue(), border);
}
- private native Object jni_YGNodeStyleGetPosition(long nativePointer, int edge);
+ private static native Object jni_YGNodeStyleGetPosition(long nativePointer, int edge);
public YogaValue getPosition(YogaEdge edge) {
if (!mHasSetPosition) {
return YogaValue.UNDEFINED;
@@ -517,124 +517,124 @@
return (YogaValue) jni_YGNodeStyleGetPosition(mNativePointer, edge.intValue());
}
- private native void jni_YGNodeStyleSetPosition(long nativePointer, int edge, float position);
+ private static native void jni_YGNodeStyleSetPosition(long nativePointer, int edge, float position);
public void setPosition(YogaEdge edge, float position) {
mHasSetPosition = true;
jni_YGNodeStyleSetPosition(mNativePointer, edge.intValue(), position);
}
- private native void jni_YGNodeStyleSetPositionPercent(long nativePointer, int edge, float percent);
+ private static native void jni_YGNodeStyleSetPositionPercent(long nativePointer, int edge, float percent);
public void setPositionPercent(YogaEdge edge, float percent) {
mHasSetPosition = true;
jni_YGNodeStyleSetPositionPercent(mNativePointer, edge.intValue(), percent);
}
- private native Object jni_YGNodeStyleGetWidth(long nativePointer);
+ private static native Object jni_YGNodeStyleGetWidth(long nativePointer);
public YogaValue getWidth() {
return (YogaValue) jni_YGNodeStyleGetWidth(mNativePointer);
}
- private native void jni_YGNodeStyleSetWidth(long nativePointer, float width);
+ private static native void jni_YGNodeStyleSetWidth(long nativePointer, float width);
public void setWidth(float width) {
jni_YGNodeStyleSetWidth(mNativePointer, width);
}
- private native void jni_YGNodeStyleSetWidthPercent(long nativePointer, float percent);
+ private static native void jni_YGNodeStyleSetWidthPercent(long nativePointer, float percent);
public void setWidthPercent(float percent) {
jni_YGNodeStyleSetWidthPercent(mNativePointer, percent);
}
- private native void jni_YGNodeStyleSetWidthAuto(long nativePointer);
+ private static native void jni_YGNodeStyleSetWidthAuto(long nativePointer);
public void setWidthAuto() {
jni_YGNodeStyleSetWidthAuto(mNativePointer);
}
- private native Object jni_YGNodeStyleGetHeight(long nativePointer);
+ private static native Object jni_YGNodeStyleGetHeight(long nativePointer);
public YogaValue getHeight() {
return (YogaValue) jni_YGNodeStyleGetHeight(mNativePointer);
}
- private native void jni_YGNodeStyleSetHeight(long nativePointer, float height);
+ private static native void jni_YGNodeStyleSetHeight(long nativePointer, float height);
public void setHeight(float height) {
jni_YGNodeStyleSetHeight(mNativePointer, height);
}
- private native void jni_YGNodeStyleSetHeightPercent(long nativePointer, float percent);
+ private static native void jni_YGNodeStyleSetHeightPercent(long nativePointer, float percent);
public void setHeightPercent(float percent) {
jni_YGNodeStyleSetHeightPercent(mNativePointer, percent);
}
- private native void jni_YGNodeStyleSetHeightAuto(long nativePointer);
+ private static native void jni_YGNodeStyleSetHeightAuto(long nativePointer);
public void setHeightAuto() {
jni_YGNodeStyleSetHeightAuto(mNativePointer);
}
- private native Object jni_YGNodeStyleGetMinWidth(long nativePointer);
+ private static native Object jni_YGNodeStyleGetMinWidth(long nativePointer);
public YogaValue getMinWidth() {
return (YogaValue) jni_YGNodeStyleGetMinWidth(mNativePointer);
}
- private native void jni_YGNodeStyleSetMinWidth(long nativePointer, float minWidth);
+ private static native void jni_YGNodeStyleSetMinWidth(long nativePointer, float minWidth);
public void setMinWidth(float minWidth) {
jni_YGNodeStyleSetMinWidth(mNativePointer, minWidth);
}
- private native void jni_YGNodeStyleSetMinWidthPercent(long nativePointer, float percent);
+ private static native void jni_YGNodeStyleSetMinWidthPercent(long nativePointer, float percent);
public void setMinWidthPercent(float percent) {
jni_YGNodeStyleSetMinWidthPercent(mNativePointer, percent);
}
- private native Object jni_YGNodeStyleGetMinHeight(long nativePointer);
+ private static native Object jni_YGNodeStyleGetMinHeight(long nativePointer);
public YogaValue getMinHeight() {
return (YogaValue) jni_YGNodeStyleGetMinHeight(mNativePointer);
}
- private native void jni_YGNodeStyleSetMinHeight(long nativePointer, float minHeight);
+ private static native void jni_YGNodeStyleSetMinHeight(long nativePointer, float minHeight);
public void setMinHeight(float minHeight) {
jni_YGNodeStyleSetMinHeight(mNativePointer, minHeight);
}
- private native void jni_YGNodeStyleSetMinHeightPercent(long nativePointer, float percent);
+ private static native void jni_YGNodeStyleSetMinHeightPercent(long nativePointer, float percent);
public void setMinHeightPercent(float percent) {
jni_YGNodeStyleSetMinHeightPercent(mNativePointer, percent);
}
- private native Object jni_YGNodeStyleGetMaxWidth(long nativePointer);
+ private static native Object jni_YGNodeStyleGetMaxWidth(long nativePointer);
public YogaValue getMaxWidth() {
return (YogaValue) jni_YGNodeStyleGetMaxWidth(mNativePointer);
}
- private native void jni_YGNodeStyleSetMaxWidth(long nativePointer, float maxWidth);
+ private static native void jni_YGNodeStyleSetMaxWidth(long nativePointer, float maxWidth);
public void setMaxWidth(float maxWidth) {
jni_YGNodeStyleSetMaxWidth(mNativePointer, maxWidth);
}
- private native void jni_YGNodeStyleSetMaxWidthPercent(long nativePointer, float percent);
+ private static native void jni_YGNodeStyleSetMaxWidthPercent(long nativePointer, float percent);
public void setMaxWidthPercent(float percent) {
jni_YGNodeStyleSetMaxWidthPercent(mNativePointer, percent);
}
- private native Object jni_YGNodeStyleGetMaxHeight(long nativePointer);
+ private static native Object jni_YGNodeStyleGetMaxHeight(long nativePointer);
public YogaValue getMaxHeight() {
return (YogaValue) jni_YGNodeStyleGetMaxHeight(mNativePointer);
}
- private native void jni_YGNodeStyleSetMaxHeight(long nativePointer, float maxheight);
+ private static native void jni_YGNodeStyleSetMaxHeight(long nativePointer, float maxheight);
public void setMaxHeight(float maxheight) {
jni_YGNodeStyleSetMaxHeight(mNativePointer, maxheight);
}
- private native void jni_YGNodeStyleSetMaxHeightPercent(long nativePointer, float percent);
+ private static native void jni_YGNodeStyleSetMaxHeightPercent(long nativePointer, float percent);
public void setMaxHeightPercent(float percent) {
jni_YGNodeStyleSetMaxHeightPercent(mNativePointer, percent);
}
- private native float jni_YGNodeStyleGetAspectRatio(long nativePointer);
+ private static native float jni_YGNodeStyleGetAspectRatio(long nativePointer);
public float getAspectRatio() {
return jni_YGNodeStyleGetAspectRatio(mNativePointer);
}
- private native void jni_YGNodeStyleSetAspectRatio(long nativePointer, float aspectRatio);
+ private static native void jni_YGNodeStyleSetAspectRatio(long nativePointer, float aspectRatio);
public void setAspectRatio(float aspectRatio) {
jni_YGNodeStyleSetAspectRatio(mNativePointer, aspectRatio);
}
@@ -720,7 +720,7 @@
return YogaDirection.fromInt(mLayoutDirection);
}
- private native void jni_YGNodeSetHasMeasureFunc(long nativePointer, boolean hasMeasureFunc);
+ private static native void jni_YGNodeSetHasMeasureFunc(long nativePointer, boolean hasMeasureFunc);
public void setMeasureFunction(YogaMeasureFunction measureFunction) {
mMeasureFunction = measureFunction;
jni_YGNodeSetHasMeasureFunc(mNativePointer, measureFunction != null);
@@ -745,7 +745,7 @@
YogaMeasureMode.fromInt(heightMode));
}
- private native void jni_YGNodeSetHasBaselineFunc(long nativePointer, boolean hasMeasureFunc);
+ private static native void jni_YGNodeSetHasBaselineFunc(long nativePointer, boolean hasMeasureFunc);
public void setBaselineFunction(YogaBaselineFunction baselineFunction) {
mBaselineFunction = baselineFunction;
jni_YGNodeSetHasBaselineFunc(mNativePointer, baselineFunction != null);
@@ -768,7 +768,7 @@
return mData;
}
- private native void jni_YGNodePrint(long nativePointer);
+ private static native void jni_YGNodePrint(long nativePointer);
/**
* Use the set logger (defaults to adb log) to print out the styles, children, and computed

ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeType.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

ReactAndroid/src/main/java/com/facebook/yoga/YogaOverflow.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

ReactAndroid/src/main/java/com/facebook/yoga/YogaPositionType.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

ReactAndroid/src/main/java/com/facebook/yoga/YogaPrintOptions.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

ReactAndroid/src/main/java/com/facebook/yoga/YogaUnit.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

ReactAndroid/src/main/java/com/facebook/yoga/YogaValue.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

ReactAndroid/src/main/java/com/facebook/yoga/YogaWrap.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

ReactAndroid/src/main/jni/Application.mk

@@ -1,17 +1,34 @@
+# 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.
+
APP_BUILD_SCRIPT := Android.mk
-APP_ABI := armeabi-v7a x86
+APP_ABI := armeabi-v7a x86 arm64-v8a x86_64
APP_PLATFORM := android-16
APP_MK_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
-NDK_MODULE_PATH := $(APP_MK_DIR)$(HOST_DIRSEP)$(THIRD_PARTY_NDK_DIR)$(HOST_DIRSEP)$(REACT_COMMON_DIR)$(HOST_DIRSEP)$(APP_MK_DIR)first-party
+# What is NDK_MODULE_PATH?
+# This is comparable to the PATH environment variable in Linux. The purpose
+# of NDK_MODULE_PATH is to provide a list of directories that contain modules
+# we want ndk-build to compile.
+#
+# What is HOST_DIRSEP?
+# In PATH, the directories are separated by a ':'.
+# In NDK_MODULE_PATH, the directories are separated by $(HOST_DIRSEP).
+#
+# Where are APP_MK_DIR, THIRD_PARTY_NDK_DIR, etc. defined?
+# The directories inside NDK_MODULE_PATH (ex: APP_MK_DIR, THIRD_PARTY_NDK_DIR,
+# etc.) are defined inside build.gradle.
+NDK_MODULE_PATH := $(APP_MK_DIR)$(HOST_DIRSEP)$(THIRD_PARTY_NDK_DIR)$(HOST_DIRSEP)$(REACT_COMMON_DIR)$(HOST_DIRSEP)$(APP_MK_DIR)first-party$(HOST_DIRSEP)$(REACT_SRC_DIR)
-APP_STL := gnustl_shared
+APP_STL := c++_shared
# Make sure every shared lib includes a .note.gnu.build-id header
APP_CFLAGS := -Wall -Werror
APP_CPPFLAGS := -std=c++1y
APP_LDFLAGS := -Wl,--build-id
-NDK_TOOLCHAIN_VERSION := 4.9
+NDK_TOOLCHAIN_VERSION := clang

ReactAndroid/src/main/jni/first-party/fb/Android.mk

@@ -1,3 +1,8 @@
+# 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.
+
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

ReactAndroid/src/main/jni/first-party/fb/assert.cpp

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/BUCK

@@ -1,4 +1,4 @@
-load("//tools/build_defs/oss:rn_defs.bzl", "JNI_TARGET", "subdir_glob", "oss_cxx_library")
+load("//tools/build_defs/oss:rn_defs.bzl", "JNI_TARGET", "oss_cxx_library", "subdir_glob")
# This target is only used in open source
oss_cxx_library(

ReactAndroid/src/main/jni/first-party/fb/include/fb/ALog.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/assert.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/Build.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/Countable.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/Environment.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/Boxed.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/ByteBuffer.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/Common.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/Context.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/CoreClasses.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -235,11 +235,18 @@
/// makeNativeMethod("nativeMethodWithExplicitDescriptor",
/// "(Lcom/facebook/example/MyClass;)V",
/// methodWithExplicitDescriptor),
+ /// makeCriticalNativeMethod("criticalNativeMethodWithAutomaticDescriptor",
+ /// criticalNativeMethodWithAutomaticDescriptor),
+ /// makeCriticalNativeMethod("criticalNativeMethodWithExplicitDescriptor",
+ /// "(IIF)Z",
+ /// criticalNativeMethodWithExplicitDescriptor),
/// });
///
/// By default, C++ exceptions raised will be converted to Java exceptions.
/// To avoid this and get the "standard" JNI behavior of a crash when a C++
/// exception is crashing out of the JNI method, declare the method noexcept.
+ /// This does NOT apply to critical native methods, where exceptions causes
+ /// a crash.
void registerNatives(std::initializer_list<NativeMethod> methods);
/// Check to see if the class is assignable from another class

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/CoreClasses-inl.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/Exceptions.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/File.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/Hybrid.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/Iterator.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/Iterator-inl.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/JThread.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/JWeakReference.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/MetaConvert.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/Meta-forward.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/Meta.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/Meta-inl.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/NativeRunnable.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/ReadableByteChannel.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/ReferenceAllocators.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/ReferenceAllocators-inl.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/References-forward.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/References.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/References-inl.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/Registration.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -44,6 +44,18 @@
template<typename R, typename C, typename... Args>
std::string makeDescriptor(R (C::*method0)(Args... args));
+template<typename F>
+struct CriticalMethod;
+
+template<typename R, typename ...Args>
+struct CriticalMethod<R(*)(Args...)> {
+ template<R(*func)(Args...)>
+ static R call(alias_ref<jclass>, Args... args);
+
+ template<R(*func)(Args...)>
+ inline static std::string desc();
+};
+
}
// We have to use macros here, because the func needs to be used
@@ -66,6 +78,35 @@
#define makeNativeMethodN(a, b, c, count, ...) makeNativeMethod ## count
#define makeNativeMethod(...) makeNativeMethodN(__VA_ARGS__, 3, 2)(__VA_ARGS__)
+
+// FAST CALLS / CRITICAL CALLS
+// Android up to and including v7 supports "fast calls" by prefixing the method
+// signature with an exclamation mark.
+// Android v8+ supports fast calls by annotating methods:
+// https://source.android.com/devices/tech/dalvik/improvements#faster-native-methods
+
+// prefixes a JNI method signature as android "fast call".
+#if defined(__ANDROID__) && defined(FBJNI_WITH_FAST_CALLS)
+#define FBJNI_PREFIX_FAST_CALL(desc) (std::string{"!"} + desc)
+#else
+#define FBJNI_PREFIX_FAST_CALL(desc) (desc)
+#endif
+
+#define makeCriticalNativeMethod3(name, desc, func) \
+ makeNativeMethod3( \
+ name, \
+ FBJNI_PREFIX_FAST_CALL(desc), \
+ ::facebook::jni::detail::CriticalMethod<decltype(&func)>::call<&func>)
+
+#define makeCriticalNativeMethod2(name, func) \
+ makeCriticalNativeMethod3( \
+ name, \
+ ::facebook::jni::detail::CriticalMethod<decltype(&func)>::desc<&func>(), \
+ func)
+
+#define makeCriticalNativeMethodN(a, b, c, count, ...) makeCriticalNativeMethod ## count
+#define makeCriticalNativeMethod(...) makeCriticalNativeMethodN(__VA_ARGS__, 3, 2)(__VA_ARGS__)
+
}}
#include "Registration-inl.h"

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/Registration-inl.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -142,6 +142,25 @@
return jmethod_traits_from_cxx<R(Args...)>::descriptor();
}
+template<typename R, typename ...Args>
+template<R(*func)(Args...)>
+JNI_ENTRY_POINT R CriticalMethod<R(*)(Args...)>::call(alias_ref<jclass>, Args... args) {
+ static_assert(
+ IsJniPrimitive<R>() || std::is_void<R>(),
+ "Critical Native Methods may only return primitive JNI types, or void.");
+ static_assert(
+ AreJniPrimitives<Args...>(),
+ "Critical Native Methods may only use primitive JNI types as parameters");
+
+ return func(std::forward<Args>(args)...);
+}
+
+template<typename R, typename ...Args>
+template<R(*func)(Args...)>
+inline std::string CriticalMethod<R(*)(Args...)>::desc() {
+ return makeDescriptor(call<func>);
+}
+
}
}}

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/TypeTraits.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -69,6 +69,25 @@
return is_jni_primitive<T>::value;
}
+/// Metafunction to determine whether a series of types are all primitive JNI types.
+template<typename ...Ts>
+struct are_jni_primitives;
+
+template<typename T, typename ...Ts>
+struct are_jni_primitives<T, Ts...> :
+ std::integral_constant<bool,
+ is_jni_primitive<T>::value && are_jni_primitives<Ts...>::value> {};
+
+template<>
+struct are_jni_primitives<> : std::integral_constant<bool, true> {};
+
+/// Helper to simplify use of are_jni_primitives
+template<typename ...Ts>
+constexpr bool AreJniPrimitives() {
+ return are_jni_primitives<Ts...>::value;
+}
+
+
/// Metafunction to determine whether a type is a JNI array of primitives or not
template <typename T>
struct is_jni_primitive_array :

ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/lyra.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/noncopyable.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/nonmovable.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/ProgramLocation.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/RefPtr.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/StaticInitialized.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/ThreadLocal.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/fb/visibility.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/jni/Countable.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/jni/GlobalReference.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/jni/jni_helpers.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/jni/JniTerminateHandler.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/jni/LocalReference.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/jni/LocalString.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/jni/Registration.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/include/jni/WeakReference.h

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/jni/android/CpuCapabilities.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/first-party/fb/jni/android/ReferenceChecking.cpp

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/jni/ByteBuffer.cpp

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/jni/Countable.cpp

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/jni/Environment.cpp

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/jni/Exceptions.cpp

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/jni/fbjni.cpp

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/jni/Hybrid.cpp

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/jni/java/CppException.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/jni/java/CppSystemErrorException.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/jni/java/UnknownCppException.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/jni/jni_helpers.cpp

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/jni/LocalString.cpp

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/jni/OnLoad.cpp

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/jni/ReadableByteChannel.cpp

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/jni/References.cpp

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/jni/WeakReference.cpp

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/log.cpp

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fb/lyra/lyra.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/first-party/fb/onload.cpp

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/fbgloginit/Android.mk

@@ -1,3 +1,8 @@
+# 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.
+
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

ReactAndroid/src/main/jni/first-party/fbgloginit/fb/glog_init.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/first-party/fbgloginit/glog_init.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/first-party/jni-hack/BUCK

@@ -1,6 +1,6 @@
load("//tools/build_defs/oss:rn_defs.bzl", "cxx_library")
-# Copyright (c) 2014-present, Facebook, Inc.
+# 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.

ReactAndroid/src/main/jni/first-party/jni-hack/jni.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/main/jni/first-party/yogajni/Android.mk

@@ -1,3 +1,8 @@
+# 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.
+
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp

@@ -1,9 +1,8 @@
-/*
- * Copyright (c) 2014-present, Facebook, Inc.
+/**
+ * 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.
- *
*/
#include <fb/fbjni.h>
#include <yoga/YGNode.h>
@@ -101,7 +100,7 @@
const int PADDING = 2;
const int BORDER = 4;
- int hasEdgeSetFlag = (int)obj->getFieldValue(edgeSetFlagField);
+ int hasEdgeSetFlag = (int) obj->getFieldValue(edgeSetFlagField);
obj->setFieldValue(widthField, YGNodeLayoutGetWidth(root));
obj->setFieldValue(heightField, YGNodeLayoutGetHeight(root));
@@ -181,8 +180,10 @@
return reinterpret_cast<YGConfigRef>(static_cast<intptr_t>(addr));
}
-static YGNodeRef
-YGJNIOnNodeClonedFunc(YGNodeRef oldNode, YGNodeRef owner, int childIndex) {
+static YGNodeRef YGJNIOnNodeClonedFunc(
+ YGNodeRef oldNode,
+ YGNodeRef owner,
+ int childIndex) {
auto config = oldNode->getConfig();
if (!config) {
return nullptr;
@@ -303,10 +304,7 @@
return reinterpret_cast<jlong>(node);
}
-void jni_YGNodeSetOwner(
- alias_ref<jobject> thiz,
- jlong nativePointer,
- jlong newOwnerNativePointer) {
+void jni_YGNodeSetOwner(jlong nativePointer, jlong newOwnerNativePointer) {
const YGNodeRef node = _jlong2YGNodeRef(nativePointer);
const YGNodeRef newOwnerNode = _jlong2YGNodeRef(newOwnerNativePointer);
@@ -323,7 +321,7 @@
return reinterpret_cast<jlong>(clonedYogaNode);
}
-void jni_YGNodeFree(alias_ref<jclass>, jlong nativePointer) {
+void jni_YGNodeFree(jlong nativePointer) {
if (nativePointer == 0) {
return;
}
@@ -332,12 +330,12 @@
YGNodeFree(node);
}
-void jni_YGNodeClearChildren(alias_ref<jobject> thiz, jlong nativePointer) {
+void jni_YGNodeClearChildren(jlong nativePointer) {
const YGNodeRef node = _jlong2YGNodeRef(nativePointer);
node->clearChildren();
}
-void jni_YGNodeReset(alias_ref<jobject> thiz, jlong nativePointer) {
+void jni_YGNodeReset(jlong nativePointer) {
const YGNodeRef node = _jlong2YGNodeRef(nativePointer);
void* context = node->getContext();
YGNodeReset(node);
@@ -345,7 +343,7 @@
node->setPrintFunc(YGPrint);
}
-void jni_YGNodePrint(alias_ref<jobject> thiz, jlong nativePointer) {
+void jni_YGNodePrint(jlong nativePointer) {
const YGNodeRef node = _jlong2YGNodeRef(nativePointer);
YGNodePrint(
node,
@@ -354,7 +352,6 @@
}
void jni_YGNodeInsertChild(
- alias_ref<jobject>,
jlong nativePointer,
jlong childPointer,
jint index) {
@@ -362,25 +359,24 @@
_jlong2YGNodeRef(nativePointer), _jlong2YGNodeRef(childPointer), index);
}
-void jni_YGNodeInsertSharedChild(
- alias_ref<jobject>,
- jlong nativePointer,
- jlong childPointer,
- jint index) {
- YGNodeInsertSharedChild(
- _jlong2YGNodeRef(nativePointer), _jlong2YGNodeRef(childPointer), index);
+void jni_YGNodeRemoveChild(jlong nativePointer, jlong childPointer) {
+ YGNodeRemoveChild(
+ _jlong2YGNodeRef(nativePointer), _jlong2YGNodeRef(childPointer));
}
-void jni_YGNodeRemoveChild(
- alias_ref<jobject>,
+void jni_YGNodeSetIsReferenceBaseline(
jlong nativePointer,
- jlong childPointer) {
- YGNodeRemoveChild(
- _jlong2YGNodeRef(nativePointer), _jlong2YGNodeRef(childPointer));
+ jboolean isReferenceBaseline) {
+ YGNodeSetIsReferenceBaseline(
+ _jlong2YGNodeRef(nativePointer), isReferenceBaseline);
+}
+
+jboolean jni_YGNodeIsReferenceBaseline(jlong nativePointer) {
+ return YGNodeIsReferenceBaseline(_jlong2YGNodeRef(nativePointer));
}
void jni_YGNodeCalculateLayout(
- alias_ref<jobject>,
+ alias_ref<jclass>,
jlong nativePointer,
jfloat width,
jfloat height) {
@@ -393,40 +389,31 @@
YGTransferLayoutOutputsRecursive(root);
}
-void jni_YGNodeMarkDirty(alias_ref<jobject>, jlong nativePointer) {
+void jni_YGNodeMarkDirty(jlong nativePointer) {
YGNodeMarkDirty(_jlong2YGNodeRef(nativePointer));
}
-void jni_YGNodeMarkDirtyAndPropogateToDescendants(
- alias_ref<jobject>,
- jlong nativePointer) {
+void jni_YGNodeMarkDirtyAndPropogateToDescendants(jlong nativePointer) {
YGNodeMarkDirtyAndPropogateToDescendants(_jlong2YGNodeRef(nativePointer));
}
-jboolean jni_YGNodeIsDirty(alias_ref<jobject>, jlong nativePointer) {
- return (jboolean)_jlong2YGNodeRef(nativePointer)->isDirty();
+jboolean jni_YGNodeIsDirty(jlong nativePointer) {
+ return (jboolean) _jlong2YGNodeRef(nativePointer)->isDirty();
}
-void jni_YGNodeSetHasMeasureFunc(
- alias_ref<jobject>,
- jlong nativePointer,
- jboolean hasMeasureFunc) {
+void jni_YGNodeSetHasMeasureFunc(jlong nativePointer, jboolean hasMeasureFunc) {
_jlong2YGNodeRef(nativePointer)
->setMeasureFunc(hasMeasureFunc ? YGJNIMeasureFunc : nullptr);
}
void jni_YGNodeSetHasBaselineFunc(
- alias_ref<jobject>,
jlong nativePointer,
jboolean hasBaselineFunc) {
_jlong2YGNodeRef(nativePointer)
->setBaseLineFunc(hasBaselineFunc ? YGJNIBaselineFunc : nullptr);
}
-void jni_YGNodeCopyStyle(
- alias_ref<jobject>,
- jlong dstNativePointer,
- jlong srcNativePointer) {
+void jni_YGNodeCopyStyle(jlong dstNativePointer, jlong srcNativePointer) {
YGNodeCopyStyle(
_jlong2YGNodeRef(dstNativePointer), _jlong2YGNodeRef(srcNativePointer));
}
@@ -440,12 +427,11 @@
};
#define YG_NODE_JNI_STYLE_PROP(javatype, type, name) \
- javatype jni_YGNodeStyleGet##name(alias_ref<jobject>, jlong nativePointer) { \
- return (javatype)YGNodeStyleGet##name(_jlong2YGNodeRef(nativePointer)); \
+ javatype jni_YGNodeStyleGet##name(jlong nativePointer) { \
+ return (javatype) YGNodeStyleGet##name(_jlong2YGNodeRef(nativePointer)); \
} \
\
- void jni_YGNodeStyleSet##name( \
- alias_ref<jobject>, jlong nativePointer, javatype value) { \
+ void jni_YGNodeStyleSet##name(jlong nativePointer, javatype value) { \
YGNodeStyleSet##name( \
_jlong2YGNodeRef(nativePointer), static_cast<type>(value)); \
}
@@ -457,34 +443,30 @@
YGNodeStyleGet##name(_jlong2YGNodeRef(nativePointer))); \
} \
\
- void jni_YGNodeStyleSet##name( \
- alias_ref<jobject>, jlong nativePointer, jfloat value) { \
+ void jni_YGNodeStyleSet##name(jlong nativePointer, jfloat value) { \
YGNodeStyleSet##name( \
_jlong2YGNodeRef(nativePointer), static_cast<float>(value)); \
} \
\
- void jni_YGNodeStyleSet##name##Percent( \
- alias_ref<jobject>, jlong nativePointer, jfloat value) { \
+ void jni_YGNodeStyleSet##name##Percent(jlong nativePointer, jfloat value) { \
YGNodeStyleSet##name##Percent( \
_jlong2YGNodeRef(nativePointer), static_cast<float>(value)); \
}
#define YG_NODE_JNI_STYLE_UNIT_PROP_AUTO(name) \
YG_NODE_JNI_STYLE_UNIT_PROP(name) \
- void jni_YGNodeStyleSet##name##Auto( \
- alias_ref<jobject>, jlong nativePointer) { \
+ void jni_YGNodeStyleSet##name##Auto(jlong nativePointer) { \
YGNodeStyleSet##name##Auto(_jlong2YGNodeRef(nativePointer)); \
}
#define YG_NODE_JNI_STYLE_EDGE_PROP(javatype, type, name) \
- javatype jni_YGNodeStyleGet##name( \
- alias_ref<jobject>, jlong nativePointer, jint edge) { \
- return (javatype)YGNodeStyleGet##name( \
+ javatype jni_YGNodeStyleGet##name(jlong nativePointer, jint edge) { \
+ return (javatype) YGNodeStyleGet##name( \
_jlong2YGNodeRef(nativePointer), static_cast<YGEdge>(edge)); \
} \
\
void jni_YGNodeStyleSet##name( \
- alias_ref<jobject>, jlong nativePointer, jint edge, javatype value) { \
+ jlong nativePointer, jint edge, javatype value) { \
YGNodeStyleSet##name( \
_jlong2YGNodeRef(nativePointer), \
static_cast<YGEdge>(edge), \
@@ -499,7 +481,7 @@
} \
\
void jni_YGNodeStyleSet##name( \
- alias_ref<jobject>, jlong nativePointer, jint edge, jfloat value) { \
+ jlong nativePointer, jint edge, jfloat value) { \
YGNodeStyleSet##name( \
_jlong2YGNodeRef(nativePointer), \
static_cast<YGEdge>(edge), \
@@ -507,7 +489,7 @@
} \
\
void jni_YGNodeStyleSet##name##Percent( \
- alias_ref<jobject>, jlong nativePointer, jint edge, jfloat value) { \
+ jlong nativePointer, jint edge, jfloat value) { \
YGNodeStyleSet##name##Percent( \
_jlong2YGNodeRef(nativePointer), \
static_cast<YGEdge>(edge), \
@@ -516,8 +498,7 @@
#define YG_NODE_JNI_STYLE_EDGE_UNIT_PROP_AUTO(name) \
YG_NODE_JNI_STYLE_EDGE_UNIT_PROP(name) \
- void jni_YGNodeStyleSet##name##Auto( \
- alias_ref<jobject>, jlong nativePointer, jint edge) { \
+ void jni_YGNodeStyleSet##name##Auto(jlong nativePointer, jint edge) { \
YGNodeStyleSet##name##Auto( \
_jlong2YGNodeRef(nativePointer), static_cast<YGEdge>(edge)); \
}
@@ -533,10 +514,7 @@
YG_NODE_JNI_STYLE_PROP(jint, YGOverflow, Overflow);
YG_NODE_JNI_STYLE_PROP(jint, YGDisplay, Display);
-void jni_YGNodeStyleSetFlex(
- alias_ref<jobject>,
- jlong nativePointer,
- jfloat value) {
+void jni_YGNodeStyleSetFlex(jlong nativePointer, jfloat value) {
YGNodeStyleSetFlex(
_jlong2YGNodeRef(nativePointer), static_cast<float>(value));
}
@@ -598,6 +576,14 @@
YGConfigSetUseWebDefaults(config, useWebDefaults);
}
+void jni_YGConfigSetPrintTreeFlag(
+ alias_ref<jobject>,
+ jlong nativePointer,
+ jboolean enable) {
+ const YGConfigRef config = _jlong2YGConfigRef(nativePointer);
+ YGConfigSetPrintTreeFlag(config, enable);
+}
+
void jni_YGConfigSetPointScaleFactor(
alias_ref<jobject>,
jlong nativePointer,
@@ -660,11 +646,12 @@
}
}
-jint jni_YGNodeGetInstanceCount(alias_ref<jclass> clazz) {
+jint jni_YGNodeGetInstanceCount() {
return YGNodeGetInstanceCount();
}
#define YGMakeNativeMethod(name) makeNativeMethod(#name, name)
+#define YGMakeCriticalNativeMethod(name) makeCriticalNativeMethod(#name, name)
jint JNI_OnLoad(JavaVM* vm, void*) {
return initialize(vm, [] {
@@ -673,85 +660,87 @@
{
YGMakeNativeMethod(jni_YGNodeNew),
YGMakeNativeMethod(jni_YGNodeNewWithConfig),
- YGMakeNativeMethod(jni_YGNodeFree),
- YGMakeNativeMethod(jni_YGNodeReset),
- YGMakeNativeMethod(jni_YGNodeClearChildren),
- YGMakeNativeMethod(jni_YGNodeInsertChild),
- YGMakeNativeMethod(jni_YGNodeInsertSharedChild),
- YGMakeNativeMethod(jni_YGNodeRemoveChild),
+ YGMakeCriticalNativeMethod(jni_YGNodeFree),
+ YGMakeCriticalNativeMethod(jni_YGNodeReset),
+ YGMakeCriticalNativeMethod(jni_YGNodeClearChildren),
+ YGMakeCriticalNativeMethod(jni_YGNodeInsertChild),
+ YGMakeCriticalNativeMethod(jni_YGNodeRemoveChild),
+ YGMakeCriticalNativeMethod(jni_YGNodeSetIsReferenceBaseline),
+ YGMakeCriticalNativeMethod(jni_YGNodeIsReferenceBaseline),
YGMakeNativeMethod(jni_YGNodeCalculateLayout),
- YGMakeNativeMethod(jni_YGNodeMarkDirty),
- YGMakeNativeMethod(jni_YGNodeMarkDirtyAndPropogateToDescendants),
- YGMakeNativeMethod(jni_YGNodeIsDirty),
- YGMakeNativeMethod(jni_YGNodeSetHasMeasureFunc),
- YGMakeNativeMethod(jni_YGNodeSetHasBaselineFunc),
- YGMakeNativeMethod(jni_YGNodeCopyStyle),
- YGMakeNativeMethod(jni_YGNodeStyleGetDirection),
- YGMakeNativeMethod(jni_YGNodeStyleSetDirection),
- YGMakeNativeMethod(jni_YGNodeStyleGetFlexDirection),
- YGMakeNativeMethod(jni_YGNodeStyleSetFlexDirection),
- YGMakeNativeMethod(jni_YGNodeStyleGetJustifyContent),
- YGMakeNativeMethod(jni_YGNodeStyleSetJustifyContent),
- YGMakeNativeMethod(jni_YGNodeStyleGetAlignItems),
- YGMakeNativeMethod(jni_YGNodeStyleSetAlignItems),
- YGMakeNativeMethod(jni_YGNodeStyleGetAlignSelf),
- YGMakeNativeMethod(jni_YGNodeStyleSetAlignSelf),
- YGMakeNativeMethod(jni_YGNodeStyleGetAlignContent),
- YGMakeNativeMethod(jni_YGNodeStyleSetAlignContent),
- YGMakeNativeMethod(jni_YGNodeStyleGetPositionType),
- YGMakeNativeMethod(jni_YGNodeStyleSetPositionType),
- YGMakeNativeMethod(jni_YGNodeStyleSetFlexWrap),
- YGMakeNativeMethod(jni_YGNodeStyleGetOverflow),
- YGMakeNativeMethod(jni_YGNodeStyleSetOverflow),
- YGMakeNativeMethod(jni_YGNodeStyleGetDisplay),
- YGMakeNativeMethod(jni_YGNodeStyleSetDisplay),
- YGMakeNativeMethod(jni_YGNodeStyleSetFlex),
- YGMakeNativeMethod(jni_YGNodeStyleGetFlexGrow),
- YGMakeNativeMethod(jni_YGNodeStyleSetFlexGrow),
- YGMakeNativeMethod(jni_YGNodeStyleGetFlexShrink),
- YGMakeNativeMethod(jni_YGNodeStyleSetFlexShrink),
+ YGMakeCriticalNativeMethod(jni_YGNodeMarkDirty),
+ YGMakeCriticalNativeMethod(
+ jni_YGNodeMarkDirtyAndPropogateToDescendants),
+ YGMakeCriticalNativeMethod(jni_YGNodeIsDirty),
+ YGMakeCriticalNativeMethod(jni_YGNodeSetHasMeasureFunc),
+ YGMakeCriticalNativeMethod(jni_YGNodeSetHasBaselineFunc),
+ YGMakeCriticalNativeMethod(jni_YGNodeCopyStyle),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleGetDirection),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetDirection),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleGetFlexDirection),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetFlexDirection),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleGetJustifyContent),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetJustifyContent),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleGetAlignItems),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetAlignItems),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleGetAlignSelf),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetAlignSelf),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleGetAlignContent),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetAlignContent),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleGetPositionType),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetPositionType),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetFlexWrap),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleGetOverflow),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetOverflow),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleGetDisplay),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetDisplay),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetFlex),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleGetFlexGrow),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetFlexGrow),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleGetFlexShrink),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetFlexShrink),
YGMakeNativeMethod(jni_YGNodeStyleGetFlexBasis),
- YGMakeNativeMethod(jni_YGNodeStyleSetFlexBasis),
- YGMakeNativeMethod(jni_YGNodeStyleSetFlexBasisPercent),
- YGMakeNativeMethod(jni_YGNodeStyleSetFlexBasisAuto),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetFlexBasis),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetFlexBasisPercent),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetFlexBasisAuto),
YGMakeNativeMethod(jni_YGNodeStyleGetMargin),
- YGMakeNativeMethod(jni_YGNodeStyleSetMargin),
- YGMakeNativeMethod(jni_YGNodeStyleSetMarginPercent),
- YGMakeNativeMethod(jni_YGNodeStyleSetMarginAuto),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMargin),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMarginPercent),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMarginAuto),
YGMakeNativeMethod(jni_YGNodeStyleGetPadding),
- YGMakeNativeMethod(jni_YGNodeStyleSetPadding),
- YGMakeNativeMethod(jni_YGNodeStyleSetPaddingPercent),
- YGMakeNativeMethod(jni_YGNodeStyleGetBorder),
- YGMakeNativeMethod(jni_YGNodeStyleSetBorder),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetPadding),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetPaddingPercent),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleGetBorder),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetBorder),
YGMakeNativeMethod(jni_YGNodeStyleGetPosition),
- YGMakeNativeMethod(jni_YGNodeStyleSetPosition),
- YGMakeNativeMethod(jni_YGNodeStyleSetPositionPercent),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetPosition),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetPositionPercent),
YGMakeNativeMethod(jni_YGNodeStyleGetWidth),
- YGMakeNativeMethod(jni_YGNodeStyleSetWidth),
- YGMakeNativeMethod(jni_YGNodeStyleSetWidthPercent),
- YGMakeNativeMethod(jni_YGNodeStyleSetWidthAuto),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetWidth),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetWidthPercent),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetWidthAuto),
YGMakeNativeMethod(jni_YGNodeStyleGetHeight),
- YGMakeNativeMethod(jni_YGNodeStyleSetHeight),
- YGMakeNativeMethod(jni_YGNodeStyleSetHeightPercent),
- YGMakeNativeMethod(jni_YGNodeStyleSetHeightAuto),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetHeight),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetHeightPercent),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetHeightAuto),
YGMakeNativeMethod(jni_YGNodeStyleGetMinWidth),
- YGMakeNativeMethod(jni_YGNodeStyleSetMinWidth),
- YGMakeNativeMethod(jni_YGNodeStyleSetMinWidthPercent),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMinWidth),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMinWidthPercent),
YGMakeNativeMethod(jni_YGNodeStyleGetMinHeight),
- YGMakeNativeMethod(jni_YGNodeStyleSetMinHeight),
- YGMakeNativeMethod(jni_YGNodeStyleSetMinHeightPercent),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMinHeight),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMinHeightPercent),
YGMakeNativeMethod(jni_YGNodeStyleGetMaxWidth),
- YGMakeNativeMethod(jni_YGNodeStyleSetMaxWidth),
- YGMakeNativeMethod(jni_YGNodeStyleSetMaxWidthPercent),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMaxWidth),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMaxWidthPercent),
YGMakeNativeMethod(jni_YGNodeStyleGetMaxHeight),
- YGMakeNativeMethod(jni_YGNodeStyleSetMaxHeight),
- YGMakeNativeMethod(jni_YGNodeStyleSetMaxHeightPercent),
- YGMakeNativeMethod(jni_YGNodeStyleGetAspectRatio),
- YGMakeNativeMethod(jni_YGNodeStyleSetAspectRatio),
- YGMakeNativeMethod(jni_YGNodeGetInstanceCount),
- YGMakeNativeMethod(jni_YGNodePrint),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMaxHeight),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMaxHeightPercent),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleGetAspectRatio),
+ YGMakeCriticalNativeMethod(jni_YGNodeStyleSetAspectRatio),
+ YGMakeCriticalNativeMethod(jni_YGNodeGetInstanceCount),
+ YGMakeCriticalNativeMethod(jni_YGNodePrint),
YGMakeNativeMethod(jni_YGNodeClone),
- YGMakeNativeMethod(jni_YGNodeSetOwner),
+ YGMakeCriticalNativeMethod(jni_YGNodeSetOwner),
});
registerNatives(
"com/facebook/yoga/YogaConfig",
@@ -760,6 +749,7 @@
YGMakeNativeMethod(jni_YGConfigFree),
YGMakeNativeMethod(jni_YGConfigSetExperimentalFeatureEnabled),
YGMakeNativeMethod(jni_YGConfigSetUseWebDefaults),
+ YGMakeNativeMethod(jni_YGConfigSetPrintTreeFlag),
YGMakeNativeMethod(jni_YGConfigSetPointScaleFactor),
YGMakeNativeMethod(jni_YGConfigSetUseLegacyStretchBehaviour),
YGMakeNativeMethod(jni_YGConfigSetLogger),

ReactAndroid/src/main/jni/prebuilt/BUCK

@@ -1,5 +1,6 @@
-load("//tools/build_defs/oss:rn_defs.bzl", "rn_android_prebuilt_aar", "rn_prebuilt_native_library")
# Temp workaround to get the build working e2e, Gradle builds them for us
+load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
+load("//tools/build_defs/oss:rn_defs.bzl", "rn_android_prebuilt_aar", "rn_prebuilt_native_library")
rn_prebuilt_native_library(
name = "reactnative-libs",
@@ -13,7 +14,7 @@
visibility = ["PUBLIC"],
)
-remote_file(
+fb_native.remote_file(
name = "android-jsc-aar",
sha1 = "880cedd93f43e0fc841f01f2fa185a63d9230f85",
url = "mvn:org.webkit:android-jsc:aar:r174650",

ReactAndroid/src/main/jni/react/jni/AndroidJSCFactory.cpp

@@ -1,125 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#include <cxxreact/JSCExecutor.h>
-
-#include <string>
-
-#include <cxxreact/Platform.h>
-#include <fb/fbjni.h>
-#include <folly/Conv.h>
-#include <folly/dynamic.h>
-#include <folly/Memory.h>
-#include <jschelpers/JSCHelpers.h>
-
-#include "JSCPerfLogging.h"
-#include "JSLogging.h"
-#include "JReactMarker.h"
-
-using namespace facebook::jni;
-
-namespace facebook {
-namespace react {
-
-namespace {
-
-ExceptionHandling::ExtractedEror extractJniError(const std::exception& ex, const char *context) {
- auto jniEx = dynamic_cast<const jni::JniException *>(&ex);
- if (!jniEx) {
- return {};
- }
-
- auto stackTrace = jniEx->getThrowable()->getStackTrace();
- std::ostringstream stackStr;
- for (int i = 0, count = stackTrace->size(); i < count; ++i) {
- auto frame = stackTrace->getElement(i);
-
- auto methodName = folly::to<std::string>(frame->getClassName(), ".",
- frame->getMethodName());
-
- // Cut off stack traces at the Android looper, to keep them simple
- if (methodName == "android.os.Looper.loop") {
- break;
- }
-
- stackStr << std::move(methodName) << '@' << frame->getFileName();
- if (frame->getLineNumber() > 0) {
- stackStr << ':' << frame->getLineNumber();
- }
- stackStr << std::endl;
- }
-
- auto msg = folly::to<std::string>("Java exception in '", context, "'\n\n", jniEx->what());
- return {.message = msg, .stack = stackStr.str()};
-}
-
-JSValueRef nativePerformanceNow(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[], JSValueRef *exception) {
- static const int64_t NANOSECONDS_IN_SECOND = 1000000000LL;
- static const int64_t NANOSECONDS_IN_MILLISECOND = 1000000LL;
-
- // Since SystemClock.uptimeMillis() is commonly used for performance measurement in Java
- // and uptimeMillis() internally uses clock_gettime(CLOCK_MONOTONIC),
- // we use the same API here.
- // We need that to make sure we use the same time system on both JS and Java sides.
- // Links to the source code:
- // https://android.googlesource.com/platform/frameworks/native/+/jb-mr1-release/libs/utils/SystemClock.cpp
- // https://android.googlesource.com/platform/system/core/+/master/libutils/Timers.cpp
- struct timespec now;
- clock_gettime(CLOCK_MONOTONIC, &now);
- int64_t nano = now.tv_sec * NANOSECONDS_IN_SECOND + now.tv_nsec;
- return Value::makeNumber(ctx, (nano / (double)NANOSECONDS_IN_MILLISECOND));
-}
-
-JSValueRef nativeLoggingHook(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- android_LogPriority logLevel = ANDROID_LOG_DEBUG;
- if (argumentCount > 1) {
- int level = (int)Value(ctx, arguments[1]).asNumber();
- // The lowest log level we get from JS is 0. We shift and cap it to be
- // in the range the Android logging method expects.
- logLevel = std::min(
- static_cast<android_LogPriority>(level + ANDROID_LOG_DEBUG),
- ANDROID_LOG_FATAL);
- }
- if (argumentCount > 0) {
- String message = Value(ctx, arguments[0]).toString();
- reactAndroidLoggingHook(message.str(), logLevel);
- }
- return Value::makeUndefined(ctx);
-}
-
-}
-
-namespace detail {
-
-void injectJSCExecutorAndroidPlatform() {
- // Inject some behavior into react/
- JReactMarker::setLogPerfMarkerIfNeeded();
- ExceptionHandling::platformErrorExtractor = extractJniError;
- JSCNativeHooks::loggingHook = nativeLoggingHook;
- JSCNativeHooks::nowHook = nativePerformanceNow;
- JSCNativeHooks::installPerfHooks = addNativePerfLoggingHooks;
-}
-
-}
-
-std::unique_ptr<JSExecutorFactory> makeAndroidJSCExecutorFactory(
- const folly::dynamic& jscConfig) {
- detail::injectJSCExecutorAndroidPlatform();
- return folly::make_unique<JSCExecutorFactory>(std::move(jscConfig));
-}
-
-}
-}

ReactAndroid/src/main/jni/react/jni/AndroidJSCFactory.h

@@ -1,33 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#pragma once
-
-#include <memory>
-#include <cxxreact/JSExecutor.h>
-
-namespace folly {
-
-class dynamic;
-
-}
-
-namespace facebook {
-namespace react {
-
-class JSExecutorFactory;
-
-namespace detail {
-
-// This is only exposed so instrumentation tests can call it.
-void injectJSCExecutorAndroidPlatform();
-
-}
-
-std::unique_ptr<JSExecutorFactory> makeAndroidJSCExecutorFactory(
- const folly::dynamic& jscConfig);
-
-}
-}

ReactAndroid/src/main/jni/react/jni/Android.mk

@@ -1,48 +1,67 @@
+# 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.
+
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_MODULE := reactnativejni
-
-LOCAL_SRC_FILES := \
- AndroidJSCFactory.cpp \
- CatalystInstanceImpl.cpp \
- CxxModuleWrapper.cpp \
- JavaModuleWrapper.cpp \
- JReactMarker.cpp \
- JMessageQueueThread.cpp \
- JSCPerfLogging.cpp \
- JSLoader.cpp \
- JSLogging.cpp \
- JniJSModulesUnbundle.cpp \
- MethodInvoker.cpp \
- ModuleRegistryBuilder.cpp \
- NativeArray.cpp \
- NativeCommon.cpp \
- NativeDeltaClient.cpp \
- NativeMap.cpp \
- OnLoad.cpp \
- ProxyExecutor.cpp \
- ReadableNativeArray.cpp \
- ReadableNativeMap.cpp \
- WritableNativeArray.cpp \
- WritableNativeMap.cpp \
-
+# Include . in the header search path for all source files in this module.
LOCAL_C_INCLUDES := $(LOCAL_PATH)
+
+# Include ./../../ in the header search path for modules that depend on
+# reactnativejni. This will allow external modules to require this module's
+# headers using #include <react/jni/<header>.h>, assuming:
+# . == jni
+# ./../ == react
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../..
-LOCAL_CFLAGS += -fvisibility=hidden -fexceptions -frtti
+LOCAL_CFLAGS += -fexceptions -frtti -Wno-unused-lambda-capture
LOCAL_LDLIBS += -landroid
-LOCAL_SHARED_LIBRARIES := libfolly_json libfb libjsc libglog_init libyoga libprivatedata
+
+# The dynamic libraries (.so files) that this module depends on.
+LOCAL_SHARED_LIBRARIES := libfolly_json libfb libjsc libglog_init libyoga
+
+# The static libraries (.a files) that this module depends on.
LOCAL_STATIC_LIBRARIES := libreactnative
+# Name of this module.
+#
+# Other modules can depend on this one by adding libreactnativejni to their
+# LOCAL_SHARED_LIBRARIES variable.
+LOCAL_MODULE := reactnativejni
+
+# Compile all local c++ files.
+LOCAL_SRC_FILES := $(wildcard *.cpp)
+
+# Build the files in this directory as a shared library
include $(BUILD_SHARED_LIBRARY)
-$(call import-module,cxxreact)
-$(call import-module,privatedata)
-$(call import-module,fb)
-$(call import-module,fbgloginit)
+# Compile the c++ dependencies required for ReactAndroid
+#
+# How does the import-module function work?
+# For each $(call import-module,<module-dir>), you search the directories in
+# NDK_MODULE_PATH. (This variable is defined in Application.mk). If you find a
+# <module-dir>/Android.mk you in a directory <dir>, you run:
+# include <dir>/<module-dir>/Android.mk
+#
+# What does it mean to include an Android.mk file?
+# Whenever you encounter an include <dir>/<module-dir>/Android.mk, you
+# tell andorid-ndk to compile the module in <dir>/<module-dir> according
+# to the specification inside <dir>/<module-dir>/Android.mk.
$(call import-module,folly)
+$(call import-module,fb)
$(call import-module,jsc)
+$(call import-module,fbgloginit)
$(call import-module,yogajni)
+$(call import-module,cxxreact)
+$(call import-module,jsi)
+$(call import-module,jsiexecutor)
+
+# TODO(ramanpreet):
+# Why doesn't this import-module call generate a jscexecutor.so file?
+# $(call import-module,jscexecutor)
+
+include $(REACT_SRC_DIR)/jscexecutor/Android.mk

ReactAndroid/src/main/jni/react/jni/BUCK

@@ -1,12 +1,13 @@
-load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "ANDROID_JSC_DEPS", "APPLE_JSC_DEPS", "FBJNI_TARGET", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library")
+load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "FBJNI_TARGET", "IS_OSS_BUILD", "react_native_xplat_dep", "react_native_xplat_target", "rn_xplat_cxx_library")
EXPORTED_HEADERS = [
- "AndroidJSCFactory.h",
"CxxModuleWrapper.h",
"CxxModuleWrapperBase.h",
"CxxSharedModuleWrapper.h",
"JavaModuleWrapper.h",
"JavaScriptExecutorHolder.h",
+ "JCallback.h",
+ "JMessageQueueThread.h",
"JReactMarker.h",
"JSLoader.h",
"JSLogging.h",
@@ -40,8 +41,6 @@
"-Wno-inconsistent-missing-override",
],
fbandroid_allow_jni_merging = True,
- fbandroid_deps = ANDROID_JSC_DEPS,
- fbobjc_deps = APPLE_JSC_DEPS,
platforms = ANDROID,
preprocessor_flags = [
"-DLOG_TAG=\"ReactNativeJNI\"",
@@ -54,11 +53,15 @@
],
deps = ([
"xplat//third-party/linker_lib:android",
+ "xplat//third-party/linker_lib:atomic",
"xplat//folly:molly",
"fbandroid//xplat/fbgloginit:fbgloginit",
"xplat//fbsystrace:fbsystrace",
react_native_xplat_target("cxxreact:bridge"),
+ react_native_xplat_target("cxxreact:jsbigstring"),
react_native_xplat_target("cxxreact:module"),
+ react_native_xplat_target("jsinspector:jsinspector"),
+ react_native_xplat_dep("jsi:jsi"),
FBJNI_TARGET,
]) if not IS_OSS_BUILD else [],
)

ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -153,7 +153,7 @@
moduleMessageQueue_));
instance_->initializeBridge(
- folly::make_unique<JInstanceCallback>(
+ std::make_unique<JInstanceCallback>(
callback,
moduleMessageQueue_),
jseh->getExecutorFactory(),

ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/CxxModuleWrapperBase.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/CxxModuleWrapper.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/CxxModuleWrapper.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/CxxSharedModuleWrapper.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/JavaModuleWrapper.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/JavaModuleWrapper.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/JavaScriptExecutorHolder.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/JCallback.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/JInspector.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/JInspector.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -8,11 +8,10 @@
#include <condition_variable>
#include <mutex>
+#include <fb/fbjni.h>
#include <fb/log.h>
#include <folly/Memory.h>
-#include <fb/fbjni.h>
-
-#include <jschelpers/JSCHelpers.h>
+#include <jsi/jsi.h>
#include "JNativeRunnable.h"
@@ -35,8 +34,10 @@
return [runnable=std::move(runnable)] {
try {
runnable();
- } catch (const JSException& ex) {
- throwNewJavaException(JavaJSException::create(ex.what(), ex.getStack().c_str(), ex).get());
+ } catch (const jsi::JSError& ex) {
+ throwNewJavaException(
+ JavaJSException::create(ex.getMessage().c_str(), ex.getStack().c_str(), ex)
+ .get());
}
};
}

ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/JNativeRunnable.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/JReactMarker.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/JReactMarker.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/JSCPerfLogging.cpp

@@ -1,308 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#include "JSCPerfLogging.h"
-
-#include <jschelpers/JSCHelpers.h>
-
-#include <fb/log.h>
-#include <fb/fbjni.h>
-
-using namespace facebook::jni;
-
-namespace facebook { namespace react {
-
-struct JQuickPerformanceLogger : JavaClass<JQuickPerformanceLogger> {
- static auto constexpr kJavaDescriptor = "Lcom/facebook/quicklog/QuickPerformanceLogger;";
-
- void markerStart(int markerId, int instanceKey, long timestamp) {
- static auto markerStartMethod =
- javaClassStatic()->getMethod<void(jint, jint, jlong)>("markerStart");
- markerStartMethod(self(), markerId, instanceKey, timestamp);
- }
-
- void markerEnd(int markerId, int instanceKey, short actionId, long timestamp) {
- static auto markerEndMethod =
- javaClassStatic()->getMethod<void(jint, jint, jshort, jlong)>("markerEnd");
- markerEndMethod(self(), markerId, instanceKey, actionId, timestamp);
- }
-
- void markerTag(int markerId, int instanceKey, alias_ref<jstring> tag) {
- static auto markerTagMethod =
- javaClassStatic()->getMethod<void(jint, jint, alias_ref<jstring>)>("markerTag");
- markerTagMethod(self(), markerId, instanceKey, tag);
- }
-
- void markerAnnotate(
- int markerId,
- int instanceKey,
- alias_ref<jstring> key,
- alias_ref<jstring> value) {
- static auto markerAnnotateMethod = javaClassStatic()->
- getMethod<void(jint, jint, alias_ref<jstring>, alias_ref<jstring>)>("markerAnnotate");
- markerAnnotateMethod(self(), markerId, instanceKey, key, value);
- }
-
- void markerNote(int markerId, int instanceKey, short actionId, long timestamp) {
- static auto markerNoteMethod =
- javaClassStatic()->getMethod<void(jint, jint, jshort, jlong)>("markerNote");
- markerNoteMethod(self(), markerId, instanceKey, actionId, timestamp);
- }
-
- void markerCancel(int markerId, int instanceKey) {
- static auto markerCancelMethod =
- javaClassStatic()->getMethod<void(jint, jint)>("markerCancel");
- markerCancelMethod(self(), markerId, instanceKey);
- }
-
- int64_t currentMonotonicTimestamp() {
- static auto currentTimestampMethod =
- javaClassStatic()->getMethod<jlong()>("currentMonotonicTimestamp");
- return currentTimestampMethod(self());
- }
-
- void markerPoint(int markerId, alias_ref<jstring> name, int instanceKey) {
- static auto markerPointMethod =
- javaClassStatic()->getMethod<void(jint, jint, alias_ref<jstring>)>("markerPoint");
- markerPointMethod(self(), markerId, instanceKey, name);
- }
-};
-
-struct JQuickPerformanceLoggerProvider : JavaClass<JQuickPerformanceLoggerProvider> {
- static auto constexpr kJavaDescriptor = "Lcom/facebook/quicklog/QuickPerformanceLoggerProvider;";
-
- static alias_ref<JQuickPerformanceLogger::javaobject> get() {
- static auto getQPLInstMethod =
- javaClassStatic()->getStaticMethod<JQuickPerformanceLogger::javaobject()>("getQPLInstance");
- static auto logger = make_global(getQPLInstMethod(javaClassStatic()));
- return logger;
- }
-};
-
-static bool isReady() {
- static bool ready = false;
- if (!ready) {
- try {
- // TODO: findClassStatic only does the lookup once. If we can't find
- // QuickPerformanceLoggerProvider the first time we call this, we will always fail here.
- findClassStatic("com/facebook/quicklog/QuickPerformanceLoggerProvider");
- } catch(...) {
- // Swallow this exception - we don't want to crash the app, an error is enough.
- FBLOGE("Calling QPL from JS before class has been loaded in Java. Ignored.");
- return false;
- }
- if (JQuickPerformanceLoggerProvider::get()) {
- ready = true;
- } else {
- FBLOGE("Calling QPL from JS before it has been initialized in Java. Ignored.");
- return false;
- }
- }
- return ready;
-}
-
-// After having read the implementation of PNaN that is returned from JSValueToNumber, and some
-// more material on how NaNs are constructed, I think this is the most consistent way to verify
-// NaN with how we generate it.
-// Once the integration completes, I'll play around with it some more and potentially change this
-// implementation to use std::isnan() if it is exactly commensurate with our usage.
-static bool isNan(double value) {
- return (value != value);
-}
-
-static double grabDouble(
- JSContextRef ctx,
- const JSValueRef arguments[],
- size_t argumentIndex,
- JSValueRef* exception) {
- return JSValueToNumber(ctx, arguments[argumentIndex], exception);
-}
-
-// Safely translates JSValues to an array of doubles.
-static bool grabDoubles(
- size_t targetsCount,
- double targets[],
- JSContextRef ctx,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- if (argumentCount < targetsCount) {
- return false;
- }
- for (size_t i = 0 ; i < targetsCount ; i++) {
- targets[i] = grabDouble(ctx, arguments, i, exception);
- if (isNan(targets[i])) {
- return false;
- }
- }
- return true;
-}
-
-static local_ref<jstring> getJStringFromJSValueRef(JSContextRef ctx, JSValueRef ref) {
- JSStringRef jsStringRef = JSValueToStringCopy(ctx, ref, nullptr);
- const JSChar* chars = JSStringGetCharactersPtr(jsStringRef);
- const size_t length = JSStringGetLength(jsStringRef);
- local_ref<jstring> returnStr = adopt_local(Environment::current()->NewString(chars, length));
- JSStringRelease(jsStringRef);
- return returnStr;
-}
-
-static JSValueRef nativeQPLMarkerStart(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- double targets[3];
- if (isReady() && grabDoubles(3, targets, ctx, argumentCount, arguments, exception)) {
- int32_t markerId = (int32_t) targets[0];
- int32_t instanceKey = (int32_t) targets[1];
- int64_t timestamp = (int64_t) targets[2];
- JQuickPerformanceLoggerProvider::get()->markerStart(markerId, instanceKey, timestamp);
- }
- return JSValueMakeUndefined(ctx);
-}
-
-static JSValueRef nativeQPLMarkerEnd(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- double targets[4];
- if (isReady() && grabDoubles(4, targets, ctx, argumentCount, arguments, exception)) {
- int32_t markerId = (int32_t) targets[0];
- int32_t instanceKey = (int32_t) targets[1];
- // NOTE: avoid undefined behavior when the value does not find in int16_t.
- int16_t actionId = (int16_t) (int32_t) targets[2];
- int64_t timestamp = (int64_t) targets[3];
- JQuickPerformanceLoggerProvider::get()->markerEnd(markerId, instanceKey, actionId, timestamp);
- }
- return JSValueMakeUndefined(ctx);
-}
-
-static JSValueRef nativeQPLMarkerTag(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- double targets[2];
- if (isReady() && grabDoubles(2, targets, ctx, argumentCount, arguments, exception)) {
- int32_t markerId = (int32_t) targets[0];
- int32_t instanceKey = (int32_t) targets[1];
- local_ref<jstring> tag = getJStringFromJSValueRef(ctx, arguments[2]);
- JQuickPerformanceLoggerProvider::get()->markerTag(markerId, instanceKey, tag);
- }
- return JSValueMakeUndefined(ctx);
-}
-
-static JSValueRef nativeQPLMarkerAnnotate(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- double targets[2];
- if (isReady() && grabDoubles(2, targets, ctx, argumentCount, arguments, exception)) {
- int32_t markerId = (int32_t) targets[0];
- int32_t instanceKey = (int32_t) targets[1];
- local_ref<jstring> key = getJStringFromJSValueRef(ctx, arguments[2]);
- local_ref<jstring> value = getJStringFromJSValueRef(ctx, arguments[3]);
- JQuickPerformanceLoggerProvider::get()->markerAnnotate(markerId, instanceKey, key, value);
- }
- return JSValueMakeUndefined(ctx);
-}
-
-static JSValueRef nativeQPLMarkerNote(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- double targets[4];
- if (isReady() && grabDoubles(4, targets, ctx, argumentCount, arguments, exception)) {
- int32_t markerId = (int32_t) targets[0];
- int32_t instanceKey = (int32_t) targets[1];
- // NOTE: avoid undefined behavior when the value does not find in int16_t.
- int16_t actionId = (int16_t) (int32_t) targets[2];
- int64_t timestamp = (int64_t) targets[3];
- JQuickPerformanceLoggerProvider::get()->markerNote(markerId, instanceKey, actionId, timestamp);
- }
- return JSValueMakeUndefined(ctx);
-}
-
-static JSValueRef nativeQPLMarkerCancel(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- double targets[2];
- if (isReady() && grabDoubles(2, targets, ctx, argumentCount, arguments, exception)) {
- int32_t markerId = (int32_t) targets[0];
- int32_t instanceKey = (int32_t) targets[1];
- JQuickPerformanceLoggerProvider::get()->markerCancel(markerId, instanceKey);
- }
- return JSValueMakeUndefined(ctx);
-}
-
-static JSValueRef nativeQPLTimestamp(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- if (!isReady()) {
- return JSValueMakeNumber(ctx, 0);
- }
- int64_t timestamp = JQuickPerformanceLoggerProvider::get()->currentMonotonicTimestamp();
- // Since this is monotonic time, I assume the 52 bits of mantissa are enough in the double value.
- return JSValueMakeNumber(ctx, timestamp);
-}
-
-static JSValueRef nativeQPLMarkerPoint(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- if (isReady() && argumentCount == 4) {
- double markerIdArgument = grabDouble(ctx, arguments, 0, exception);
- double instanceKeyArgument = grabDouble(ctx, arguments, 2, exception);
- if (isNan(markerIdArgument) || isNan(instanceKeyArgument)) {
- return JSValueMakeUndefined(ctx);
- }
-
- int32_t markerId = (int32_t) markerIdArgument;
- local_ref<jstring> name = getJStringFromJSValueRef(ctx, arguments[1]);
- int32_t instanceKey = (int32_t) instanceKeyArgument;
- // timestamp is not used as QuickPerformanceLogger::markerPoint with all
- // params is missing
- JQuickPerformanceLoggerProvider::get()->markerPoint(markerId, name, instanceKey);
- }
- return JSValueMakeUndefined(ctx);
-}
-
-void addNativePerfLoggingHooks(JSGlobalContextRef ctx) {
- installGlobalFunction(ctx, "nativeQPLMarkerStart", nativeQPLMarkerStart);
- installGlobalFunction(ctx, "nativeQPLMarkerEnd", nativeQPLMarkerEnd);
- installGlobalFunction(ctx, "nativeQPLMarkerTag", nativeQPLMarkerTag);
- installGlobalFunction(ctx, "nativeQPLMarkerAnnotate", nativeQPLMarkerAnnotate);
- installGlobalFunction(ctx, "nativeQPLMarkerNote", nativeQPLMarkerNote);
- installGlobalFunction(ctx, "nativeQPLMarkerCancel", nativeQPLMarkerCancel);
- installGlobalFunction(ctx, "nativeQPLTimestamp", nativeQPLTimestamp);
- installGlobalFunction(ctx, "nativeQPLMarkerPoint", nativeQPLMarkerPoint);
-}
-
-} }

ReactAndroid/src/main/jni/react/jni/JSCPerfLogging.h

@@ -1,15 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#pragma once
-
-#include <JavaScriptCore/JSContextRef.h>
-
-namespace facebook {
-namespace react {
-
-void addNativePerfLoggingHooks(JSGlobalContextRef ctx);
-
-} }

ReactAndroid/src/main/jni/react/jni/JSLoader.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -59,8 +59,9 @@
}
}
- throw std::runtime_error(folly::to<std::string>("Unable to load script from assets '", assetName,
- "'. Make sure your bundle is packaged correctly or you're running a packager server."));
+ throw std::runtime_error(folly::to<std::string>("Unable to load script. Make sure you're "
+ "either running a Metro server (run 'react-native start') or that your bundle '", assetName,
+ "' is packaged correctly for release."));
}
}}

ReactAndroid/src/main/jni/react/jni/JSLoader.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/JSLogging.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/JSLogging.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/MethodInvoker.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/MethodInvoker.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/ModuleRegistryBuilder.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/ModuleRegistryBuilder.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/NativeArray.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/NativeArray.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/NativeCommon.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/NativeCommon.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/NativeDeltaClient.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/NativeDeltaClient.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/NativeMap.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/NativeMap.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/OnLoad.cpp

@@ -1,15 +1,16 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
#include <string>
+#include <glog/logging.h>
+
#include <fb/fbjni.h>
#include <fb/glog_init.h>
#include <fb/log.h>
-#include "AndroidJSCFactory.h"
#include "CatalystInstanceImpl.h"
#include "CxxModuleWrapper.h"
#include "JavaScriptExecutorHolder.h"
@@ -30,27 +31,6 @@
namespace {
-// TODO: can we avoid these wrapper classes, and instead specialize the logic in CatalystInstanceImpl
-class JSCJavaScriptExecutorHolder : public HybridClass<JSCJavaScriptExecutorHolder,
- JavaScriptExecutorHolder> {
- public:
- static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/JSCJavaScriptExecutor;";
-
- static local_ref<jhybriddata> initHybrid(alias_ref<jclass>, ReadableNativeMap* jscConfig) {
- return makeCxxInstance(makeAndroidJSCExecutorFactory(jscConfig->consume()));
- }
-
- static void registerNatives() {
- registerHybrid({
- makeNativeMethod("initHybrid", JSCJavaScriptExecutorHolder::initHybrid),
- });
- }
-
- private:
- friend HybridBase;
- using HybridBase::HybridBase;
-};
-
struct JavaJSExecutor : public JavaClass<JavaJSExecutor> {
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/JavaJSExecutor;";
};
@@ -83,7 +63,7 @@
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
return initialize(vm, [] {
gloginit::initialize();
- JSCJavaScriptExecutorHolder::registerNatives();
+ FLAGS_minloglevel = 0;
ProxyJavaScriptExecutorHolder::registerNatives();
CatalystInstanceImpl::registerNatives();
CxxModuleWrapperBase::registerNatives();

ReactAndroid/src/main/jni/react/jni/OnLoad.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/ReadableNativeArray.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/ReadableNativeArray.h

@@ -1,4 +1,7 @@
- // Copyright 2004-present Facebook. All Rights Reserved.
+// 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.
#pragma once
@@ -10,6 +13,10 @@
namespace facebook {
namespace react {
+struct ReadableArray : jni::JavaClass<ReadableArray> {
+ static auto constexpr kJavaDescriptor = "Lcom/facebook/react/bridge/ReadableArray;";
+};
+
class ReadableNativeArray : public jni::HybridClass<ReadableNativeArray, NativeArray> {
protected:
friend HybridBase;

ReactAndroid/src/main/jni/react/jni/ReadableNativeMap.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/ReadableNativeMap.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -19,6 +19,10 @@
struct WritableNativeMap;
+struct ReadableMap : jni::JavaClass<ReadableMap> {
+ static auto constexpr kJavaDescriptor = "Lcom/facebook/react/bridge/ReadableMap;";
+};
+
struct ReadableNativeMap : jni::HybridClass<ReadableNativeMap, NativeMap> {
static auto constexpr kJavaDescriptor = "Lcom/facebook/react/bridge/ReadableNativeMap;";

ReactAndroid/src/main/jni/react/jni/WritableNativeArray.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/WritableNativeArray.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -16,6 +16,10 @@
struct WritableNativeMap;
+struct WritableArray : jni::JavaClass<WritableArray> {
+ static auto constexpr kJavaDescriptor = "Lcom/facebook/react/bridge/WritableArray;";
+};
+
struct WritableNativeArray
: public jni::HybridClass<WritableNativeArray, ReadableNativeArray> {
static constexpr const char* kJavaDescriptor = "Lcom/facebook/react/bridge/WritableNativeArray;";

ReactAndroid/src/main/jni/react/jni/WritableNativeMap.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/react/jni/WritableNativeMap.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -15,6 +15,10 @@
namespace facebook {
namespace react {
+struct WritableMap : jni::JavaClass<WritableMap> {
+ static auto constexpr kJavaDescriptor = "Lcom/facebook/react/bridge/WritableMap;";
+};
+
struct WritableNativeMap : jni::HybridClass<WritableNativeMap, ReadableNativeMap> {
static auto constexpr kJavaDescriptor = "Lcom/facebook/react/bridge/WritableNativeMap;";

ReactAndroid/src/main/jni/react/perftests/OnLoad.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactAndroid/src/main/jni/third-party/folly/Android.mk

@@ -6,16 +6,32 @@
folly/Unicode.cpp \
folly/Conv.cpp \
folly/Demangle.cpp \
- folly/detail/MallocImpl.cpp \
- folly/StringBase.cpp \
+ folly/memory/detail/MallocImpl.cpp \
+ folly/String.cpp \
folly/dynamic.cpp \
+ folly/Format.cpp \
+ folly/json_pointer.cpp \
+ folly/lang/ColdClass.cpp \
+ folly/detail/Demangle.cpp \
+ folly/hash/SpookyHashV2.cpp \
+ folly/container/detail/F14Table.cpp \
+ folly/ScopeGuard.cpp \
LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
-LOCAL_CFLAGS += -fexceptions -fno-omit-frame-pointer -frtti
+LOCAL_CFLAGS += -fexceptions -fno-omit-frame-pointer -frtti -Wno-sign-compare
+
+FOLLY_FLAGS := \
+ -DFOLLY_NO_CONFIG=1 \
+ -DFOLLY_HAVE_CLOCK_GETTIME=1 \
+ -DFOLLY_HAVE_MEMRCHR=1 \
+ -DFOLLY_USE_LIBCPP=1
+
+# If APP_PLATFORM in Application.mk targets android-23 above, please comment this line.
+# NDK uses GNU style stderror_r() after API 23.
+FOLLY_FLAGS += -DFOLLY_HAVE_XSI_STRERROR_R=1
-FOLLY_FLAGS := -DFOLLY_NO_CONFIG=1 -DFOLLY_HAVE_CLOCK_GETTIME=1 -DFOLLY_HAVE_MEMRCHR=1
LOCAL_CFLAGS += $(FOLLY_FLAGS)
LOCAL_EXPORT_CPPFLAGS := $(FOLLY_FLAGS)

ReactAndroid/src/main/jni/third-party/glibc/BUCK

@@ -4,7 +4,9 @@
# libpthread is implicitly included in the android runtime so, when building
# on an android platform, we don't do anything.
-prebuilt_cxx_library(
+load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
+
+fb_native.prebuilt_cxx_library(
name = "pthread",
exported_platform_linker_flags = [
(
@@ -26,7 +28,7 @@
],
)
-prebuilt_cxx_library(
+fb_native.prebuilt_cxx_library(
name = "dl",
exported_linker_flags = [
"-ldl",
@@ -37,7 +39,7 @@
],
)
-prebuilt_cxx_library(
+fb_native.prebuilt_cxx_library(
name = "m",
exported_linker_flags = [
"-lm",
@@ -48,7 +50,7 @@
],
)
-prebuilt_cxx_library(
+fb_native.prebuilt_cxx_library(
name = "rt",
exported_platform_linker_flags = [
(

ReactAndroid/src/main/jni/third-party/glog/Android.mk

@@ -13,7 +13,7 @@
LOCAL_C_INCLUDES += $(LOCAL_PATH) $(LOCAL_PATH)/.. $(LOCAL_PATH)/glog-0.3.5/src/
-LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/.. $(LOCAL_PATH)/glog-0.3.5/src/
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/exported
LOCAL_CFLAGS += \
-Wwrite-strings \
@@ -23,7 +23,8 @@
-g \
-O2 \
-D_START_GOOGLE_NAMESPACE_="namespace google {" \
- -D_END_GOOGLE_NAMESPACE_="}"
+ -D_END_GOOGLE_NAMESPACE_="}" \
+ -DHAVE_PREAD=1
LOCAL_MODULE := glog

ReactAndroid/src/main/libraries/fbcore/src/test/java/com/facebook/powermock/BUCK

@@ -1,3 +1,4 @@
+load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
load("//tools/build_defs/oss:rn_defs.bzl", "rn_android_library", "rn_prebuilt_jar")
rn_android_library(
@@ -25,7 +26,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "download-powermock-core.jar",
sha1 = "ea04e79244e19dcf0c3ccf6863c5b028b4b58c9c",
url = "mvn:org.powermock:powermock-core:jar:1.6.2",
@@ -37,7 +38,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "download-powermock-api-mockito.jar",
sha1 = "c213230ae20a7b422f3d622a261d0e3427d2464c",
url = "mvn:org.powermock:powermock-api-mockito:jar:1.6.2",
@@ -49,7 +50,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "download-powermock-api-support.jar",
sha1 = "93b21413b4ee99b7bc0dd34e1416fdca96866aaf",
url = "mvn:org.powermock:powermock-api-support:jar:1.6.2",
@@ -61,7 +62,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "download-powermock-module-junit4-rule.jar",
sha1 = "4847638c5729b9f203e21144b0bdb5d34d888473",
url = "mvn:org.powermock:powermock-module-junit4-rule:jar:1.6.2",
@@ -73,7 +74,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "download-powermock-classloading-xstream.jar",
sha1 = "3ced31cd7024fe365b9f3c8082d22c02434577da",
url = "mvn:org.powermock:powermock-classloading-xstream:jar:1.6.2",
@@ -85,7 +86,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "download-powermock-classloading-base.jar",
sha1 = "c8bfc10731a02d3b241892cf2c334a754d473ca7",
url = "mvn:org.powermock:powermock-classloading-base:jar:1.6.2",
@@ -97,7 +98,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "download-xstream.jar",
sha1 = "97e5013f391487cce4de6b0eebcde21549e91872",
url = "mvn:com.thoughtworks.xstream:xstream:jar:1.4.2",
@@ -109,7 +110,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "download-powermock-reflect.jar",
sha1 = "1af1bbd1207c3ecdcf64973e6f9d57dcd17cc145",
url = "mvn:org.powermock:powermock-reflect:jar:1.6.2",
@@ -121,7 +122,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "download-javassist.jar",
sha1 = "a9cbcdfb7e9f86fbc74d3afae65f2248bfbf82a0",
url = "mvn:org.javassist:javassist:jar:3.20.0-GA",
@@ -133,7 +134,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "download-mockito-all.jar",
sha1 = "539df70269cc254a58cccc5d8e43286b4a73bf30",
url = "mvn:org.mockito:mockito-all:jar:1.10.19",
@@ -145,7 +146,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "download-xmlpull.jar",
sha1 = "2b8e230d2ab644e4ecaa94db7cdedbc40c805dfa",
url = "mvn:xmlpull:xmlpull:jar:1.1.3.1",
@@ -157,7 +158,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "download-xpp3.jar",
sha1 = "19d4e90b43059058f6e056f794f0ea4030d60b86",
url = "mvn:xpp3:xpp3_min:jar:1.1.4c",

ReactAndroid/src/main/libraries/fresco/fresco-react-native/BUCK

@@ -1,3 +1,4 @@
+load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
load("//tools/build_defs/oss:rn_defs.bzl", "rn_android_library", "rn_android_prebuilt_aar", "rn_prebuilt_jar")
rn_android_prebuilt_aar(
@@ -6,19 +7,19 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "fresco-binary-aar",
sha1 = "076812472879be341f392c4aab469b8fdf8c6759",
url = "mvn:com.facebook.fresco:fresco:aar:1.10.0",
)
-android_prebuilt_aar(
+rn_android_prebuilt_aar(
name = "fresco-drawee",
aar = ":drawee-binary-aar",
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "drawee-binary-aar",
sha1 = "c1fef7cdc5f6e4fd7d7c58522075c6b66f46a52b",
url = "mvn:com.facebook.fresco:drawee:aar:1.10.0",
@@ -40,7 +41,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "imagepipeline-base-aar",
sha1 = "56672fa5fa46bf4962adecc7c88a1544f5a20225",
url = "mvn:com.facebook.fresco:imagepipeline-base:aar:1.10.0",
@@ -52,7 +53,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "imagepipeline-aar",
sha1 = "e317bdb7f18f0f4ac4f3ab5d3edb49fd09290a6f",
url = "mvn:com.facebook.fresco:imagepipeline:aar:1.10.0",
@@ -64,31 +65,31 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "download-bolts.jar",
sha1 = "d85884acf6810a3bbbecb587f239005cbc846dc4",
url = "mvn:com.parse.bolts:bolts-tasks:jar:1.4.0",
)
-android_prebuilt_aar(
+rn_android_prebuilt_aar(
name = "fbcore",
aar = ":fbcore-aar",
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "fbcore-aar",
sha1 = "d79dbf5e47d6e528dd1f90170e0299c14d835ab8",
url = "mvn:com.facebook.fresco:fbcore:aar:1.10.0",
)
-android_prebuilt_aar(
+rn_android_prebuilt_aar(
name = "imagepipeline-okhttp3",
aar = ":imagepipeline-okhttp3-binary-aar",
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "imagepipeline-okhttp3-binary-aar",
sha1 = "3429ffb776d7511d0f911fbe9efda4c73179d416",
url = "mvn:com.facebook.fresco:imagepipeline-okhttp3:aar:1.10.0",

ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/BUCK

@@ -1,11 +1,13 @@
-android_prebuilt_aar(
+load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
+
+fb_native.android_prebuilt_aar(
name = "soloader",
aar = ":soloader-binary-aar",
visibility = ["PUBLIC"],
)
-remote_file(
+fb_native.remote_file(
name = "soloader-binary-aar",
- sha1 = "042357559a6c9313bdb9b1ba137a9df3b5365f35",
- url = "mvn:com.facebook.soloader:soloader:aar:0.5.1",
+ sha1 = "4de8f64830aff60beb52fb27dffb2fcbe54c39df",
+ url = "mvn:com.facebook.soloader:soloader:aar:0.6.0",
)

ReactAndroid/src/main/res/devsupport/drawable/redbox_top_border_background.xml

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item>
+ <shape android:shape="rectangle" >
+ <solid android:color="#1A1A1A" />
+ </shape>
+ </item>
+
+ <item android:bottom="-2dp" android:right="-2dp" android:left="-2dp">
+ <shape>
+ <solid android:color="@android:color/transparent" />
+ <stroke
+ android:width="1dp"
+ android:color="#B3B3B3" />
+ </shape>
+ </item>
+</layer-list>

ReactAndroid/src/main/res/devsupport/layout/redbox_item_frame.xml

@@ -19,7 +19,7 @@
android:id="@+id/rn_frame_file"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:textColor="#E6B8B8"
+ android:textColor="#B3B3B3"
android:textSize="12sp"
android:fontFamily="monospace"
/>

ReactAndroid/src/main/res/devsupport/layout/redbox_item_title.xml

@@ -7,4 +7,5 @@
android:textColor="@android:color/white"
android:textSize="16sp"
android:textStyle="bold"
+ android:background="#D01926"
/>

ReactAndroid/src/main/res/devsupport/layout/redbox_view.xml

@@ -3,7 +3,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:background="#E80000"
+ android:background="#1A1A1A"
>
<ListView
android:id="@+id/rn_redbox_stack"
@@ -53,6 +53,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
+ android:background="@drawable/redbox_top_border_background"
>
<Button
android:id="@+id/rn_redbox_dismiss_button"

ReactAndroid/src/main/res/devsupport/values/strings.xml

@@ -21,7 +21,7 @@
<string name="catalyst_dismiss_button" project="catalyst" translatable="false">Dismiss\n(ESC)</string>
<string name="catalyst_reload_button" project="catalyst" translatable="false">Reload\n(R,\u00A0R)</string>
<string name="catalyst_poke_sampling_profiler" project="catalyst" translatable="false">Start/Stop Sampling Profiler</string>
- <string name="catalyst_copy_button" project="catalyst" translatable="false">Copy</string>
+ <string name="catalyst_copy_button" project="catalyst" translatable="false">Copy\n</string>
<string name="catalyst_report_button" project="catalyst" translatable="false">Report</string>
<string name="catalyst_loading_from_url" project="catalyst" translatable="false">Loading from %1$s…</string>
</resources>

ReactAndroid/src/main/res/devsupport/xml/preferences.xml

@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<PreferenceScreen
- xmlns:android="http://schemas.android.com/apk/res/android"
- >
- <PreferenceCategory
- android:key="catalyst_perf"
- android:title="Performance"
- >
- <CheckBoxPreference
- android:key="js_dev_mode_debug"
- android:title="JS Dev Mode"
- android:summary="Load JavaScript bundle with __DEV__ = true for easier debugging. Disable for performance testing. Reload for the change to take effect."
- android:defaultValue="true"
- />
- <CheckBoxPreference
- android:key="js_minify_debug"
- android:title="JS Minify"
- android:summary="Load JavaScript bundle with minify=true for debugging minification issues."
- android:defaultValue="false"
- />
- <CheckBoxPreference
- android:key="js_bundle_deltas"
- android:title="Use JS Deltas"
- android:summary="Request delta bundles from metro to get faster reloads (Experimental)"
- android:defaultValue="true"
- />
- <CheckBoxPreference
- android:key="js_bundle_deltas_cpp"
- android:title="Native Delta Handling"
- android:summary="Handles delta bundles in native code without writing code to disk (Experimental)."
- android:defaultValue="false"
- android:dependency="js_bundle_deltas"
- />
- <CheckBoxPreference
- android:key="animations_debug"
- android:title="Animations FPS Summaries"
- android:summary="At the end of animations, Toasts and logs to logcat debug information about the FPS during that transition. Currently only supported for transitions (animated navigations)."
- android:defaultValue="false"
- />
- </PreferenceCategory>
- <PreferenceCategory
- android:key="pref_key_catalyst_debug"
- android:title="Debugging"
- >
- <EditTextPreference
- android:key="debug_http_host"
- android:title="Debug server host &amp; port for device"
- android:summary="Debug server host &amp; port for downloading JS bundle or communicating with JS debugger. With this setting empty launcher should work fine when running on emulator (or genymotion) and connection to debug server running on emulator's host."
- android:defaultValue=""
- />
- <CheckBoxPreference
- android:key="start_sampling_profiler_on_init"
- android:title="Start Sampling Profiler on init"
- android:summary="If true the Sampling Profiler will start on initialization of JS. Useful for profiling startup of the app. Reload JS after setting."
- android:defaultValue="false"
- />
- <EditTextPreference
- android:key="sampling_profiler_sample_interval"
- android:title="Sample interval for Sampling Profiler"
- android:summary="Sample interval in microseconds for the Sampling Profiler (default: 1000). Reload JS after setting."
- android:defaultValue="1000"
- android:inputType="number"
- />
- </PreferenceCategory>
-</PreferenceScreen>

ReactAndroid/src/main/res/devsupport/xml/rn_dev_preferences.xml

@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ >
+ <PreferenceCategory
+ android:key="catalyst_perf"
+ android:title="Performance"
+ >
+ <CheckBoxPreference
+ android:key="js_dev_mode_debug"
+ android:title="JS Dev Mode"
+ android:summary="Load JavaScript bundle with __DEV__ = true for easier debugging. Disable for performance testing. Reload for the change to take effect."
+ android:defaultValue="true"
+ />
+ <CheckBoxPreference
+ android:key="js_minify_debug"
+ android:title="JS Minify"
+ android:summary="Load JavaScript bundle with minify=true for debugging minification issues."
+ android:defaultValue="false"
+ />
+ <CheckBoxPreference
+ android:key="js_bundle_deltas"
+ android:title="Use JS Deltas"
+ android:summary="Request delta bundles from metro to get faster reloads (Experimental)"
+ android:defaultValue="false"
+ />
+ <CheckBoxPreference
+ android:key="js_bundle_deltas_cpp"
+ android:title="Native Delta Handling"
+ android:summary="Handles delta bundles in native code without writing code to disk (Experimental)."
+ android:defaultValue="false"
+ android:dependency="js_bundle_deltas"
+ />
+ <CheckBoxPreference
+ android:key="animations_debug"
+ android:title="Animations FPS Summaries"
+ android:summary="At the end of animations, Toasts and logs to logcat debug information about the FPS during that transition. Currently only supported for transitions (animated navigations)."
+ android:defaultValue="false"
+ />
+ </PreferenceCategory>
+ <PreferenceCategory
+ android:key="pref_key_catalyst_debug"
+ android:title="Debugging"
+ >
+ <EditTextPreference
+ android:key="debug_http_host"
+ android:title="Debug server host &amp; port for device"
+ android:summary="Debug server host &amp; port for downloading JS bundle or communicating with JS debugger. With this setting empty launcher should work fine when running on emulator (or genymotion) and connection to debug server running on emulator's host."
+ android:defaultValue=""
+ />
+ <CheckBoxPreference
+ android:key="start_sampling_profiler_on_init"
+ android:title="Start Sampling Profiler on init"
+ android:summary="If true the Sampling Profiler will start on initialization of JS. Useful for profiling startup of the app. Reload JS after setting."
+ android:defaultValue="false"
+ />
+ <EditTextPreference
+ android:key="sampling_profiler_sample_interval"
+ android:title="Sample interval for Sampling Profiler"
+ android:summary="Sample interval in microseconds for the Sampling Profiler (default: 1000). Reload JS after setting."
+ android:defaultValue="1000"
+ android:inputType="number"
+ />
+ </PreferenceCategory>
+</PreferenceScreen>

ReactAndroid/src/main/res/views/uimanager/values/strings.xml

@@ -20,4 +20,8 @@
name="adjustable_description"
translatable="false"
>Adjustable</string>
+ <string
+ name="header_description"
+ translatable="false"
+ >Heading</string>
</resources>

ReactAndroid/src/main/third-party/android/support/BUCK

@@ -0,0 +1,26 @@
+load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
+load("//tools/build_defs/oss:rn_defs.bzl", "react_native_dep", "rn_android_library")
+
+rn_android_library(
+ name = "support-v4",
+ visibility = ["PUBLIC"],
+ exported_deps = [
+ react_native_dep("third-party/android/support:support-v4"),
+ ],
+)
+
+rn_android_library(
+ name = "appcompat-v7",
+ visibility = ["PUBLIC"],
+ exported_deps = [
+ react_native_dep("third-party/android/support:support-v4"),
+ ],
+)
+
+# a fake genrule so that BUCK files in react native are preseable in fbsource
+fb_native.genrule(
+ name = "appcompat-res-cmd",
+ out = ".",
+ bash = "ls",
+ visibility = ["PUBLIC"],
+)

ReactAndroid/src/main/third-party/android/support/v4/BUCK

@@ -1,114 +1,370 @@
-android_library(
+load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
+
+fb_native.android_library(
name = "lib-support-v4",
visibility = ["PUBLIC"],
exported_deps = [
- ":android-lifecycle-common",
- ":android-lifecycle-core",
- ":android-lifecycle-runtime",
- ":android-lifecycle-viewmodel",
- ":lib-support-v4-support-compat",
- ":lib-support-v4-support-core-ui",
- ":lib-support-v4-support-core-utils",
- ":lib-support-v4-support-fragment",
+ ":animated-vector-drawable",
+ ":arch-common",
+ ":arch-runtime",
+ ":asynclayoutinflater",
+ ":collections",
+ ":coordinatorlayout",
+ ":cursoradapter",
+ ":customview",
+ ":documentfile",
+ ":drawerlayout",
+ ":interpolator",
+ ":support-annotations",
+ ":support-compat",
+ ":support-core-ui",
+ ":support-core-utils",
+ ":support-vector-drawable",
+ ":support-fragment",
":lib-support-v4-support-media-compat",
+ ":lifecycle-common",
+ ":lifecycle-runtime",
+ ":lifecycle-viewmodel",
+ ":livedata-core",
+ ":livedata",
+ ":loader",
+ ":localbroadcastmanager",
+ ":print",
+ ":slidingpanelayout",
+ ":swiperefreshlayout",
+ ":versionedparcelable",
+ ":viewpager",
],
)
-prebuilt_jar(
- name = "android-lifecycle-common",
- binary_jar = ":android-lifecycle-common.jar",
+fb_native.android_prebuilt_aar(
+ name = "animated-vector-drawable",
+ aar = ":animated-vector-drawable-aar",
+)
+
+fb_native.android_prebuilt_aar(
+ name = "asynclayoutinflater",
+ aar = ":asynclayoutinflater-aar",
+)
+
+fb_native.prebuilt_jar(
+ name = "lifecycle-common",
+ binary_jar = ":lifecycle-common.jar",
+)
+
+fb_native.prebuilt_jar(
+ name = "arch-common",
+ binary_jar = ":arch-common.jar",
+)
+
+fb_native.android_prebuilt_aar(
+ name = "arch-runtime",
+ aar = ":arch-runtime-aar",
+)
+
+fb_native.android_prebuilt_aar(
+ name = "lifecycle-runtime",
+ aar = ":lifecycle-runtime-aar",
)
-prebuilt_jar(
- name = "android-lifecycle-core",
- binary_jar = ":android-lifecycle-core.jar",
+fb_native.android_prebuilt_aar(
+ name = "lifecycle-viewmodel",
+ aar = ":lifecycle-viewmodel-aar",
)
-android_prebuilt_aar(
- name = "android-lifecycle-runtime",
- aar = ":android-lifecycle-runtime-aar",
+fb_native.prebuilt_jar(
+ name = "collections",
+ binary_jar = ":collections.jar",
)
-android_prebuilt_aar(
- name = "android-lifecycle-viewmodel",
- aar = ":android-lifecycle-viewmodel-aar",
+fb_native.android_prebuilt_aar(
+ name = "coordinatorlayout",
+ aar = ":coordinatorlayout-aar",
)
-android_prebuilt_aar(
- name = "lib-support-v4-support-compat",
- aar = ":lib-support-v4-support-compat-aar",
+fb_native.android_prebuilt_aar(
+ name = "cursoradapter",
+ aar = ":cursoradapter-aar",
)
-android_prebuilt_aar(
- name = "lib-support-v4-support-core-utils",
- aar = ":lib-support-v4-support-core-utils-aar",
+fb_native.android_prebuilt_aar(
+ name = "customview",
+ aar = ":customview-aar",
)
-android_prebuilt_aar(
- name = "lib-support-v4-support-core-ui",
- aar = ":lib-support-v4-support-core-ui-aar",
+fb_native.android_prebuilt_aar(
+ name = "documentfile",
+ aar = ":documentfile-aar",
)
-android_prebuilt_aar(
+fb_native.android_prebuilt_aar(
+ name = "drawerlayout",
+ aar = ":drawerlayout-aar",
+)
+
+fb_native.android_prebuilt_aar(
+ name = "interpolator",
+ aar = ":interpolator-aar",
+)
+
+fb_native.prebuilt_jar(
+ name = "support-annotations",
+ binary_jar = ":support-annotations.jar",
+)
+
+fb_native.android_prebuilt_aar(
+ name = "support-compat",
+ aar = ":support-compat-aar",
+)
+
+fb_native.android_prebuilt_aar(
+ name = "support-core-utils",
+ aar = ":support-core-utils-aar",
+)
+
+fb_native.android_prebuilt_aar(
+ name = "support-core-ui",
+ aar = ":support-core-ui-aar",
+)
+
+fb_native.android_prebuilt_aar(
+ name = "support-vector-drawable",
+ aar = ":support-vector-drawable-aar",
+)
+
+fb_native.android_prebuilt_aar(
name = "lib-support-v4-support-media-compat",
aar = ":lib-support-v4-support-media-compat-aar",
)
-android_prebuilt_aar(
- name = "lib-support-v4-support-fragment",
- aar = ":lib-support-v4-support-fragment-aar",
+fb_native.android_prebuilt_aar(
+ name = "support-fragment",
+ aar = ":support-fragment-aar",
+)
+
+fb_native.android_prebuilt_aar(
+ name = "livedata-core",
+ aar = ":livedata-core-aar",
+)
+
+fb_native.android_prebuilt_aar(
+ name = "livedata",
+ aar = ":livedata-aar",
+)
+
+fb_native.android_prebuilt_aar(
+ name = "loader",
+ aar = ":loader-aar",
+)
+
+fb_native.android_prebuilt_aar(
+ name = "localbroadcastmanager",
+ aar = ":localbroadcastmanager-aar",
+)
+
+fb_native.android_prebuilt_aar(
+ name = "print",
+ aar = ":print-aar",
+)
+
+fb_native.android_prebuilt_aar(
+ name = "slidingpanelayout",
+ aar = ":slidingpanelayout-aar",
+)
+
+fb_native.android_prebuilt_aar(
+ name = "swiperefreshlayout",
+ aar = ":swiperefreshlayout-aar",
+)
+
+fb_native.android_prebuilt_aar(
+ name = "versionedparcelable",
+ aar = ":versionedparcelable-aar",
+)
+
+fb_native.android_prebuilt_aar(
+ name = "viewpager",
+ aar = ":viewpager-aar",
)
-remote_file(
- name = "android-lifecycle-runtime-aar",
- sha1 = "95428e5f6bf6875a6a1125d2157c3836a1a837f5",
- url = "mvn:android.arch.lifecycle:runtime:aar:1.1.0",
+# remote files
+fb_native.remote_file(
+ name = "asynclayoutinflater-aar",
+ sha1 = "3ae7643d120e6da3adbe2d698de923f48c904d1f",
+ url = "mvn:com.android.support:asynclayoutinflater:aar:28.0.0",
)
-remote_file(
- name = "android-lifecycle-common.jar",
- sha1 = "0edf3f7bfb84a7521d0599efa3b0113a0ee90f85",
- url = "mvn:android.arch.lifecycle:common:jar:1.1.0",
+fb_native.remote_file(
+ name = "lifecycle-runtime-aar",
+ sha1 = "4286e1ae9364b485cb2ff7a370e355b7c570015b",
+ url = "mvn:android.arch.lifecycle:runtime:aar:1.1.1",
)
-remote_file(
- name = "android-lifecycle-core.jar",
- sha1 = "8007981f7d7540d89cd18471b8e5dcd2b4f99167",
- url = "mvn:android.arch.core:common:jar:1.1.0",
+fb_native.remote_file(
+ name = "lifecycle-common.jar",
+ sha1 = "207a6efae6a3555e326de41f76bdadd9a239cbce",
+ url = "mvn:android.arch.lifecycle:common:jar:1.1.1",
)
-remote_file(
- name = "android-lifecycle-viewmodel-aar",
- sha1 = "74ee369b874da61b5b81bebd7b8df0c2577309c8",
- url = "mvn:android.arch.lifecycle:viewmodel:aar:1.1.0",
+fb_native.remote_file(
+ name = "arch-common.jar",
+ sha1 = "e55b70d1f5620db124b3e85a7f4bdc7bd48d9f95",
+ url = "mvn:android.arch.core:common:jar:1.1.1",
)
-remote_file(
- name = "lib-support-v4-support-compat-aar",
- sha1 = "a55ad550d0b84c7fec7ecca012690636062c0e64",
- url = "mvn:com.android.support:support-compat:aar:27.1.1",
+fb_native.remote_file(
+ name = "arch-runtime-aar",
+ sha1 = "a7e27caf787e14c0d8417be907f4a31f0306acb2",
+ url = "mvn:android.arch.core:runtime:aar:1.1.1",
)
-remote_file(
- name = "lib-support-v4-support-core-utils-aar",
- sha1 = "b3a7a4040fda0c5138dbc8c477103b6723b9dbe6",
- url = "mvn:com.android.support:support-core-utils:aar:27.1.1",
+
+fb_native.remote_file(
+ name = "lifecycle-viewmodel-aar",
+ sha1 = "897b6e22c8357b23ab0c7600c961549c098f5ccf",
+ url = "mvn:android.arch.lifecycle:viewmodel:aar:1.1.1",
+)
+
+fb_native.remote_file(
+ name = "collections.jar",
+ sha1 = "c1bcdade4d3cc2836130424a3f3e4182c666a745",
+ url = "mvn:com.android.support:collections:jar:28.0.0",
+)
+
+fb_native.remote_file(
+ name = "coordinatorlayout-aar",
+ sha1 = "7a708aac3443762e58e84368040a6a23b2c63545",
+ url = "mvn:com.android.support:coordinatorlayout:aar:28.0.0",
+)
+
+fb_native.remote_file(
+ name = "cursoradapter-aar",
+ sha1 = "d803f573799e6cd2db8839e2a70fe6ad67e86b79",
+ url = "mvn:com.android.support:cursoradapter:aar:28.0.0",
+)
+
+fb_native.remote_file(
+ name = "customview-aar",
+ sha1 = "423fe0f417f2f8d9c718c2cf73f9253da43f1f11",
+ url = "mvn:com.android.support:customview:aar:28.0.0",
+)
+
+fb_native.remote_file(
+ name = "documentfile-aar",
+ sha1 = "1187e4a23ff6250b096249c734bdabf5403c6ba9",
+ url = "mvn:com.android.support:documentfile:aar:28.0.0",
)
-remote_file(
- name = "lib-support-v4-support-core-ui-aar",
- sha1 = "f9acdb8a4c3a9fe883fd7fa5efd3f0426bb9dcda",
- url = "mvn:com.android.support:support-core-ui:aar:27.1.1",
+fb_native.remote_file(
+ name = "drawerlayout-aar",
+ sha1 = "4de65d42b8e1b7f0ba40b5f35e5d4bafcd70019f",
+ url = "mvn:com.android.support:drawerlayout:aar:28.0.0",
)
-remote_file(
+fb_native.remote_file(
+ name = "interpolator-aar",
+ sha1 = "5d501569c8f7b667c47333a0b873aa529e0a0b9c",
+ url = "mvn:com.android.support:interpolator:aar:28.0.0",
+)
+
+fb_native.remote_file(
+ name = "support-annotations.jar",
+ sha1 = "ed73f5337a002d1fd24339d5fb08c2c9d9ca60d8",
+ url = "mvn:com.android.support:support-annotations:jar:28.0.0",
+)
+
+fb_native.remote_file(
+ name = "support-compat-aar",
+ sha1 = "d252b640ed832cf8addc35ef0a9f9186dc7738a5",
+ url = "mvn:com.android.support:support-compat:aar:28.0.0",
+)
+
+fb_native.remote_file(
+ name = "support-core-utils-aar",
+ sha1 = "29b1bb783f1a86eba7f1618bad58842bde72892a",
+ url = "mvn:com.android.support:support-core-utils:aar:28.0.0",
+)
+
+fb_native.remote_file(
+ name = "support-core-ui-aar",
+ sha1 = "96035b1030d7c3a81903966c2fa52117d36aa5b7",
+ url = "mvn:com.android.support:support-core-ui:aar:28.0.0",
+)
+
+fb_native.remote_file(
name = "lib-support-v4-support-media-compat-aar",
- sha1 = "10e309e2cc22ff4cab30bd5f573e4bb30be707ad",
- url = "mvn:com.android.support:support-media-compat:aar:27.1.1",
+ sha1 = "b7ab2145c7f70e303cfe2e44667d61441b5b558c",
+ url = "mvn:com.android.support:support-media-compat:aar:28.0.0",
+)
+
+fb_native.remote_file(
+ name = "support-fragment-aar",
+ sha1 = "f21c8a8700b30dc57cb6277ae3c4c168a94a4e81",
+ url = "mvn:com.android.support:support-fragment:aar:28.0.0",
+)
+
+fb_native.remote_file(
+ name = "livedata-core-aar",
+ sha1 = "30ede25cb577323f039c2e3d72b3b56526a2b2e6",
+ url = "mvn:android.arch.lifecycle:livedata-core:aar:1.1.1",
+)
+
+fb_native.remote_file(
+ name = "livedata-aar",
+ sha1 = "82e0b1bf2dc8ce23898cf433cc150df7b3dba952",
+ url = "mvn:android.arch.lifecycle:livedata:aar:1.1.1",
+)
+
+fb_native.remote_file(
+ name = "loader-aar",
+ sha1 = "49a297a4635e01ed55f31b5d4a718ba3416fde3d",
+ url = "mvn:com.android.support:loader:aar:28.0.0",
+)
+
+fb_native.remote_file(
+ name = "localbroadcastmanager-aar",
+ sha1 = "5c498cb7e2fa5910d6c50e28531c55b77d6bf0f6",
+ url = "mvn:com.android.support:localbroadcastmanager:aar:28.0.0",
+)
+
+fb_native.remote_file(
+ name = "print-aar",
+ sha1 = "d2c60bfbbdc2eadd4ff7c8f65743fab830339743",
+ url = "mvn:com.android.support:print:aar:28.0.0",
+)
+
+fb_native.remote_file(
+ name = "slidingpanelayout-aar",
+ sha1 = "20468e3ec8f36dc84846ddd99ff30516f4ffd05a",
+ url = "mvn:com.android.support:slidingpanelayout:aar:28.0.0",
+)
+
+fb_native.remote_file(
+ name = "swiperefreshlayout-aar",
+ sha1 = "bfa669303f0ac8a83d9c878fafadc2936625f781",
+ url = "mvn:com.android.support:swiperefreshlayout:aar:28.0.0",
+)
+
+fb_native.remote_file(
+ name = "versionedparcelable-aar",
+ sha1 = "90432a1e322e0e0bad2116dff0e64c708514808f",
+ url = "mvn:com.android.support:versionedparcelable:aar:28.0.0",
+)
+
+fb_native.remote_file(
+ name = "support-vector-drawable-aar",
+ sha1 = "80387886ef55af284d8253e52d321f93b3f923dd",
+ url = "mvn:com.android.support:support-vector-drawable:aar:28.0.0",
+)
+
+fb_native.remote_file(
+ name = "viewpager-aar",
+ sha1 = "f513ecf69dfea8b60987bd3e869970300ba7c0eb",
+ url = "mvn:com.android.support:viewpager:aar:28.0.0",
)
-remote_file(
- name = "lib-support-v4-support-fragment-aar",
- sha1 = "eb8053ebf038b7561c29e5e8964664fac05f375e",
- url = "mvn:com.android.support:support-fragment:aar:27.1.1",
+fb_native.remote_file(
+ name = "animated-vector-drawable-aar",
+ sha1 = "e2d41c2a032145313f42ab38a2d9757c5d1ebc19",
+ url = "mvn:com.android.support:animated-vector-drawable:aar:28.0.0",
)

ReactAndroid/src/main/third-party/android/support/v7/appcompat-orig/BUCK

@@ -1,4 +1,5 @@
-load("//tools/build_defs/oss:rn_defs.bzl", "rn_android_library", "rn_android_resource", "react_native_dep", "rn_prebuilt_jar")
+load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
+load("//tools/build_defs/oss:rn_defs.bzl", "react_native_dep", "rn_android_library", "rn_android_resource", "rn_genrule", "rn_prebuilt_jar")
# This is a bit messy and hopefully a temporary thing
# The problem is that Gradle extracts appcompat resources into app namespace, com.facebook.react
@@ -18,8 +19,7 @@
":res-for-appcompat",
],
exported_deps = [
- ":classes-for-react-native",
- react_native_dep("third-party/android/support-annotations:android-support-annotations"),
+ ":classes-for-react-native"
],
)
@@ -37,26 +37,26 @@
visibility = ["//ReactAndroid/..."],
)
-genrule(
+rn_genrule(
name = "classes-unpacker-cmd",
out = "classes.jar",
cmd = "$(exe :aar-unpacker) $(location :appcompat-binary-aar) classes.jar $OUT",
)
-genrule(
+rn_genrule(
name = "res-unpacker-cmd",
out = "res",
cmd = "$(exe :aar-unpacker) $(location :appcompat-binary-aar) res/ $OUT",
visibility = ["//ReactAndroid/..."],
)
-python_binary(
+fb_native.python_binary(
name = "aar-unpacker",
main = "aar-unpacker.py",
)
-remote_file(
+fb_native.remote_file(
name = "appcompat-binary-aar",
- sha1 = "22b1ef4ff9ef1a3513c18eb132d597eac6ef1a86",
- url = "mvn:com.android.support:appcompat-v7:aar:27.1.1",
+ sha1 = "132586ec59604a86703796851a063a0ac61f697b",
+ url = "mvn:com.android.support:appcompat-v7:aar:28.0.0",
)

ReactAndroid/src/main/third-party/android/support-annotations/BUCK

@@ -1,11 +1,14 @@
-prebuilt_jar(
+load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
+load("//tools/build_defs/oss:rn_defs.bzl", "rn_prebuilt_jar")
+
+rn_prebuilt_jar(
name = "android-support-annotations",
binary_jar = ":support-annotations-binary.jar",
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "support-annotations-binary.jar",
- sha1 = "39ded76b5e1ce1c5b2688e1d25cdc20ecee32007",
- url = "mvn:com.android.support:support-annotations:jar:27.1.1",
+ sha1 = "ed73f5337a002d1fd24339d5fb08c2c9d9ca60d8",
+ url = "mvn:com.android.support:support-annotations:jar:28.0.0",
)

ReactAndroid/src/main/third-party/java/asm/BUCK

@@ -1,3 +1,4 @@
+load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
load("//tools/build_defs/oss:rn_defs.bzl", "rn_android_library", "rn_prebuilt_jar")
rn_android_library(
@@ -18,7 +19,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "download-asm.jar",
sha1 = "2fd56467a018aafe6ec6a73ccba520be4a7e1565",
url = "mvn:org.ow2.asm:asm:jar:5.0.1",
@@ -30,7 +31,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "download-asm-commons.jar",
sha1 = "7b7147a390a93a14d2edfdcf3f7b0e87a0939c3e",
url = "mvn:org.ow2.asm:asm-commons:jar:5.0.1",
@@ -42,7 +43,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "download-asm-tree.jar",
sha1 = "1b1e6e9d869acd704056d0a4223071a511c619e6",
url = "mvn:org.ow2.asm:asm-tree:jar:5.0.1",
@@ -54,7 +55,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "download-asm-util.jar",
sha1 = "7c8caddfbd0b2d7b844f8fcc75175b9cb9cf4724",
url = "mvn:org.ow2.asm:asm-util:jar:5.0.1",
@@ -66,7 +67,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "download-asm-analysis.jar",
sha1 = "e286fbee48efacb4e7c175f7948d9d8b2ab52352",
url = "mvn:org.ow2.asm:asm-analysis:jar:5.0.1",

ReactAndroid/src/main/third-party/java/buck-android-support/BUCK

@@ -1,7 +1,8 @@
+load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
load("//tools/build_defs/oss:rn_defs.bzl", "react_native_integration_tests_target")
# this lib was compiled by buck version : 6cbf2709778ea352a169d1c84e3ef2894dfa39ec
-prebuilt_jar(
+fb_native.prebuilt_jar(
name = "buck-android-support",
binary_jar = "buck-android-support.jar",
visibility = [

ReactAndroid/src/main/third-party/java/fest/BUCK

@@ -1,3 +1,4 @@
+load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
load("//tools/build_defs/oss:rn_defs.bzl", "rn_android_library", "rn_prebuilt_jar")
rn_android_library(
@@ -15,7 +16,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "fest-binary.jar",
sha1 = "cb7c91cf614901928ae405f19d9bcdedf82781db",
url = "mvn:org.easytesting:fest-assert-core:jar:2.0M10",
@@ -27,7 +28,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "fest-util-binary.jar",
sha1 = "c4a8d7305b23b8d043be12c979813b096df11f44",
url = "mvn:org.easytesting:fest-util:jar:1.2.5",

ReactAndroid/src/main/third-party/java/infer-annotations/BUCK

@@ -1,10 +1,13 @@
-prebuilt_jar(
+load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
+load("//tools/build_defs/oss:rn_defs.bzl", "rn_prebuilt_jar")
+
+rn_prebuilt_jar(
name = "infer-annotations",
binary_jar = ":infer-annotations.jar",
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "infer-annotations.jar",
sha1 = "f514ff4ca022a579d9cf7524846988b646ae4491",
url = "mvn:com.facebook.infer.annotation:infer-annotation:jar:0.11.2",

ReactAndroid/src/main/third-party/java/javapoet/BUCK

@@ -1,10 +1,13 @@
-prebuilt_jar(
+load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
+load("//tools/build_defs/oss:rn_defs.bzl", "rn_prebuilt_jar")
+
+rn_prebuilt_jar(
name = "javapoet",
binary_jar = ":jsr305-binary.jar",
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "jsr305-binary.jar",
sha1 = "ad3ba65c1788f4d814a4da056323e2b84412fb3c",
url = "mvn:com.squareup:javapoet:jar:1.2.0",

ReactAndroid/src/main/third-party/java/jsr-305/BUCK

@@ -1,10 +1,12 @@
-prebuilt_jar(
+load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
+
+fb_native.prebuilt_jar(
name = "jsr-305",
binary_jar = ":jsr305-binary.jar",
visibility = ["PUBLIC"],
)
-remote_file(
+fb_native.remote_file(
name = "jsr305-binary.jar",
sha1 = "25ea2e8b0c338a877313bd4672d3fe056ea78f0d",
url = "mvn:com.google.code.findbugs:jsr305:jar:3.0.2",

ReactAndroid/src/main/third-party/java/jsr-330/BUCK

@@ -1,10 +1,12 @@
-prebuilt_jar(
+load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
+
+fb_native.prebuilt_jar(
name = "jsr-330",
binary_jar = ":jsr330-binary.jar",
visibility = ["PUBLIC"],
)
-remote_file(
+fb_native.remote_file(
name = "jsr330-binary.jar",
sha1 = "6975da39a7040257bd51d21a231b76c915872d38",
url = "mvn:javax.inject:javax.inject:jar:1",

ReactAndroid/src/main/third-party/java/junit/BUCK

@@ -1,3 +1,4 @@
+load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
load("//tools/build_defs/oss:rn_defs.bzl", "rn_android_library", "rn_prebuilt_jar")
rn_android_library(
@@ -15,7 +16,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "download-junit.jar",
sha1 = "2973d150c0dc1fefe998f834810d68f278ea58ec",
url = "mvn:junit:junit:jar:4.12",
@@ -27,7 +28,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "download-hamcrest.jar",
sha1 = "63a21ebc981131004ad02e0434e799fd7f3a8d5a",
url = "mvn:org.hamcrest:hamcrest-all:jar:1.3",

ReactAndroid/src/main/third-party/java/mockito/BUCK

@@ -1,3 +1,4 @@
+load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
load("//tools/build_defs/oss:rn_defs.bzl", "rn_android_library", "rn_prebuilt_jar")
rn_android_library(
@@ -15,7 +16,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "mockito-binary.jar",
sha1 = "c54c55cae0f4742ad6bf8a1987ada35363f2c4e2",
url = "mvn:org.mockito:mockito-core:jar:2.19.1",
@@ -27,7 +28,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "objenesis-binary.jar",
sha1 = "87c0ea803b69252868d09308b4618f766f135a96",
url = "mvn:org.objenesis:objenesis:jar:2.1",

ReactAndroid/src/main/third-party/java/okhttp/BUCK

@@ -1,23 +1,26 @@
-prebuilt_jar(
+load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
+load("//tools/build_defs/oss:rn_defs.bzl", "rn_prebuilt_jar")
+
+rn_prebuilt_jar(
name = "okhttp3",
binary_jar = ":okhttp3-binary.jar",
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "okhttp3-binary.jar",
- sha1 = "75966e05a49046ca2ae734e5626f28837a8d1e82",
- url = "mvn:com.squareup.okhttp3:okhttp:jar:3.11.0",
+ sha1 = "dc6d02e4e68514eff5631963e28ca7742ac69efe",
+ url = "mvn:com.squareup.okhttp3:okhttp:jar:3.12.1",
)
-prebuilt_jar(
+rn_prebuilt_jar(
name = "okhttp3-urlconnection",
binary_jar = ":okhttp3-urlconnection-binary.jar",
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "okhttp3-urlconnection-binary.jar",
- sha1 = "54ec442e9c0fac51265110cf0cb44dfe5ad1ea05",
- url = "mvn:com.squareup.okhttp3:okhttp-urlconnection:jar:3.11.0",
+ sha1 = "f689d3657c3f1fdbde4877bcddc668491a4ad46f",
+ url = "mvn:com.squareup.okhttp3:okhttp-urlconnection:jar:3.12.1",
)

ReactAndroid/src/main/third-party/java/okio/BUCK

@@ -1,11 +1,14 @@
-prebuilt_jar(
+load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
+load("//tools/build_defs/oss:rn_defs.bzl", "rn_prebuilt_jar")
+
+rn_prebuilt_jar(
name = "okio",
binary_jar = ":okio-binary.jar",
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "okio-binary.jar",
- sha1 = "102d7be47241d781ef95f1581d414b0943053130",
- url = "mvn:com.squareup.okio:okio:jar:1.14.0",
+ sha1 = "bc28b5a964c8f5721eb58ee3f3c47a9bcbf4f4d8",
+ url = "mvn:com.squareup.okio:okio:jar:1.15.0",
)

ReactAndroid/src/main/third-party/java/robolectric3/robolectric/BUCK

@@ -1,3 +1,4 @@
+load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
load("//tools/build_defs/oss:rn_defs.bzl", "react_native_dep", "rn_android_library", "rn_prebuilt_jar")
rn_android_library(
@@ -26,7 +27,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "robolectric-binary.jar",
sha1 = "f888cea3bc1a24110e315eb9827ab593610ea62f",
url = "mvn:org.robolectric:robolectric:jar:3.0",
@@ -38,7 +39,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "robolectric-resources-binary.jar",
sha1 = "1ab609054aab67cd13a434567467f4b4774f2465",
url = "mvn:org.robolectric:robolectric-resources:jar:3.0",
@@ -50,7 +51,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "robolectric-annotations-binary.jar",
sha1 = "2a6cfc072d7680694c1ff893c5dc8fec33163110",
url = "mvn:org.robolectric:robolectric-annotations:jar:3.0",
@@ -62,7 +63,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "robolectric-utils-binary.jar",
sha1 = "4bcecd8115fe7296088bb1636e6cbd7ae8927392",
url = "mvn:org.robolectric:robolectric-utils:jar:3.0",
@@ -74,7 +75,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "bouncycastle-binary.jar",
sha1 = "ce091790943599535cbb4de8ede84535b0c1260c",
url = "mvn:org.bouncycastle:bcprov-jdk16:jar:1.46",
@@ -86,7 +87,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "vtd-xml-binary.jar",
sha1 = "ee5bcf62c1acf76434ee9f1c67a840bafef72a6d",
url = "mvn:com.ximpleware:vtd-xml:jar:2.11",
@@ -98,7 +99,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "icu-binary.jar",
sha1 = "786d9055d4ca8c1aab4a7d4ac8283f973fd7e41f",
url = "mvn:com.ibm.icu:icu4j:jar:53.1",
@@ -112,13 +113,13 @@
# This new rule will make the .jar file appear in the "right" location,
# though that may change in the future
-export_file(
+fb_native.export_file(
name = "robolectric-android-all-binary.jar",
src = ":robolectric-android-all-binary-remote.jar",
out = "../android-all-4.1.2_r1-robolectric-0.jar", # name defines filename used by robolectric in runtime
)
-remote_file(
+fb_native.remote_file(
name = "robolectric-android-all-binary-remote.jar",
sha1 = "aecc8ce5119a25fcea1cdf8285469c9d1261a352",
url = "mvn:org.robolectric:android-all:jar:4.1.2_r1-robolectric-0",
@@ -130,13 +131,13 @@
visibility = ["//ReactAndroid/..."],
)
-export_file(
+fb_native.export_file(
name = "json.jar",
src = ":json-remote.jar",
out = "../json-20080701.jar", # name defines filename used by robolectric in runtime
)
-remote_file(
+fb_native.remote_file(
name = "json-remote.jar",
sha1 = "d652f102185530c93b66158b1859f35d45687258",
url = "mvn:org.json:json:jar:20080701",
@@ -148,13 +149,13 @@
visibility = ["//ReactAndroid/..."],
)
-export_file(
+fb_native.export_file(
name = "tagsoup.jar",
src = ":tagsoup-remote.jar",
out = "../tagsoup-1.2.jar", # name defines filename used by robolectric in runtime
)
-remote_file(
+fb_native.remote_file(
name = "tagsoup-remote.jar",
sha1 = "639fd364750d7363c85797dc944b4a80f78fa684",
url = "mvn:org.ccil.cowan.tagsoup:tagsoup:jar:1.2",
@@ -166,13 +167,13 @@
visibility = ["//ReactAndroid/..."],
)
-export_file(
+fb_native.export_file(
name = "robolectric-shadows-binary.jar",
src = ":robolectric-shadows-binary-remote.jar",
out = "../shadows-core-3.0-16.jar", # name defines filename used by robolectric in runtime
)
-remote_file(
+fb_native.remote_file(
name = "robolectric-shadows-binary-remote.jar",
sha1 = "39d7a856bf91640b1a6d044333336a2b3f3c198f",
url = "https://repo1.maven.org/maven2/org/robolectric/shadows-core/3.0/shadows-core-3.0-16.jar",

ReactAndroid/src/main/third-party/java/sqlite/BUCK

@@ -1,3 +1,4 @@
+load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
load("//tools/build_defs/oss:rn_defs.bzl", "rn_android_library", "rn_prebuilt_jar")
rn_android_library(
@@ -14,7 +15,7 @@
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "download-sqlite4java.jar",
sha1 = "745a7e2f35fdbe6336922e0d492c979dbbfa74fb",
url = "mvn:com.almworks.sqlite4java:sqlite4java:jar:0.282",

ReactAndroid/src/main/third-party/java/testing-support-lib/BUCK

@@ -1,22 +1,25 @@
-android_prebuilt_aar(
+load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
+load("//tools/build_defs/oss:rn_defs.bzl", "rn_android_prebuilt_aar")
+
+rn_android_prebuilt_aar(
name = "runner",
aar = ":testing-support-lib-runner-download",
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "testing-support-lib-runner-download",
sha1 = "a31e7e8db98ca19fb3fab23f120d19a6f4e3e8a9",
url = "mvn:com.android.support.test:runner:aar:0.3",
)
-android_prebuilt_aar(
+rn_android_prebuilt_aar(
name = "exposed-instrumentation-api",
aar = ":testing-support-instrumentation",
visibility = ["//ReactAndroid/..."],
)
-remote_file(
+fb_native.remote_file(
name = "testing-support-instrumentation",
sha1 = "a7161eafdfbd02a39461f076c9dce0c8e5e7a149",
url = "mvn:com.android.support.test:exposed-instrumentation-api-publish:aar:0.3",

ReactAndroid/src/test/java/com/facebook/common/logging/FakeLoggingDelegate.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/animated/NativeAnimatedInterpolationTest.java

@@ -1,3 +1,10 @@
+/**
+ * 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.animated;
import org.junit.Test;

ReactAndroid/src/test/java/com/facebook/react/animated/NativeAnimatedNodeTraversalTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/bridge/BaseJavaModuleTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -41,7 +41,7 @@
@Before
public void setup() {
ModuleHolder moduleHolder = new ModuleHolder(new MethodsModule());
- mWrapper = new JavaModuleWrapper(null, MethodsModule.class.getName(), moduleHolder);
+ mWrapper = new JavaModuleWrapper(null, moduleHolder);
mMethods = mWrapper.getMethodDescriptors();
PowerMockito.mockStatic(SoLoader.class);
mArguments = PowerMockito.mock(ReadableNativeArray.class);

ReactAndroid/src/test/java/com/facebook/react/bridge/FallbackJSBundleLoaderTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/bridge/InstanceHandleHelper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/bridge/JavaOnlyArrayTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/bridge/JsonWriterTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/bridge/ModuleSpecTest.java

@@ -1,104 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-package com.facebook.react.bridge;
-
-import com.facebook.react.common.build.ReactBuildConfig;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor;
-import org.powermock.modules.junit4.rule.PowerMockRule;
-import org.powermock.reflect.Whitebox;
-import org.robolectric.RobolectricTestRunner;
-
-import static org.fest.assertions.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-
-@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
-@SuppressStaticInitializationFor("com.facebook.react.common.build.ReactBuildConfig")
-@PrepareForTest({ReactBuildConfig.class})
-@RunWith(RobolectricTestRunner.class)
-public class ModuleSpecTest {
- @Rule
- public PowerMockRule rule = new PowerMockRule();
-
- @Test(expected = IllegalArgumentException.class)
- public void testSimpleFailFast() {
- Whitebox.setInternalState(ReactBuildConfig.class, "DEBUG", true);
- ModuleSpec.simple(ComplexModule.class, mock(ReactApplicationContext.class));
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testSimpleFailFastDefault() {
- Whitebox.setInternalState(ReactBuildConfig.class, "DEBUG", true);
- ModuleSpec.simple(ComplexModule.class);
- }
-
- @Test
- public void testSimpleNoFailFastRelease() {
- Whitebox.setInternalState(ReactBuildConfig.class, "DEBUG", false);
- ModuleSpec.simple(ComplexModule.class, mock(ReactApplicationContext.class));
- }
-
- @Test(expected = RuntimeException.class)
- public void testSimpleFailLateRelease() {
- Whitebox.setInternalState(ReactBuildConfig.class, "DEBUG", false);
- ModuleSpec spec = ModuleSpec.simple(ComplexModule.class, mock(ReactApplicationContext.class));
- spec.getProvider().get();
- }
-
- @Test
- public void testSimpleDefaultConstructor() {
- Whitebox.setInternalState(ReactBuildConfig.class, "DEBUG", true);
- ModuleSpec spec = ModuleSpec.simple(SimpleModule.class);
- assertThat(spec.getProvider().get()).isInstanceOf(SimpleModule.class);
- }
-
- @Test
- public void testSimpleContextConstructor() {
- Whitebox.setInternalState(ReactBuildConfig.class, "DEBUG", true);
- ReactApplicationContext context = mock(ReactApplicationContext.class);
- ModuleSpec spec = ModuleSpec.simple(SimpleContextModule.class, context);
-
- NativeModule module = spec.getProvider().get();
- assertThat(module).isInstanceOf(SimpleContextModule.class);
- SimpleContextModule contextModule = (SimpleContextModule) module;
- assertThat(contextModule.getReactApplicationContext()).isSameAs(context);
- }
-
- public static class ComplexModule extends BaseJavaModule {
-
- public ComplexModule(int a, int b) {
- }
-
- public String getName() {
- return "ComplexModule";
- }
- }
-
- public static class SimpleModule extends BaseJavaModule {
-
- public String getName() {
- return "SimpleModule";
- }
- }
-
- public static class SimpleContextModule extends ReactContextBaseJavaModule {
-
- public SimpleContextModule(ReactApplicationContext context) {
- super(context);
- }
-
- public String getName() {
- return "SimpleContextModule";
- }
- }
-}

ReactAndroid/src/test/java/com/facebook/react/bridge/ReactTestHelper.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/CompositeReactPackageTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/devsupport/JSDebuggerWebSocketClientTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/devsupport/MultipartStreamReaderTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/devsupport/StackTraceHelperTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/fabric/BUCK

@@ -1,40 +0,0 @@
-load("//tools/build_defs/oss:rn_defs.bzl", "IS_OSS_BUILD", "YOGA_TARGET", "react_native_dep", "react_native_target", "react_native_tests_target", "rn_robolectric_test")
-
-rn_robolectric_test(
- name = "fabric",
- srcs = glob(["**/*.java"]),
- contacts = ["oncall+fbandroid_sheriff@xmail.facebook.com"],
- resources = glob([
- "**/*.txt",
- "**/*.json",
- ]),
- visibility = [
- "PUBLIC",
- ],
- deps = [
- "xplat//yoga/java:java",
- react_native_dep("third-party/java/assertj:assertj-core"),
- react_native_dep("third-party/java/fest:fest"),
- react_native_dep("third-party/java/fest:fest_android"),
- react_native_dep("third-party/java/guava:guava"),
- react_native_dep("third-party/java/jackson:jackson"),
- react_native_dep("third-party/java/jsr-305:jsr-305"),
- react_native_dep("third-party/java/jsr-330:jsr-330"),
- react_native_dep("third-party/java/junit:junit"),
- react_native_dep("third-party/java/mockito:mockito"),
- react_native_dep("third-party/java/robolectric3/robolectric:robolectric"),
- react_native_dep("libraries/fbcore/src/test/java/com/facebook/powermock:powermock"),
- react_native_dep("libraries/soloader/java/com/facebook/soloader:soloader"),
- react_native_dep("third-party/android/support/v4:lib-support-v4"),
- react_native_target("java/com/facebook/react:react"),
- react_native_target("java/com/facebook/react/bridge:bridge"),
- react_native_target("java/com/facebook/react/common:common"),
- react_native_target("java/com/facebook/react/fabric:fabric"),
- react_native_target("java/com/facebook/react/modules/core:core"),
- react_native_target("java/com/facebook/react/uimanager:uimanager"),
- react_native_target("java/com/facebook/react/views/text:text"),
- react_native_target("java/com/facebook/react/views/view:view"),
- react_native_target("java/com/facebook/react/views/progressbar:progressbar"),
- react_native_tests_target("java/com/facebook/react/bridge:testhelpers"),
- ],
-) if not IS_OSS_BUILD else None

ReactAndroid/src/test/java/com/facebook/react/fabric/FabricReconcilerTest.java

@@ -1,205 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-package com.facebook.react.fabric;
-
-import static org.fest.assertions.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-
-import com.facebook.react.bridge.CatalystInstance;
-import com.facebook.react.bridge.JavaScriptContextHolder;
-import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.ReactTestHelper;
-import com.facebook.react.uimanager.events.EventDispatcher;
-import com.facebook.react.uimanager.NativeViewHierarchyManager;
-import com.facebook.react.uimanager.ReactShadowNode;
-import com.facebook.react.uimanager.ReactShadowNodeImpl;
-import com.facebook.react.uimanager.ThemedReactContext;
-import com.facebook.react.uimanager.UIViewOperationQueue;
-import com.facebook.react.uimanager.ViewAtIndex;
-import com.facebook.react.uimanager.ViewManager;
-import com.facebook.react.uimanager.ViewManagerRegistry;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-/** Tests {@link FabricReconciler} */
-@RunWith(RobolectricTestRunner.class)
-public class FabricReconcilerTest {
-
- private FabricReconciler mFabricReconciler;
- private FabricUIManager mFabricUIManager;
- private MockUIViewOperationQueue mMockUIViewOperationQueue;
-
- @Before
- public void setUp() {
- CatalystInstance catalystInstance = ReactTestHelper.createMockCatalystInstance();
- ReactApplicationContext reactContext =
- new ReactApplicationContext(RuntimeEnvironment.application);
- reactContext.initializeWithInstance(catalystInstance);
- List<ViewManager> viewManagers = new ArrayList<>();
- ViewManagerRegistry viewManagerRegistry = new ViewManagerRegistry(viewManagers);
- JavaScriptContextHolder jsContext = mock(JavaScriptContextHolder.class);
- EventDispatcher eventDispatcher = mock(EventDispatcher.class);
- mFabricUIManager = new FabricUIManager(reactContext, viewManagerRegistry, jsContext, eventDispatcher);
- mMockUIViewOperationQueue = new MockUIViewOperationQueue(reactContext);
- mFabricReconciler = new FabricReconciler(mMockUIViewOperationQueue);
- }
-
- @Test
- public void testSimpleHierarchy() {
- ReactShadowNode parent = createNode(0);
- ReactShadowNode child1 = createNode(1);
- ReactShadowNode child2 = createNode(2);
- addChildren(parent, child1, child2);
-
- ReactShadowNode parentCloned = createNode(0);
- ReactShadowNode child3 = createNode(3);
- addChildren(parentCloned, child3, child2);
-
- mFabricReconciler.manageChildren(parent, parentCloned);
-
- List<ManageChildrenOperation> expectedOperations = new ArrayList<>();
- expectedOperations.add(
- new ManageChildrenOperation(
- 0,
- new int[] {0, 1},
- new ViewAtIndex[] {new ViewAtIndex(3, 0), new ViewAtIndex(2, 1)},
- new int[] {1}));
- assertThat(mMockUIViewOperationQueue.getOperations()).isEqualTo(expectedOperations);
- }
-
- @Test
- public void testVirtualNodes() {
- ReactShadowNode parent = createNode(0);
- ReactShadowNode child1 = createVirtualNode(1);
- ReactShadowNode child2 = createVirtualNode(2);
- ReactShadowNode child3 = createVirtualNode(3);
- addChildren(parent, child1, child2, child3);
-
- ReactShadowNode parentCloned = createNode(0);
- ReactShadowNode child4 = createVirtualNode(4);
- addChildren(parentCloned, child1, child4, child3);
-
- mFabricReconciler.manageChildren(parent, parentCloned);
-
- List<ManageChildrenOperation> expectedOperations = new ArrayList<>();
- assertThat(mMockUIViewOperationQueue.getOperations()).isEqualTo(expectedOperations);
- }
-
- private void addChildren(ReactShadowNode parent, ReactShadowNode... children) {
- for (ReactShadowNode child : children) {
- mFabricUIManager.appendChild(parent, child);
- }
- }
-
- private static ReactShadowNode createNode(int tag) {
- return createNode(tag, false);
- }
-
- private static ReactShadowNode createVirtualNode(int tag) {
- return createNode(tag, true);
- }
-
- private static ReactShadowNode createNode(int tag, boolean virtual) {
- ReactShadowNode node;
- if (virtual) {
- node = new VirtualReactShadowNode();
- } else {
- node = new ReactShadowNodeImpl();
- }
- node.setReactTag(tag);
- node.setViewClassName("View");
- node.setThemedContext(mock(ThemedReactContext.class));
- return node;
- }
-
- private static class VirtualReactShadowNode extends ReactShadowNodeImpl {
-
- VirtualReactShadowNode() {}
-
- VirtualReactShadowNode(VirtualReactShadowNode original) {
- super(original);
- }
-
- @Override
- public boolean isVirtual() {
- return true;
- }
-
- @Override
- public ReactShadowNodeImpl copy() {
- return new VirtualReactShadowNode(this);
- }
- }
-
- private static class ManageChildrenOperation {
- private int mTag;
- private int[] mIndicesToRemove;
- private ViewAtIndex[] mViewsToAdd;
- private int[] mTagsToRemove;
-
- private ManageChildrenOperation(
- int tag, int[] indicesToRemove, ViewAtIndex[] viewsToAdd, int[] tagsToRemove) {
- mTag = tag;
- mIndicesToRemove = indicesToRemove;
- mViewsToAdd = viewsToAdd;
- mTagsToRemove = tagsToRemove;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null || obj.getClass() != getClass()) {
- return false;
- }
- ManageChildrenOperation op = (ManageChildrenOperation) obj;
- return mTag == op.mTag
- && Arrays.equals(mIndicesToRemove, op.mIndicesToRemove)
- && Arrays.equals(mViewsToAdd, op.mViewsToAdd)
- && Arrays.equals(mTagsToRemove, op.mTagsToRemove);
- }
-
- @Override
- public int hashCode() {
- return Arrays.deepHashCode(new Object[] {mTag, mIndicesToRemove, mViewsToAdd, mTagsToRemove});
- }
-
- @Override
- public String toString() {
- return "ManageChildrenOperation \n\tindicesToRemove: "
- + Arrays.toString(mIndicesToRemove)
- + "\n\tviewsToAdd: "
- + Arrays.toString(mViewsToAdd)
- + "\n\ttagsToRemove: "
- + Arrays.toString(mTagsToRemove);
- }
- }
-
- private static class MockUIViewOperationQueue extends UIViewOperationQueue {
-
- private List<ManageChildrenOperation> mOperations;
-
- private MockUIViewOperationQueue(ReactApplicationContext context) {
- super(context, mock(NativeViewHierarchyManager.class), 0);
- mOperations = new ArrayList<>();
- }
-
- @Override
- public void enqueueManageChildren(
- int reactTag, int[] indicesToRemove, ViewAtIndex[] viewsToAdd, int[] tagsToDelete) {
- mOperations.add(
- new ManageChildrenOperation(reactTag, indicesToRemove, viewsToAdd, tagsToDelete));
- }
-
- public List<ManageChildrenOperation> getOperations() {
- return Collections.unmodifiableList(mOperations);
- }
- }
-}

ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java

@@ -1,336 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-package com.facebook.react.fabric;
-
-import static org.fest.assertions.api.Assertions.assertThat;
-import static com.facebook.react.bridge.InstanceHandleHelper.randomInstanceHandle;
-import static org.mockito.Mockito.mock;
-
-import com.facebook.react.ReactRootView;
-import com.facebook.react.bridge.JavaScriptContextHolder;
-import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.ReactTestHelper;
-import com.facebook.react.bridge.ReadableNativeMap;
-import com.facebook.react.uimanager.events.EventDispatcher;
-import com.facebook.react.uimanager.ReactShadowNode;
-import com.facebook.react.uimanager.ReactShadowNodeImpl;
-import com.facebook.react.uimanager.Spacing;
-import com.facebook.react.uimanager.ThemedReactContext;
-import com.facebook.react.uimanager.ViewManager;
-import com.facebook.react.uimanager.ViewManagerRegistry;
-import com.facebook.react.views.progressbar.ProgressBarShadowNode;
-import com.facebook.react.views.text.ReactRawTextManager;
-import com.facebook.react.views.text.ReactRawTextShadowNode;
-import com.facebook.react.views.text.ReactTextViewManager;
-import com.facebook.react.views.view.ReactViewManager;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import org.fest.assertions.data.Offset;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-
-/** Tests {@link FabricUIManager} */
-@RunWith(RobolectricTestRunner.class)
-public class FabricUIManagerTest {
-
- private FabricUIManager mFabricUIManager;
- private ThemedReactContext mThemedReactContext;
- private int mNextReactTag;
-
- @Before
- public void setUp() throws Exception {
- mNextReactTag = 2;
- ReactApplicationContext reactContext = new ReactApplicationContext(RuntimeEnvironment.application);
- reactContext.initializeWithInstance(ReactTestHelper.createMockCatalystInstance());
- mThemedReactContext = new ThemedReactContext(reactContext, reactContext);
-
- List<ViewManager> viewManagers =
- Arrays.<ViewManager>asList(
- new ReactViewManager(), new ReactTextViewManager(), new ReactRawTextManager());
- ViewManagerRegistry viewManagerRegistry = new ViewManagerRegistry(viewManagers);
- JavaScriptContextHolder jsContext = mock(JavaScriptContextHolder.class);
- EventDispatcher eventDispatcher = mock(EventDispatcher.class);
- mFabricUIManager = new FabricUIManager(reactContext, viewManagerRegistry, jsContext, eventDispatcher);
- }
-
- @Test
- public void testCreateNode() {
- ReactRootView rootView =
- new ReactRootView(RuntimeEnvironment.application.getApplicationContext());
- int rootTag = mFabricUIManager.addRootView(rootView);
- int reactTag = mNextReactTag++;
- String viewClass = ReactViewManager.REACT_CLASS;
- ReactShadowNode node =
- mFabricUIManager.createNode(reactTag, viewClass, rootTag, null, randomInstanceHandle());
-
- assertThat(reactTag).isEqualTo(node.getReactTag());
- assertThat(viewClass).isEqualTo(node.getViewClass());
- assertThat(rootTag).isEqualTo(rootTag);
- }
-
- @Test
- public void testCreateMultpleRootViews() {
- createAndRenderRootView();
- createAndRenderRootView();
- }
-
- private int createAndRenderRootView() {
- ReactRootView rootView =
- new ReactRootView(RuntimeEnvironment.application.getApplicationContext());
- int rootTag = mFabricUIManager.addRootView(rootView);
- int reactTag = mNextReactTag++;
- String viewClass = ReactViewManager.REACT_CLASS;
- ReactShadowNode node =
- mFabricUIManager.createNode(reactTag, viewClass, rootTag, null, randomInstanceHandle());
-
- List<ReactShadowNode> childSet = mFabricUIManager.createChildSet(rootTag);
- mFabricUIManager.appendChildToSet(childSet, node);
- mFabricUIManager.completeRoot(rootTag, childSet);
-
- return rootTag;
- }
-
- @Test
- public void testCloneNode() {
- ReactShadowNode node = createViewNode();
- ReactShadowNode child = createViewNode();
- node.addChildAt(child, 0);
-
- ReactShadowNode clonedNode = mFabricUIManager.cloneNode(node);
-
- assertThat(clonedNode).isNotSameAs(node);
- assertThat(clonedNode.getOriginalReactShadowNode()).isSameAs(node);
- assertSameFields(clonedNode, node);
- assertSameChildren(clonedNode, node);
- assertThat(clonedNode.getChildAt(0)).isEqualTo(child);
- }
-
- @Test
- public void testDefaultSpacingCloning() {
- ReactShadowNode node = createViewNode();
- node.setDefaultPadding(Spacing.LEFT, 10);
-
- ReactShadowNode clonedNode = mFabricUIManager.cloneNode(node);
-
- node.setDefaultPadding(Spacing.LEFT, 20);
- assertThat(clonedNode.getStylePadding(Spacing.LEFT).value).isEqualTo(10f, Offset.offset(0.01f));
- assertThat(node.getStylePadding(Spacing.LEFT).value).isEqualTo(20f, Offset.offset(0.01f));
- }
-
- @Test
- public void testCloneVirtualNode() {
- ReactRawTextShadowNode node = new ReactRawTextShadowNode();
- node.setText("test");
- assertThat(node.isVirtual()).isTrue();
-
- ReactRawTextShadowNode clonedNode = (ReactRawTextShadowNode) node.mutableCopy(randomInstanceHandle());
-
- assertThat(clonedNode.getText()).isEqualTo("test");
- assertThat(clonedNode).isNotEqualTo(node);
- }
-
- @Test
- public void testLayoutProgressBarAfterClonning() {
- ProgressBarShadowNode node = new ProgressBarShadowNode();
- node.setThemedContext(mThemedReactContext);
- ProgressBarShadowNode clone = (ProgressBarShadowNode) node.mutableCopy(randomInstanceHandle());
- clone.calculateLayout();
- }
-
- @Test
- public void testCloneNodeWithNewChildren() {
- ReactShadowNode node = createViewNode();
- ReactShadowNode child = createViewNode();
- node.addChildAt(child, 0);
-
- ReactShadowNode clonedNode = mFabricUIManager.cloneNodeWithNewChildren(node);
-
- assertThat(clonedNode.getChildCount()).isZero();
- assertSameFields(clonedNode, node);
- }
-
- @Test
- public void testCloneNodeWithNewProps() {
- ReactShadowNode node = createViewNode();
- ReadableNativeMap props = null; // TODO(ayc): Figure out how to create a Native map from tests.
-
- ReactShadowNode clonedNode = mFabricUIManager.cloneNodeWithNewProps(node, props);
- }
-
- @Test
- public void testCloneNodeWithNewChildrenAndProps() {
- ReactShadowNode node = createViewNode();
- ReadableNativeMap props = null;
-
- ReactShadowNode clonedNode = mFabricUIManager.cloneNodeWithNewChildrenAndProps(node, props);
-
- assertThat(clonedNode.getChildCount()).isZero();
- }
-
- @Test
- public void testAppendChild() {
- ReactShadowNode node = createViewNode();
- ReactShadowNode child = createViewNode();
-
- mFabricUIManager.appendChild(node, child);
-
- assertThat(node.getChildCount()).isEqualTo(1);
- assertThat(node.getChildAt(0)).isEqualTo(child);
- }
-
- @Test
- public void testCreateChildSet() {
- List<ReactShadowNode> childSet = mFabricUIManager.createChildSet(0);
-
- assertThat(childSet).isEmpty();
- }
-
- @Test
- public void testAppendChildToSet() {
- ReactShadowNode node = createViewNode();
- List<ReactShadowNode> childSet = mFabricUIManager.createChildSet(0);
-
- mFabricUIManager.appendChildToSet(childSet, node);
-
- assertThat(childSet).hasSize(1);
- assertThat(childSet).contains(node);
- }
-
- @Test(expected = AssertionError.class)
- public void testCompleteRootBeforeAddRoot() {
- mFabricUIManager.completeRoot(0, new ArrayList<ReactShadowNode>());
- }
-
- @Test
- public void testCompleteRoot() {
- ReactRootView rootView =
- new ReactRootView(RuntimeEnvironment.application.getApplicationContext());
- int rootTag = mFabricUIManager.addRootView(rootView);
- List<ReactShadowNode> children = mFabricUIManager.createChildSet(rootTag);
-
- mFabricUIManager.completeRoot(rootTag, children);
- }
-
- @Test
- public void testSealReactShadowNode() {
- ReactRootView rootView =
- new ReactRootView(RuntimeEnvironment.application.getApplicationContext());
- int rootTag = mFabricUIManager.addRootView(rootView);
- String viewClass = ReactViewManager.REACT_CLASS;
-
- ReactShadowNode container = mFabricUIManager.createNode(6, viewClass, rootTag, null, randomInstanceHandle());
- List<ReactShadowNode> childSet = mFabricUIManager.createChildSet(rootTag);
- mFabricUIManager.appendChildToSet(childSet, container);
-
- assertThat(container.isSealed()).isFalse();
-
- mFabricUIManager.completeRoot(rootTag, childSet);
-
- assertThat(container.isSealed()).isTrue();
- }
-
- /**
- * Tests that cloned text nodes will not share measure functions
- */
- @Test
- public void testTextMutableClone() {
- ReactRootView rootView =
- new ReactRootView(RuntimeEnvironment.application.getApplicationContext());
- int rootTag = mFabricUIManager.addRootView(rootView);
- ReactShadowNode text =
- mFabricUIManager.createNode(0, ReactTextViewManager.REACT_CLASS, rootTag, null, randomInstanceHandle());
- assertThat(text.isMeasureDefined()).isTrue();
-
- ReactShadowNode textCopy = text.mutableCopy(randomInstanceHandle());
- assertThat(textCopy.isMeasureDefined()).isTrue();
-
- textCopy.setStyleWidth(200);
- text.onBeforeLayout();
- text.calculateLayout();
- textCopy.onBeforeLayout();
- textCopy.calculateLayout();
-
- assertThat(text.getLayoutWidth()).isNotEqualTo(textCopy.getLayoutWidth());
- }
-
- /**
- * Verifies that the reconciliation phase will always set the originalNode field of every node in
- * the tree to null once completeRoot has finished to prevent memory leaks.
- */
- @Test
- public void testRemoveOriginalNodeReferences() {
- ReactRootView rootView =
- new ReactRootView(RuntimeEnvironment.application.getApplicationContext());
- int rootTag = mFabricUIManager.addRootView(rootView);
- String viewClass = ReactViewManager.REACT_CLASS;
-
- ReactShadowNode aa = mFabricUIManager.createNode(2, viewClass, rootTag, null, randomInstanceHandle());
- ReactShadowNode a = mFabricUIManager.createNode(3, viewClass, rootTag, null, randomInstanceHandle());
- mFabricUIManager.appendChild(a, aa);
- ReactShadowNode bb = mFabricUIManager.createNode(4, viewClass, rootTag, null, randomInstanceHandle());
- ReactShadowNode b = mFabricUIManager.createNode(5, viewClass, rootTag, null, randomInstanceHandle());
- mFabricUIManager.appendChild(b, bb);
- ReactShadowNode container = mFabricUIManager.createNode(6, viewClass, rootTag, null, randomInstanceHandle());
- mFabricUIManager.appendChild(container, a);
- mFabricUIManager.appendChild(container, b);
- List<ReactShadowNode> childSet = mFabricUIManager.createChildSet(rootTag);
- mFabricUIManager.appendChildToSet(childSet, container);
- mFabricUIManager.completeRoot(rootTag, childSet);
-
- ReactShadowNode aaClone = mFabricUIManager.cloneNodeWithNewProps(aa, null);
- ReactShadowNode aClone = mFabricUIManager.cloneNodeWithNewChildren(a);
- mFabricUIManager.appendChild(aClone, aaClone);
- ReactShadowNode containerClone = mFabricUIManager.cloneNodeWithNewChildren(container);
- mFabricUIManager.appendChild(containerClone, b);
- mFabricUIManager.appendChild(containerClone, aClone);
- List<ReactShadowNode> childSet2 = mFabricUIManager.createChildSet(rootTag);
- mFabricUIManager.appendChildToSet(childSet2, containerClone);
- mFabricUIManager.completeRoot(rootTag, childSet2);
-
- ReactShadowNode[] nodes =
- new ReactShadowNode[] {aa, a, bb, b, container, aaClone, aClone, containerClone};
-
- for (ReactShadowNode node : nodes) {
- assertThat(node.getOriginalReactShadowNode()).isNull();
- }
- }
-
- private void assertSameChildren(ReactShadowNode node1, ReactShadowNode node2) {
- assertThat(node1.getChildCount()).isEqualTo(node2.getChildCount());
- for (int i = 0; i < node1.getChildCount(); i++) {
- assertThat(node1.getChildAt(i)).isEqualTo(node2.getChildAt(i));
- }
- }
-
- private void assertSameFields(ReactShadowNode node1, ReactShadowNode node2) {
- assertThat(node1.getReactTag()).isEqualTo(node2.getReactTag());
- assertThat(node1.getViewClass()).isEqualTo(node2.getViewClass());
- assertThat(node2.getParent()).isNull();
- assertThat(node1.getThemedContext()).isEqualTo(node2.getThemedContext());
- assertThat(node1.isVirtual()).isEqualTo(node2.isVirtual());
- assertThat(node1.getLayoutDirection()).isEqualTo(node2.getLayoutDirection());
- assertThat(node1.getLayoutHeight()).isEqualTo(node2.getLayoutHeight());
- assertThat(node1.getLayoutWidth()).isEqualTo(node2.getLayoutWidth());
- assertThat(node1.getLayoutX()).isEqualTo(node2.getLayoutX());
- assertThat(node1.getLayoutY()).isEqualTo(node2.getLayoutY());
- for (int spacingType = Spacing.LEFT; spacingType <= Spacing.ALL; spacingType++) {
- assertThat(node1.getStylePadding(spacingType)).isEqualTo(node2.getStylePadding(spacingType));
- }
- assertThat(node1.getStyleWidth()).isEqualTo(node2.getStyleWidth());
- assertThat(node1.getStyleHeight()).isEqualTo(node2.getStyleHeight());
- }
-
- private ReactShadowNode createViewNode() {
- ReactShadowNode node = new ReactShadowNodeImpl();
- node.setViewClassName(ReactViewManager.REACT_CLASS);
- node.setThemedContext(mThemedReactContext);
- return node;
- }
-}

ReactAndroid/src/test/java/com/facebook/react/fabric/ReactShadowNodeTest.java

@@ -1,23 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-package com.facebook.react.fabric;
-
-import com.facebook.react.uimanager.ReactShadowNodeImpl;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-
-/** Tests {@link ReactShadowNode} */
-@RunWith(RobolectricTestRunner.class)
-public class ReactShadowNodeTest {
-
- @Test(expected = AssertionError.class)
- public void testClonedInstance() {
- TestReactShadowNode node = new TestReactShadowNode();
- node.mutableCopy(node.getInstanceHandle());
- }
-
- private static class TestReactShadowNode extends ReactShadowNodeImpl {}
-}

ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/modules/camera/ImageStoreManagerTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/modules/clipboard/ClipboardModuleTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/modules/dialog/DialogModuleTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/modules/network/HeaderUtilTest.java

@@ -0,0 +1,76 @@
+/**
+ * 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;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class HeaderUtilTest {
+ public static final String TABULATION_TEST = "\teyJhbGciOiJS\t";
+ public static final String TABULATION_STRIP_EXPECTED = "eyJhbGciOiJS";
+ public static final String NUMBERS_TEST = "0123456789";
+ public static final String SPECIALS_TEST = "!@#$%^&*()-=_+{}[]\\|;:'\",.<>/?";
+ public static final String ALPHABET_TEST = "abcdefghijklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWHYZ";
+ public static final String VALUE_BANNED_SYMBOLS_TEST = "���name�����������\u007f\u001f";
+ public static final String NAME_BANNED_SYMBOLS_TEST = "���name�����������\u007f\u0020\u001f";
+ public static final String BANNED_TEST_EXPECTED = "name";
+
+ @Test
+ public void nameStripKeepsLetters() {
+ assertEquals(ALPHABET_TEST, HeaderUtil.stripHeaderName(ALPHABET_TEST));
+
+ }
+
+ @Test
+ public void valueStripKeepsLetters() {
+ assertEquals(ALPHABET_TEST, HeaderUtil.stripHeaderValue(ALPHABET_TEST));
+ }
+
+ @Test
+ public void nameStripKeepsNumbers() {
+ assertEquals(NUMBERS_TEST, HeaderUtil.stripHeaderName(NUMBERS_TEST));
+
+ }
+
+ @Test
+ public void valueStripKeepsNumbers() {
+ assertEquals(NUMBERS_TEST, HeaderUtil.stripHeaderValue(NUMBERS_TEST));
+ }
+
+ @Test
+ public void valueStripKeepsSpecials() {
+ assertEquals(SPECIALS_TEST, HeaderUtil.stripHeaderValue(SPECIALS_TEST));
+ }
+
+ @Test
+ public void nameStripKeepsSpecials() {
+ assertEquals(SPECIALS_TEST, HeaderUtil.stripHeaderName(SPECIALS_TEST));
+ }
+
+ @Test
+ public void valueStripKeepsTabs() {
+ assertEquals(TABULATION_TEST, HeaderUtil.stripHeaderValue(TABULATION_TEST));
+ }
+
+ @Test
+ public void nameStripDeletesTabs() {
+ assertEquals(TABULATION_STRIP_EXPECTED, HeaderUtil.stripHeaderName(TABULATION_TEST));
+ }
+
+ @Test
+ public void valueStripRemovesExtraSymbols() {
+ assertEquals(BANNED_TEST_EXPECTED, HeaderUtil.stripHeaderValue(VALUE_BANNED_SYMBOLS_TEST));
+ }
+
+ @Test
+ public void nameStripRemovesExtraSymbols() {
+ assertEquals(BANNED_TEST_EXPECTED, HeaderUtil.stripHeaderName(NAME_BANNED_SYMBOLS_TEST));
+ }
+
+}

ReactAndroid/src/test/java/com/facebook/react/modules/network/NetworkingModuleTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -18,6 +18,7 @@
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.common.StandardCharsets;
import com.facebook.react.common.network.OkHttpCallUtil;
import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter;
@@ -310,6 +311,131 @@
}
@Test
+ public void testPostJsonContentTypeHeader() throws Exception {
+ OkHttpClient httpClient = mock(OkHttpClient.class);
+ when(httpClient.newCall(any(Request.class))).thenAnswer(new Answer<Object>() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Call callMock = mock(Call.class);
+ return callMock;
+ }
+ });
+ OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class);
+ when(clientBuilder.build()).thenReturn(httpClient);
+ when(httpClient.newBuilder()).thenReturn(clientBuilder);
+ NetworkingModule networkingModule =
+ new NetworkingModule(mock(ReactApplicationContext.class), "", httpClient);
+
+ JavaOnlyMap body = new JavaOnlyMap();
+ body.putString("string", "{ \"key\": \"value\" }");
+
+ networkingModule.sendRequest(
+ "POST",
+ "http://somedomain/bar",
+ 0,
+ JavaOnlyArray.of(JavaOnlyArray.of("Content-Type", "application/json")),
+ body,
+ /* responseType */ "text",
+ /* useIncrementalUpdates*/ true,
+ /* timeout */ 0,
+ /* withCredentials */ false);
+
+ ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
+ verify(httpClient).newCall(argumentCaptor.capture());
+
+ // Verify okhttp does not append "charset=utf-8"
+ assertThat(argumentCaptor.getValue().body().contentType().toString()).isEqualTo("application/json");
+ }
+
+ @Test
+ public void testRespectsExistingCharacterSet() throws Exception {
+ RCTDeviceEventEmitter emitter = mock(RCTDeviceEventEmitter.class);
+ ReactApplicationContext context = mock(ReactApplicationContext.class);
+ when(context.getJSModule(any(Class.class))).thenReturn(emitter);
+
+ OkHttpClient httpClient = mock(OkHttpClient.class);
+ when(httpClient.newCall(any(Request.class))).thenAnswer(new Answer<Object>() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Call callMock = mock(Call.class);
+ return callMock;
+ }
+ });
+ OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class);
+ when(clientBuilder.build()).thenReturn(httpClient);
+ when(httpClient.newBuilder()).thenReturn(clientBuilder);
+ NetworkingModule networkingModule = new NetworkingModule(context, "", httpClient);
+
+ JavaOnlyMap body = new JavaOnlyMap();
+ body.putString("string", "Friðjónsson");
+
+ mockEvents();
+
+ networkingModule.sendRequest(
+ "POST",
+ "http://somedomain/bar",
+ 0,
+ JavaOnlyArray.of(JavaOnlyArray.of("Content-Type", "text/plain; charset=utf-16")),
+ body,
+ /* responseType */ "text",
+ /* useIncrementalUpdates*/ true,
+ /* timeout */ 0,
+ /* withCredentials */ false);
+
+ ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
+ verify(httpClient).newCall(argumentCaptor.capture());
+
+ Buffer contentBuffer = new Buffer();
+ argumentCaptor.getValue().body().writeTo(contentBuffer);
+ assertThat(contentBuffer.readString(StandardCharsets.UTF_16)).isEqualTo("Friðjónsson");
+ }
+
+ @Test
+ public void testGracefullyRecoversFromInvalidContentType() throws Exception {
+ RCTDeviceEventEmitter emitter = mock(RCTDeviceEventEmitter.class);
+ ReactApplicationContext context = mock(ReactApplicationContext.class);
+ when(context.getJSModule(any(Class.class))).thenReturn(emitter);
+
+ OkHttpClient httpClient = mock(OkHttpClient.class);
+ when(httpClient.newCall(any(Request.class))).thenAnswer(new Answer<Object>() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Call callMock = mock(Call.class);
+ return callMock;
+ }
+ });
+ OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class);
+ when(clientBuilder.build()).thenReturn(httpClient);
+ when(httpClient.newBuilder()).thenReturn(clientBuilder);
+ NetworkingModule networkingModule = new NetworkingModule(context, "", httpClient);
+
+ JavaOnlyMap body = new JavaOnlyMap();
+ body.putString("string", "test");
+
+ mockEvents();
+
+ networkingModule.sendRequest(
+ "POST",
+ "http://somedomain/bar",
+ 0,
+ JavaOnlyArray.of(JavaOnlyArray.of("Content-Type", "invalid")),
+ body,
+ /* responseType */ "text",
+ /* useIncrementalUpdates*/ true,
+ /* timeout */ 0,
+ /* withCredentials */ false);
+
+ ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
+ verify(httpClient).newCall(argumentCaptor.capture());
+
+ Buffer contentBuffer = new Buffer();
+ argumentCaptor.getValue().body().writeTo(contentBuffer);
+
+ assertThat(contentBuffer.readString(StandardCharsets.UTF_8)).isEqualTo("test");
+ assertThat(argumentCaptor.getValue().header("Content-Type")).isEqualTo("invalid");
+ }
+
+ @Test
public void testMultipartPostRequestSimple() throws Exception {
PowerMockito.mockStatic(RequestBodyUtil.class);
when(RequestBodyUtil.getFileInputStream(any(ReactContext.class), any(String.class)))

ReactAndroid/src/test/java/com/facebook/react/modules/network/ProgressiveStringDecoderTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2017-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/modules/network/ReactCookieJarContainerTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/modules/share/ShareModuleTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,31 +11,31 @@
import android.content.Intent;
import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.JavaOnlyMap;
import com.facebook.react.bridge.Promise;
-import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactTestHelper;
-import com.facebook.react.bridge.JavaOnlyMap;
-
-import javax.annotation.Nullable;
+import com.facebook.react.bridge.WritableMap;
import org.junit.After;
import org.junit.Before;
-import org.junit.Test;
import org.junit.Rule;
+import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.rule.PowerMockRule;
-import org.robolectric.internal.ShadowExtractor;
-import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.internal.ShadowExtractor;
import org.robolectric.shadows.ShadowApplication;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -53,7 +53,9 @@
@Before
public void prepareModules() throws Exception {
PowerMockito.mockStatic(Arguments.class);
- Mockito.when(Arguments.createMap()).thenAnswer(new Answer<Object>() {
+ Mockito
+ .when(Arguments.createMap())
+ .thenAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return new JavaOnlyMap();
@@ -84,16 +86,33 @@
mShareModule.share(content, dialogTitle, promise);
final Intent chooserIntent =
- ((ShadowApplication)ShadowExtractor.extract(RuntimeEnvironment.application)).getNextStartedActivity();
+ ((ShadowApplication) ShadowExtractor.extract(RuntimeEnvironment.application)).getNextStartedActivity();
assertNotNull("Dialog was not displayed", chooserIntent);
assertEquals(Intent.ACTION_CHOOSER, chooserIntent.getAction());
- assertEquals(dialogTitle, chooserIntent.getExtras().get(Intent.EXTRA_TITLE));
-
- final Intent contentIntent = (Intent)chooserIntent.getExtras().get(Intent.EXTRA_INTENT);
+ assertEquals(
+ dialogTitle,
+ chooserIntent
+ .getExtras()
+ .get(Intent.EXTRA_TITLE)
+ );
+
+ final Intent contentIntent = (Intent) chooserIntent
+ .getExtras()
+ .get(Intent.EXTRA_INTENT);
assertNotNull("Intent was not built correctly", contentIntent);
assertEquals(Intent.ACTION_SEND, contentIntent.getAction());
- assertEquals(title, contentIntent.getExtras().get(Intent.EXTRA_SUBJECT));
- assertEquals(message, contentIntent.getExtras().get(Intent.EXTRA_TEXT));
+ assertEquals(
+ title,
+ contentIntent
+ .getExtras()
+ .get(Intent.EXTRA_SUBJECT)
+ );
+ assertEquals(
+ message,
+ contentIntent
+ .getExtras()
+ .get(Intent.EXTRA_TEXT)
+ );
assertEquals(1, promise.getResolved());
}
@@ -111,7 +130,8 @@
}
final static class SimplePromise implements Promise {
- private static final String DEFAULT_ERROR = "EUNSPECIFIED";
+ private static final String ERROR_DEFAULT_CODE = "EUNSPECIFIED";
+ private static final String ERROR_DEFAULT_MESSAGE = "Error not specified.";
private int mResolved;
private int mRejected;
@@ -147,31 +167,72 @@
@Override
public void reject(String code, String message) {
- reject(code, message, /*Throwable*/null);
+ reject(code, message, /*Throwable*/null, /*WritableMap*/null);
}
@Override
- @Deprecated
- public void reject(String message) {
- reject(DEFAULT_ERROR, message, /*Throwable*/null);
+ public void reject(String code, Throwable throwable) {
+ reject(code, /*Message*/null, throwable, /*WritableMap*/null);
+ }
+
+ @Override
+ public void reject(String code, String message, Throwable throwable) {
+ reject(code, message, throwable, /*WritableMap*/null);
}
@Override
- public void reject(String code, Throwable e) {
- reject(code, e.getMessage(), e);
+ public void reject(Throwable throwable) {
+ reject(/*Code*/null, /*Message*/null, throwable, /*WritableMap*/null);
}
@Override
- public void reject(Throwable e) {
- reject(DEFAULT_ERROR, e.getMessage(), e);
+ public void reject(Throwable throwable, WritableMap userInfo) {
+ reject(/*Code*/null, /*Message*/null, throwable, userInfo);
}
@Override
- public void reject(String code, String message, @Nullable Throwable e) {
+ public void reject(String code, @Nonnull WritableMap userInfo) {
+ reject(code, /*Message*/null, /*Throwable*/null, userInfo);
+ }
+
+ @Override
+ public void reject(String code, Throwable throwable, WritableMap userInfo) {
+ reject(code, /*Message*/null, throwable, userInfo);
+ }
+
+ @Override
+ public void reject(String code, String message, @Nonnull WritableMap userInfo) {
+ reject(code, message, /*Throwable*/null, userInfo);
+ }
+
+ @Override
+ public void reject(
+ String code,
+ String message,
+ @Nullable Throwable throwable,
+ @Nullable WritableMap userInfo
+ ) {
mRejected++;
+
+ if (code == null) {
+ mErrorCode = ERROR_DEFAULT_CODE;
+ } else {
mErrorCode = code;
+ }
+
+ if (message != null) {
mErrorMessage = message;
+ } else if (throwable != null) {
+ mErrorMessage = throwable.getMessage();
+ } else {
+ mErrorMessage = ERROR_DEFAULT_MESSAGE;
}
}
+ @Override
+ @Deprecated
+ public void reject(String message) {
+ reject(/*Code*/null, message, /*Throwable*/null, /*WritableMap*/null);
+ }
+ }
}

ReactAndroid/src/test/java/com/facebook/react/modules/storage/AsyncStorageModuleTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/modules/timing/TimingModuleTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/packagerconnection/JSPackagerClientTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/uimanager/BaseViewManagerTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/uimanager/layoutanimation/BUCK

@@ -1,4 +1,4 @@
-load("//tools/build_defs/oss:rn_defs.bzl", "YOGA_TARGET", "react_native_dep", "react_native_target", "react_native_tests_target", "rn_robolectric_test")
+load("//tools/build_defs/oss:rn_defs.bzl", "YOGA_TARGET", "react_native_dep", "react_native_target", "rn_robolectric_test")
rn_robolectric_test(
name = "layoutanimation",

ReactAndroid/src/test/java/com/facebook/react/uimanager/LayoutPropertyApplicatorTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/uimanager/MatrixMathHelperTest.java

@@ -1,3 +1,10 @@
+/**
+ * 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.uimanager;
import org.junit.Test;

ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropAnnotationSetterSpecTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropAnnotationSetterTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropConstantsTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropForShadowNodeSetterTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropForShadowNodeSpecTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/uimanager/SimpleViewPropertyTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleConstantsTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/util/BUCK

@@ -0,0 +1,19 @@
+load("//tools/build_defs/oss:rn_defs.bzl", "react_native_dep", "react_native_target", "rn_robolectric_test")
+
+rn_robolectric_test(
+ name = "util",
+ srcs = glob(["**/*.java"]),
+ visibility = [
+ "PUBLIC",
+ ],
+ deps = [
+ react_native_dep("libraries/fbcore/src/test/java/com/facebook/powermock:powermock"),
+ react_native_dep("third-party/java/fest:fest"),
+ react_native_dep("third-party/java/jsr-305:jsr-305"),
+ react_native_dep("third-party/java/junit:junit"),
+ react_native_dep("third-party/java/mockito:mockito"),
+ react_native_dep("third-party/java/robolectric3/robolectric:robolectric"),
+ react_native_target("java/com/facebook/react/util:util"),
+ react_native_target("java/com/facebook/react/bridge:bridge"),
+ ],
+)

ReactAndroid/src/test/java/com/facebook/react/util/JSStackTraceTest.java

@@ -0,0 +1,40 @@
+/**
+ * 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.util;
+
+import org.junit.Test;
+import org.junit.Assert;
+import com.facebook.react.bridge.JavaOnlyMap;
+import com.facebook.react.bridge.JavaOnlyArray;
+
+public class JSStackTraceTest {
+
+ @Test
+ public void testSymbolication() {
+ JavaOnlyArray values = JavaOnlyArray.of(
+ JavaOnlyMap.of("methodName", "method_from_bundle", "column", 11, "lineNumber", 7, "file", "Fb4aBundle.js"),
+ JavaOnlyMap.of("methodName", "method_from_ram_bundle", "column", 13, "lineNumber", 18, "file", "199.js"),
+ JavaOnlyMap.of("methodName", "method_from_ram_bundle_with_address", "column", 13, "lineNumber", 18, "file", "address at 199.js"),
+ JavaOnlyMap.of("methodName", "method_from_segment", "column", 18, "lineNumber", 9, "file", "seg-1.js"),
+ JavaOnlyMap.of("methodName", "method_from_segment_with_address", "column", 18, "lineNumber", 9, "file", "address at seg-1.js"),
+ JavaOnlyMap.of("methodName", "method_from_ram_segment", "column", 20, "lineNumber", 10, "file", "seg-3_198.js"),
+ JavaOnlyMap.of("methodName", "method_from_ram_segment_with_address", "column", 20, "lineNumber", 10, "file", "address at seg-3_198.js")
+ );
+ String message = JSStackTrace.format("Error", values);
+ Assert.assertEquals(message, "Error, stack:\n"
+ + "method_from_bundle@7:11\n"
+ + "method_from_ram_bundle@199.js:18:13\n"
+ + "method_from_ram_bundle_with_address@199.js:18:13\n"
+ + "method_from_segment@seg-1.js:9:18\n"
+ + "method_from_segment_with_address@seg-1.js:9:18\n"
+ + "method_from_ram_segment@seg-3_198.js:10:20\n"
+ + "method_from_ram_segment_with_address@seg-3_198.js:10:20\n"
+ );
+ }
+
+}

ReactAndroid/src/test/java/com/facebook/react/views/image/ImageResizeModeTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/views/image/ReactImagePropertyTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/views/slider/ReactSliderPropertyTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/views/text/CustomLineHeightSpanTest.java

@@ -1,3 +1,10 @@
+/**
+ * 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.views.text;
import android.graphics.Paint;

ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -12,11 +12,10 @@
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
-import android.annotation.TargetApi;
import android.graphics.Color;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
-import android.os.Build;
+import android.text.Layout;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.AbsoluteSizeSpan;
@@ -406,9 +405,6 @@
assertThat(textView.getText().toString()).isEqualTo(testTextTransformed);
}
- // JELLY_BEAN is needed for TextView#getMaxLines(), which is OK, because in the actual code we
- // only use TextView#setMaxLines() which exists since API Level 1.
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Test
public void testMaxLinesApplied() {
UIManagerModule uiManager = getUIManagerModule();
@@ -424,6 +420,21 @@
assertThat(textView.getEllipsize()).isEqualTo(TextUtils.TruncateAt.END);
}
+ @TargetApi(Build.VERSION_CODES.O)
+ @Test
+ public void testTextAlignJustifyApplied() {
+ UIManagerModule uiManager = getUIManagerModule();
+
+ ReactRootView rootView = createText(
+ uiManager,
+ JavaOnlyMap.of("textAlign", "justify"),
+ JavaOnlyMap.of(ReactRawTextShadowNode.PROP_TEXT, "test text"));
+
+ TextView textView = (TextView) rootView.getChildAt(0);
+ assertThat(textView.getText().toString()).isEqualTo("test text");
+ assertThat(textView.getJustificationMode()).isEqualTo(Layout.JUSTIFICATION_MODE_INTER_WORD);
+ }
+
/**
* Make sure TextView has exactly one span and that span has given type.
*/

ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,8 +9,10 @@
import android.content.res.ColorStateList;
import android.graphics.Color;
+import android.os.Build;
import android.text.InputType;
import android.text.InputFilter;
+import android.text.Layout;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.inputmethod.EditorInfo;
@@ -344,6 +346,10 @@
assertThat(view.getGravity() & Gravity.HORIZONTAL_GRAVITY_MASK).isEqualTo(Gravity.CENTER_HORIZONTAL);
mManager.updateProperties(view, buildStyles("textAlign", null));
assertThat(view.getGravity() & Gravity.HORIZONTAL_GRAVITY_MASK).isEqualTo(defaultHorizontalGravity);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ mManager.updateProperties(view, buildStyles("textAlign", "justify"));
+ assertThat(view.getJustificationMode()).isEqualTo(Layout.JUSTIFICATION_MODE_INTER_WORD);
+ }
// TextAlignVertical
mManager.updateProperties(view, buildStyles("textAlignVertical", "top"));

ReactAndroid/src/test/java/com/facebook/react/views/textinput/TextInputTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/com/facebook/react/views/view/ColorUtilTest.java

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactAndroid/src/test/java/org/mockito/configuration/MockitoConfiguration.java

@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactCommon/better/better.h

@@ -0,0 +1,57 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+namespace facebook {
+namespace better {
+
+/*
+ * `Better` is a trivial collection of basic tools borrowed from other low-level
+ * general purpose libraries (like Folly, Abseil or Boost). The main goals of
+ * Better:
+ * - Make the codebase more portable;
+ * - Make the dependency list explicit (by decoupling it as a dependency list of
+ * Better);
+ * - Make relying on modern C++ patterns and tools in code simple and easy.
+ * - Make executing experiments with different dependencies easier.
+ *
+ * What should be part of Better and what should not? Should I add some piece of
+ * functionality in the Better? Here is a quick checklist.
+ *
+ * If one of the following is true, yes, go for it:
+ * - If some feature is already in some future C++ standard (possibly in draft
+ * stage) and it's already implemented in some 3rd party library.
+ * - If some standardized feature of C++ is implemented in the standard not in
+ * the most efficient way (because the standard enforces some tricky constraints
+ * (like always-valid iterators) which nobody uses and should use), but you have
+ * a library that does it right providing exact same interface.
+ *
+ * If one of the following is true, please do *NOT* do it (at least as part of
+ * the library):
+ * - You want to use some very fancy pattern that your favorite library (but
+ * nothing else) provides, and You want to make this pattern very command in the
+ * code base. Your hope is that this pattern will conquer the world and be
+ * a part of the C++ standard eventually.
+ * - You favorite library provides some general purpose container that 10x times
+ * faster than the standard one, so You want to use that in the code base. That
+ * container does not have compatible API though (because it's a clear trade-off
+ * with efficiency, of course).
+ */
+
+/*
+ * Configuration
+ */
+
+/*
+ * Enables using Folly containers instead of standard ones (such as map, vector,
+ * string, optional and etc.)
+ */
+#define BETTER_USE_FOLLY_CONTAINERS
+
+} // namespace better
+} // namespace facebook

ReactCommon/better/BUCK

@@ -0,0 +1,55 @@
+load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags")
+load(
+ "//tools/build_defs/oss:rn_defs.bzl",
+ "ANDROID",
+ "APPLE",
+ "get_apple_compiler_flags",
+ "get_apple_inspector_flags",
+ "rn_xplat_cxx_library",
+ "subdir_glob",
+)
+
+APPLE_COMPILER_FLAGS = get_apple_compiler_flags()
+
+rn_xplat_cxx_library(
+ name = "better",
+ srcs = glob(
+ ["**/*.cpp"],
+ exclude = glob(["tests/**/*.cpp"]),
+ ),
+ headers = glob(
+ ["**/*.h"],
+ exclude = glob(["tests/**/*.h"]),
+ ),
+ header_namespace = "",
+ exported_headers = subdir_glob(
+ [
+ ("", "*.h"),
+ ],
+ prefix = "better",
+ ),
+ compiler_flags = [
+ "-fexceptions",
+ "-frtti",
+ "-std=c++14",
+ "-Wall",
+ ],
+ fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
+ fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
+ force_static = True,
+ macosx_tests_override = [],
+ platforms = (ANDROID, APPLE),
+ preprocessor_flags = [
+ "-DLOG_TAG=\"ReactNative\"",
+ "-DWITH_FBSYSTRACE=1",
+ ],
+ tests = [],
+ visibility = ["PUBLIC"],
+ deps = [
+ "xplat//fbsystrace:fbsystrace",
+ "xplat//folly:headers_only",
+ "xplat//folly:memory",
+ "xplat//folly:molly",
+ "xplat//third-party/glog:glog",
+ ],
+)

ReactCommon/better/map.h

@@ -0,0 +1,45 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <better/better.h>
+
+#ifdef BETTER_USE_FOLLY_CONTAINERS
+
+#include <folly/container/F14Map.h>
+
+#else
+
+#include <unordered_map>
+
+#endif
+
+namespace facebook {
+namespace better {
+
+/*
+ * Note: In Better, `map` aliases to `unorderd_map` because everyone agrees that
+ * an *ordered* map is nonsense and was a huge mistake for standardization. If
+ * you need an *ordered* map, feel free to introduce that as
+ * `better::ordered_map`.
+ */
+
+#ifdef BETTER_USE_FOLLY_CONTAINERS
+
+template <typename... Ts>
+using map = folly::F14FastMap<Ts...>;
+
+#else
+
+template <typename... Ts>
+using map = std::unordered_map<Ts...>;
+
+#endif
+
+} // namespace better
+} // namespace facebook

ReactCommon/better/mutex.h

@@ -0,0 +1,24 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <folly/SharedMutex.h>
+#include <mutex>
+#include <shared_mutex>
+
+namespace facebook {
+namespace better {
+
+template <typename T>
+using shared_lock = std::shared_lock<T>;
+
+template <typename T>
+using shared_mutex = folly::SharedMutex<T>;
+
+} // namespace better
+} // namespace facebook

ReactCommon/better/optional.h

@@ -0,0 +1,38 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <better/better.h>
+
+#ifdef BETTER_USE_FOLLY_CONTAINERS
+
+#include <folly/Optional.h>
+
+#else
+
+#include <optional>
+
+#endif
+
+namespace facebook {
+namespace better {
+
+#ifdef BETTER_USE_FOLLY_CONTAINERS
+
+template <typename Value>
+using optional = folly::Optional<Value>;
+
+#else
+
+template <typename Value>
+using optional = std::optional<Value>;
+
+#endif
+
+} // namespace better
+} // namespace facebook

ReactCommon/better/set.h

@@ -0,0 +1,38 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <better/better.h>
+
+#ifdef BETTER_USE_FOLLY_CONTAINERS
+
+#include <folly/container/F14Set.h>
+
+#else
+
+#include <unordered_set>
+
+#endif
+
+namespace facebook {
+namespace better {
+
+#ifdef BETTER_USE_FOLLY_CONTAINERS
+
+template <typename... Ts>
+using set = folly::F14FastSet<Ts...>;
+
+#else
+
+template <typename... Ts>
+using set = std::unordered_set<Ts...>;
+
+#endif
+
+} // namespace better
+} // namespace facebook

ReactCommon/better/string.h

@@ -0,0 +1,36 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <better/better.h>
+
+#ifdef BETTER_USE_FOLLY_CONTAINERS
+
+#include <folly/fbstring.h>
+
+#else
+
+#include <string>
+
+#endif
+
+namespace facebook {
+namespace better {
+
+#ifdef BETTER_USE_FOLLY_CONTAINERS
+
+using string = folly::fbstring;
+
+#else
+
+using string = std::string;
+
+#endif
+
+} // namespace better
+} // namespace facebook

ReactCommon/better/vector.h

@@ -0,0 +1,38 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <better/better.h>
+
+#ifdef BETTER_USE_FOLLY_CONTAINERS
+
+#include <folly/fbvector.h>
+
+#else
+
+#include <vector>
+
+#endif
+
+namespace facebook {
+namespace better {
+
+#ifdef BETTER_USE_FOLLY_CONTAINERS
+
+template <typename... Ts>
+using vector = folly::fbvector<Ts...>;
+
+#else
+
+template <typename... Ts>
+using vector = std::vector<Ts...>;
+
+#endif
+
+} // namespace better
+} // namespace facebook

ReactCommon/config/BUCK

@@ -0,0 +1,45 @@
+load("@fbsource//tools/build_defs:default_platform_defs.bzl", "ANDROID", "APPLE")
+load("@fbsource//tools/build_defs:glob_defs.bzl", "subdir_glob")
+load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "flags", "get_debug_preprocessor_flags", "get_static_library_ios_flags")
+load("@fbsource//tools/build_defs/oss:rn_defs.bzl", "get_apple_inspector_flags", "rn_xplat_cxx_library")
+
+APPLE_COMPILER_FLAGS = flags.get_flag_value(
+ get_static_library_ios_flags(),
+ "compiler_flags",
+)
+
+rn_xplat_cxx_library(
+ name = "config",
+ srcs = glob(["**/*.cpp"]),
+ header_namespace = "",
+ exported_headers = subdir_glob(
+ [
+ ("", "**/*.h"),
+ ],
+ prefix = "react/config",
+ ),
+ compiler_flags = [
+ "-fexceptions",
+ "-frtti",
+ "-std=c++14",
+ "-Wall",
+ ],
+ fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
+ fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
+ force_static = True,
+ platforms = (ANDROID, APPLE),
+ preprocessor_flags = [
+ "-DLOG_TAG=\"ReactNative\"",
+ "-DWITH_FBSYSTRACE=1",
+ ],
+ visibility = [
+ "PUBLIC",
+ ],
+ deps = [
+ "xplat//fbsystrace:fbsystrace",
+ "xplat//folly:headers_only",
+ "xplat//folly:memory",
+ "xplat//folly:molly",
+ "xplat//third-party/glog:glog",
+ ],
+)

ReactCommon/config/ReactNativeConfig.cpp

@@ -0,0 +1,40 @@
+/**
+ * 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.
+ */
+
+#include "ReactNativeConfig.h"
+
+namespace facebook {
+namespace react {
+
+/**
+ * ReactNative configuration as provided by the hosting app.
+ * Provide a sub-class implementation to allow app specific customization.
+ */
+ReactNativeConfig::ReactNativeConfig() {}
+
+ReactNativeConfig::~ReactNativeConfig() {}
+
+EmptyReactNativeConfig::EmptyReactNativeConfig() {}
+
+bool EmptyReactNativeConfig::getBool(const std::string &param) const {
+ return false;
+}
+
+std::string EmptyReactNativeConfig::getString(const std::string &param) const {
+ return "";
+}
+
+int64_t EmptyReactNativeConfig::getInt64(const std::string &param) const {
+ return 0;
+}
+
+double EmptyReactNativeConfig::getDouble(const std::string &param) const {
+ return 0.0;
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/config/ReactNativeConfig.h

@@ -0,0 +1,44 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <string>
+
+namespace facebook {
+namespace react {
+
+/**
+ * ReactNative configuration as provided by the hosting app.
+ * Provide a sub-class implementation to allow app specific customization.
+ */
+class ReactNativeConfig {
+public:
+ ReactNativeConfig();
+ virtual ~ReactNativeConfig();
+
+ virtual bool getBool(const std::string &param) const = 0;
+ virtual std::string getString(const std::string &param) const = 0;
+ virtual int64_t getInt64(const std::string &param) const = 0;
+ virtual double getDouble(const std::string &param) const = 0;
+};
+
+/**
+ * Empty configuration that will always provide "falsy" values.
+ */
+class EmptyReactNativeConfig : public ReactNativeConfig {
+public:
+ EmptyReactNativeConfig();
+
+ bool getBool(const std::string &param) const override;
+ std::string getString(const std::string &param) const override;
+ int64_t getInt64(const std::string &param) const override;
+ double getDouble(const std::string &param) const override;
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/cxxreact/Android.mk

@@ -1,31 +1,15 @@
+# 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.
+
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := reactnative
-LOCAL_SRC_FILES := \
- CxxNativeModule.cpp \
- Instance.cpp \
- JSBigString.cpp \
- JSBundleType.cpp \
- JSCExecutor.cpp \
- JSCLegacyTracing.cpp \
- JSCMemory.cpp \
- JSCNativeModules.cpp \
- JSCPerfStats.cpp \
- JSCSamplingProfiler.cpp \
- JSCTracing.cpp \
- JSCUtils.cpp \
- JSDeltaBundleClient.cpp \
- JSExecutor.cpp \
- JSIndexedRAMBundle.cpp \
- MethodCall.cpp \
- ModuleRegistry.cpp \
- NativeToJsBridge.cpp \
- Platform.cpp \
- RAMBundleRegistry.cpp \
- ReactMarker.cpp \
+LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/..
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
@@ -33,10 +17,10 @@
LOCAL_CFLAGS := \
-DLOG_TAG=\"ReactNative\"
-LOCAL_CFLAGS += -fexceptions -frtti
+LOCAL_CFLAGS += -fexceptions -frtti -Wno-unused-lambda-capture
-LOCAL_STATIC_LIBRARIES := jschelpers
-LOCAL_SHARED_LIBRARIES := libfb libfolly_json libjsc libglog
+LOCAL_STATIC_LIBRARIES := boost
+LOCAL_SHARED_LIBRARIES := jsinspector libfolly_json glog
include $(BUILD_STATIC_LIBRARY)
@@ -44,6 +28,4 @@
$(call import-module,folly)
$(call import-module,jsc)
$(call import-module,glog)
-$(call import-module,jschelpers)
$(call import-module,jsinspector)
-$(call import-module,privatedata)

ReactCommon/cxxreact/BUCK

@@ -1,5 +1,5 @@
-load("@xplat//tools/build_defs:glob_defs.bzl", "subdir_glob")
-load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "ANDROID_JSC_DEPS", "APPLE", "get_apple_compiler_flags", "APPLE_JSC_DEPS", "get_debug_preprocessor_flags", "get_android_inspector_flags", "get_apple_inspector_flags", "react_native_xplat_target", "rn_xplat_cxx_library")
+load("@fbsource//tools/build_defs:glob_defs.bzl", "subdir_glob")
+load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", "get_android_inspector_flags", "get_apple_compiler_flags", "get_apple_inspector_flags", "get_debug_preprocessor_flags", "react_native_xplat_target", "rn_xplat_cxx_library")
CXX_LIBRARY_COMPILER_FLAGS = [
"-std=c++14",
@@ -80,11 +80,8 @@
"CxxNativeModule.h",
"Instance.h",
"JSBundleType.h",
- "JSExecutor.h",
- "JSCExecutor.h",
- "JSCNativeModules.h",
- "JSCUtils.h",
"JSDeltaBundleClient.h",
+ "JSExecutor.h",
"JSIndexedRAMBundle.h",
"JSModulesUnbundle.h",
"MessageQueueThread.h",
@@ -92,7 +89,6 @@
"ModuleRegistry.h",
"NativeModule.h",
"NativeToJsBridge.h",
- "Platform.h",
"RAMBundleRegistry.h",
"ReactMarker.h",
"RecoverableError.h",
@@ -125,20 +121,10 @@
"-fexceptions",
"-frtti",
],
- fbandroid_deps = ANDROID_JSC_DEPS,
- fbandroid_preprocessor_flags = get_android_inspector_flags() + [
- "-DWITH_JSC_EXTRA_TRACING=1",
- "-DWITH_JSC_MEMORY_PRESSURE=1",
- "-DWITH_FB_MEMORY_PROFILING=1",
- ],
+ fbandroid_preprocessor_flags = get_android_inspector_flags(),
fbobjc_compiler_flags = get_apple_compiler_flags(),
- fbobjc_deps = APPLE_JSC_DEPS,
fbobjc_force_static = True,
- fbobjc_frameworks = [
- "$SDKROOT/System/Library/Frameworks/JavaScriptCore.framework",
- ],
fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
- force_static = True,
macosx_tests_override = [],
platforms = (ANDROID, APPLE),
preprocessor_flags = [
@@ -156,12 +142,9 @@
"xplat//folly:molly",
":jsbigstring",
":module",
- react_native_xplat_target("jschelpers:jschelpers"),
react_native_xplat_target("jsinspector:jsinspector"),
react_native_xplat_target("microprofiler:microprofiler"),
"xplat//folly:optional",
"xplat//third-party/glog:glog",
- react_native_xplat_target("jschelpers:jscinternalhelpers"),
- react_native_xplat_target("privatedata:privatedata"),
],
)

ReactCommon/cxxreact/CxxModule.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -67,13 +67,14 @@
std::string name;
size_t callbacks;
+ bool isPromise;
std::function<void(folly::dynamic, Callback, Callback)> func;
std::function<folly::dynamic(folly::dynamic)> syncFunc;
const char *getType() {
assert(func || syncFunc);
- return func ? (callbacks == 2 ? "promise" : "async") : "sync";
+ return func ? (isPromise ? "promise" : "async") : "sync";
}
// std::function/lambda ctors
@@ -82,24 +83,36 @@
std::function<void()>&& afunc)
: name(std::move(aname))
, callbacks(0)
+ , isPromise(false)
, func(std::bind(std::move(afunc))) {}
Method(std::string aname,
std::function<void(folly::dynamic)>&& afunc)
: name(std::move(aname))
, callbacks(0)
- , func(std::bind(std::move(afunc), _1)) {}
+ , isPromise(false)
+ , func(std::bind(std::move(afunc), std::placeholders::_1)) {}
Method(std::string aname,
std::function<void(folly::dynamic, Callback)>&& afunc)
: name(std::move(aname))
, callbacks(1)
- , func(std::bind(std::move(afunc), _1, _2)) {}
+ , isPromise(false)
+ , func(std::bind(std::move(afunc), std::placeholders::_1, std::placeholders::_2)) {}
Method(std::string aname,
std::function<void(folly::dynamic, Callback, Callback)>&& afunc)
: name(std::move(aname))
, callbacks(2)
+ , isPromise(true)
+ , func(std::move(afunc)) {}
+
+ Method(std::string aname,
+ std::function<void(folly::dynamic, Callback, Callback)>&& afunc,
+ AsyncTagType)
+ : name(std::move(aname))
+ , callbacks(2)
+ , isPromise(false)
, func(std::move(afunc)) {}
// method pointer ctors
@@ -108,25 +121,39 @@
Method(std::string aname, T* t, void (T::*method)())
: name(std::move(aname))
, callbacks(0)
+ , isPromise(false)
, func(std::bind(method, t)) {}
template <typename T>
Method(std::string aname, T* t, void (T::*method)(folly::dynamic))
: name(std::move(aname))
, callbacks(0)
- , func(std::bind(method, t, _1)) {}
+ , isPromise(false)
+ , func(std::bind(method, t, std::placeholders::_1)) {}
template <typename T>
Method(std::string aname, T* t, void (T::*method)(folly::dynamic, Callback))
: name(std::move(aname))
, callbacks(1)
- , func(std::bind(method, t, _1, _2)) {}
+ , isPromise(false)
+ , func(std::bind(method, t, std::placeholders::_1, std::placeholders::_2)) {}
template <typename T>
Method(std::string aname, T* t, void (T::*method)(folly::dynamic, Callback, Callback))
: name(std::move(aname))
, callbacks(2)
- , func(std::bind(method, t, _1, _2, _3)) {}
+ , isPromise(true)
+ , func(std::bind(method, t, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)) {}
+
+ template <typename T>
+ Method(std::string aname,
+ T* t,
+ void (T::*method)(folly::dynamic, Callback, Callback),
+ AsyncTagType)
+ : name(std::move(aname))
+ , callbacks(2)
+ , isPromise(false)
+ , func(std::bind(method, t, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)) {}
// sync std::function/lambda ctors
@@ -139,6 +166,7 @@
SyncTagType)
: name(std::move(aname))
, callbacks(0)
+ , isPromise(false)
, syncFunc([afunc=std::move(afunc)] (const folly::dynamic&)
{ return afunc(); })
{}
@@ -148,6 +176,7 @@
SyncTagType)
: name(std::move(aname))
, callbacks(0)
+ , isPromise(false)
, syncFunc(std::move(afunc))
{}
};

ReactCommon/cxxreact/CxxNativeModule.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactCommon/cxxreact/CxxNativeModule.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactCommon/cxxreact/Instance.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -150,6 +149,10 @@
return nativeToJsBridge_ ? nativeToJsBridge_->isInspectable() : false;
}
+bool Instance::isBatchActive() {
+ return nativeToJsBridge_ ? nativeToJsBridge_->isBatchActive() : false;
+}
+
void Instance::callJSFunction(std::string &&module, std::string &&method,
folly::dynamic &&params) {
callback_->incrementPendingJSCalls();

ReactCommon/cxxreact/Instance.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -58,6 +58,7 @@
std::unique_ptr<const JSBigString> jsonValue);
void *getJavaScriptContext();
bool isInspectable();
+ bool isBatchActive();
void callJSFunction(std::string &&module, std::string &&method,
folly::dynamic &&params);
void callJSCallback(uint64_t callbackId, folly::dynamic &&params);

ReactCommon/cxxreact/JsArgumentHelpers.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactCommon/cxxreact/JsArgumentHelpers-inl.h

@@ -1,9 +1,10 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
#pragma once
+#include <folly/dynamic.h>
namespace facebook {
namespace xplat {

ReactCommon/cxxreact/JSBigString.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -9,11 +9,65 @@
#include <sys/stat.h>
#include <folly/Memory.h>
+#include <folly/portability/SysMman.h>
#include <folly/ScopeGuard.h>
namespace facebook {
namespace react {
+JSBigFileString::JSBigFileString(int fd, size_t size, off_t offset /*= 0*/)
+ : m_fd { -1 }
+ , m_data { nullptr } {
+ folly::checkUnixError(m_fd = dup(fd),
+ "Could not duplicate file descriptor");
+
+ // Offsets given to mmap must be page aligend. We abstract away that
+ // restriction by sending a page aligned offset to mmap, and keeping track
+ // of the offset within the page that we must alter the mmap pointer by to
+ // get the final desired offset.
+ if (offset != 0) {
+ const static auto ps = getpagesize();
+ auto d = lldiv(offset, ps);
+
+ m_mapOff = d.quot;
+ m_pageOff = d.rem;
+ m_size = size + m_pageOff;
+ } else {
+ m_mapOff = 0;
+ m_pageOff = 0;
+ m_size = size;
+ }
+}
+
+JSBigFileString::~JSBigFileString() {
+ if (m_data) {
+ munmap((void *)m_data, m_size);
+ }
+ close(m_fd);
+}
+
+
+const char *JSBigFileString::c_str() const {
+ if (!m_data) {
+ m_data =
+ (const char *) mmap(0, m_size, PROT_READ, MAP_SHARED, m_fd, m_mapOff);
+ CHECK(m_data != MAP_FAILED)
+ << " fd: " << m_fd
+ << " size: " << m_size
+ << " offset: " << m_mapOff
+ << " error: " << std::strerror(errno);
+ }
+ return m_data + m_pageOff;
+}
+
+size_t JSBigFileString::size() const {
+ return m_size - m_pageOff;
+}
+
+int JSBigFileString::fd() const {
+ return m_fd;
+}
+
std::unique_ptr<const JSBigFileString> JSBigFileString::fromPath(const std::string& sourceURL) {
int fd = ::open(sourceURL.c_str(), O_RDONLY);
folly::checkUnixError(fd, "Could not open file", sourceURL);

ReactCommon/cxxreact/JSBigString.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -6,12 +6,17 @@
#pragma once
#include <fcntl.h>
+#include <unistd.h>
#include <sys/mman.h>
#include <folly/Exception.h>
#ifndef RN_EXPORT
-#define RN_EXPORT __attribute__((visibility("default")))
+# ifdef _MSC_VER
+# define RN_EXPORT
+# else
+# define RN_EXPORT __attribute__((visibility("default")))
+# endif
#endif
namespace facebook {
@@ -72,7 +77,7 @@
// buffer, and provides an accessor for writing to it. This can be
// used to construct a JSBigString in place, such as by reading from a
// file.
-class JSBigBufferString : public JSBigString {
+class RN_EXPORT JSBigBufferString : public JSBigString {
public:
JSBigBufferString(size_t size)
: m_data(new char[size + 1])
@@ -111,62 +116,17 @@
class RN_EXPORT JSBigFileString : public JSBigString {
public:
- JSBigFileString(int fd, size_t size, off_t offset = 0)
- : m_fd {-1}
- , m_data {nullptr}
- {
- folly::checkUnixError(m_fd = dup(fd),
- "Could not duplicate file descriptor");
-
- // Offsets given to mmap must be page aligend. We abstract away that
- // restriction by sending a page aligned offset to mmap, and keeping track
- // of the offset within the page that we must alter the mmap pointer by to
- // get the final desired offset.
- if (offset != 0) {
- const static auto ps = getpagesize();
- auto d = lldiv(offset, ps);
-
- m_mapOff = d.quot;
- m_pageOff = d.rem;
- m_size = size + m_pageOff;
- } else {
- m_mapOff = 0;
- m_pageOff = 0;
- m_size = size;
- }
- }
-
- ~JSBigFileString() {
- if (m_data) {
- munmap((void *)m_data, m_size);
- }
- close(m_fd);
- }
+ JSBigFileString(int fd, size_t size, off_t offset = 0);
+ ~JSBigFileString();
bool isAscii() const override {
return true;
}
- const char *c_str() const override {
- if (!m_data) {
- m_data =
- (const char *)mmap(0, m_size, PROT_READ, MAP_PRIVATE, m_fd, m_mapOff);
- CHECK(m_data != MAP_FAILED)
- << " fd: " << m_fd
- << " size: " << m_size
- << " offset: " << m_mapOff
- << " error: " << std::strerror(errno);
- }
- return m_data + m_pageOff;
- }
+ const char *c_str() const override;
- size_t size() const override {
- return m_size - m_pageOff;
- }
-
- int fd() const {
- return m_fd;
- }
+ size_t size() const override;
+ int fd() const;
static std::unique_ptr<const JSBigFileString> fromPath(const std::string& sourceURL);

ReactCommon/cxxreact/JSBundleType.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactCommon/cxxreact/JSBundleType.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -7,6 +7,7 @@
#include <cstdint>
#include <cstring>
+#include <folly/Portability.h>
#ifndef RN_EXPORT
#define RN_EXPORT __attribute__((visibility("default")))
@@ -34,7 +35,8 @@
* 4 bytes, for BC bundles this is 12 bytes. This structure holds the first 12
* bytes from a bundle in a way that gives access to that information.
*/
-struct __attribute__((packed)) BundleHeader {
+FOLLY_PACK_PUSH
+struct FOLLY_PACK_ATTR BundleHeader {
BundleHeader() {
std::memset(this, 0, sizeof(BundleHeader));
}
@@ -43,6 +45,7 @@
uint32_t reserved_;
uint32_t version;
};
+FOLLY_PACK_POP
/**
* parseTypeFromHeader

ReactCommon/cxxreact/JSCExecutor.cpp

@@ -1,790 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#include "JSCExecutor.h"
-
-#include <fcntl.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <algorithm>
-#include <condition_variable>
-#include <mutex>
-#include <sstream>
-#include <string>
-#include <system_error>
-
-#include <arpa/inet.h>
-#include <folly/Conv.h>
-#include <folly/Exception.h>
-#include <folly/Memory.h>
-#include <folly/String.h>
-#include <folly/json.h>
-#include <glog/logging.h>
-#include <jschelpers/JSCHelpers.h>
-#include <jschelpers/Value.h>
-#include <jsinspector/InspectorInterfaces.h>
-
-#include "JSBigString.h"
-#include "JSBundleType.h"
-#include "JSCLegacyTracing.h"
-#include "JSCMemory.h"
-#include "JSCPerfStats.h"
-#include "JSCSamplingProfiler.h"
-#include "JSCTracing.h"
-#include "JSCUtils.h"
-#include "JSModulesUnbundle.h"
-#include "MessageQueueThread.h"
-#include "ModuleRegistry.h"
-#include "Platform.h"
-#include "RAMBundleRegistry.h"
-#include "RecoverableError.h"
-#include "SystraceSection.h"
-
-#if defined(WITH_FB_JSC_TUNING) && defined(__ANDROID__)
-#include <jsc_config_android.h>
-#endif
-
-namespace facebook {
-namespace react {
-
-namespace {
-
-template <JSValueRef (JSCExecutor::*method)(size_t, const JSValueRef[])>
-inline JSObjectCallAsFunctionCallback exceptionWrapMethod() {
- struct funcWrapper {
- static JSValueRef call(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- try {
- auto executor = Object::getGlobalObject(ctx).getPrivate<JSCExecutor>();
- if (executor &&
- executor->getJavaScriptContext()) { // Executor not invalidated
- return (executor->*method)(argumentCount, arguments);
- }
- } catch (...) {
- *exception = translatePendingCppExceptionToJSError(ctx, function);
- }
- return Value::makeUndefined(ctx);
- }
- };
-
- return &funcWrapper::call;
-}
-
-template <JSValueRef (
- JSCExecutor::*method)(JSObjectRef object, JSStringRef propertyName)>
-inline JSObjectGetPropertyCallback exceptionWrapMethod() {
- struct funcWrapper {
- static JSValueRef call(
- JSContextRef ctx,
- JSObjectRef object,
- JSStringRef propertyName,
- JSValueRef* exception) {
- try {
- auto executor = Object::getGlobalObject(ctx).getPrivate<JSCExecutor>();
- if (executor &&
- executor->getJavaScriptContext()) { // Executor not invalidated
- return (executor->*method)(object, propertyName);
- }
- } catch (...) {
- *exception = translatePendingCppExceptionToJSError(ctx, object);
- }
- return Value::makeUndefined(ctx);
- }
- };
-
- return &funcWrapper::call;
-}
-
-} // namespace
-
-#if DEBUG
-static JSValueRef nativeInjectHMRUpdate(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- String execJSString = Value(ctx, arguments[0]).toString();
- // Temporary workaround for 0.57 and Metro 48 which did not pass second
- // argument to this function.
- // Actually we probably should to check both arguments before use and
- // throw JS exception with suitable error string.
- String jsURL = argumentCount > 1 ? Value(ctx, arguments[1]).toString() : String();
- evaluateScript(ctx, execJSString, jsURL);
- return Value::makeUndefined(ctx);
-}
-#endif
-
-std::unique_ptr<JSExecutor> JSCExecutorFactory::createJSExecutor(
- std::shared_ptr<ExecutorDelegate> delegate,
- std::shared_ptr<MessageQueueThread> jsQueue) {
- return folly::make_unique<JSCExecutor>(
- delegate, jsQueue, m_jscConfig);
-}
-
-JSCExecutor::JSCExecutor(
- std::shared_ptr<ExecutorDelegate> delegate,
- std::shared_ptr<MessageQueueThread> messageQueueThread,
- const folly::dynamic& jscConfig) throw(JSException)
- : m_delegate(delegate),
- m_messageQueueThread(messageQueueThread),
- m_nativeModules(delegate ? delegate->getModuleRegistry() : nullptr),
- m_jscConfig(jscConfig) {
- initOnJSVMThread();
-
- {
- SystraceSection s("nativeModuleProxy object");
- installGlobalProxy(
- m_context,
- "nativeModuleProxy",
- exceptionWrapMethod<&JSCExecutor::getNativeModule>());
- }
-}
-
-JSCExecutor::~JSCExecutor() {
- CHECK(*m_isDestroyed)
- << "JSCExecutor::destroy() must be called before its destructor!";
-}
-
-void JSCExecutor::destroy() {
- *m_isDestroyed = true;
- if (m_messageQueueThread.get()) {
- m_messageQueueThread->runOnQueueSync([this]() { terminateOnJSVMThread(); });
- } else {
- terminateOnJSVMThread();
- }
-}
-
-void JSCExecutor::setContextName(const std::string& name) {
- String jsName = String(m_context, name.c_str());
- JSC_JSGlobalContextSetName(m_context, jsName);
-}
-
-static bool canUseInspector(JSContextRef context) {
-#ifdef WITH_INSPECTOR
-#if defined(__APPLE__)
- return isCustomJSCPtr(context); // WITH_INSPECTOR && Apple
-#else
- return true; // WITH_INSPECTOR && Android
-#endif
-#else
- return false; // !WITH_INSPECTOR
-#endif
-}
-
-static bool canUseSamplingProfiler(JSContextRef context) {
-#if defined(__APPLE__) || defined(WITH_JSC_EXTRA_TRACING)
- return JSC_JSSamplingProfilerEnabled(context);
-#else
- return false;
-#endif
-}
-
-void JSCExecutor::initOnJSVMThread() throw(JSException) {
- SystraceSection s("JSCExecutor::initOnJSVMThread");
-
-#if defined(__APPLE__)
- const bool useCustomJSC =
- m_jscConfig.getDefault("UseCustomJSC", false).getBool();
- if (useCustomJSC) {
- JSC_configureJSCForIOS(true, toJson(m_jscConfig));
- }
-#else
- const bool useCustomJSC = false;
-#endif
-
-#if defined(WITH_FB_JSC_TUNING) && defined(__ANDROID__)
- configureJSCForAndroid(m_jscConfig);
-#endif
-
- // Create a custom global class, so we can store data in it later using
- // JSObjectSetPrivate
- JSClassRef globalClass = nullptr;
- {
- SystraceSection s_("JSClassCreate");
- JSClassDefinition definition = kJSClassDefinitionEmpty;
- definition.attributes |= kJSClassAttributeNoAutomaticPrototype;
- globalClass = JSC_JSClassCreate(useCustomJSC, &definition);
- }
- {
- SystraceSection s_("JSGlobalContextCreateInGroup");
- m_context =
- JSC_JSGlobalContextCreateInGroup(useCustomJSC, nullptr, globalClass);
- }
- JSC_JSClassRelease(useCustomJSC, globalClass);
-
- // Add a pointer to ourselves so we can retrieve it later in our hooks
- Object::getGlobalObject(m_context).setPrivate(this);
-
- if (canUseInspector(m_context)) {
- const std::string ownerId =
- m_jscConfig.getDefault("OwnerIdentity", "unknown").getString();
- const std::string appId =
- m_jscConfig.getDefault("AppIdentity", "unknown").getString();
- const std::string deviceId =
- m_jscConfig.getDefault("DeviceIdentity", "unknown").getString();
- auto checkIsInspectedRemote = [ownerId, appId, deviceId]() {
- return isNetworkInspected(ownerId, appId, deviceId);
- };
-
- auto& globalInspector = facebook::react::getInspectorInstance();
- JSC_JSGlobalContextEnableDebugger(
- m_context, globalInspector, ownerId.c_str(), checkIsInspectedRemote);
- }
-
- installNativeHook<&JSCExecutor::nativeFlushQueueImmediate>(
- "nativeFlushQueueImmediate");
- installNativeHook<&JSCExecutor::nativeCallSyncHook>("nativeCallSyncHook");
-
- installGlobalFunction(
- m_context, "nativeLoggingHook", JSCNativeHooks::loggingHook);
- installGlobalFunction(
- m_context, "nativePerformanceNow", JSCNativeHooks::nowHook);
-
-#if DEBUG
- installGlobalFunction(
- m_context, "nativeInjectHMRUpdate", nativeInjectHMRUpdate);
-#endif
-
- addNativeTracingHooks(m_context);
- addNativeTracingLegacyHooks(m_context);
- addJSCMemoryHooks(m_context);
- addJSCPerfStatsHooks(m_context);
-
- JSCNativeHooks::installPerfHooks(m_context);
-
- if (canUseSamplingProfiler(m_context)) {
- initSamplingProfilerOnMainJSCThread(m_context);
- }
-}
-
-bool JSCExecutor::isNetworkInspected(
- const std::string& owner,
- const std::string& app,
- const std::string& device) {
-#ifdef WITH_FB_DBG_ATTACH_BEFORE_EXEC
- auto connect_socket = [](int socket_desc, std::string address, int port) {
- if (socket_desc < 0) {
- ::close(socket_desc);
- return false;
- }
-
- struct timeval tv;
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- auto sock_opt_rcv_resp = setsockopt(
- socket_desc,
- SOL_SOCKET,
- SO_RCVTIMEO,
- (const char*)&tv,
- sizeof(struct timeval));
- if (sock_opt_rcv_resp < 0) {
- ::close(socket_desc);
- return false;
- }
-
- auto sock_opt_snd_resp = setsockopt(
- socket_desc,
- SOL_SOCKET,
- SO_SNDTIMEO,
- (const char*)&tv,
- sizeof(struct timeval));
- if (sock_opt_snd_resp < 0) {
- ::close(socket_desc);
- return false;
- }
-
- struct sockaddr_in server;
- server.sin_addr.s_addr = inet_addr(address.c_str());
- server.sin_family = AF_INET;
- server.sin_port = htons(port);
- auto connect_resp =
- ::connect(socket_desc, (struct sockaddr*)&server, sizeof(server));
- if (connect_resp < 0) {
- ::close(socket_desc);
- return false;
- }
-
- return true;
- };
-
- int socket_desc = socket(AF_INET, SOCK_STREAM, 0);
-
- if (!connect_socket(socket_desc, "127.0.0.1", 8082)) {
-#if defined(__ANDROID__)
- socket_desc = socket(AF_INET, SOCK_STREAM, 0);
- if (!connect_socket(socket_desc, "10.0.2.2", 8082) /* emulator */) {
- socket_desc = socket(AF_INET, SOCK_STREAM, 0);
- if (!connect_socket(socket_desc, "10.0.3.2", 8082) /* genymotion */) {
- return false;
- }
- }
-#else //! defined(__ANDROID__)
- return false;
-#endif // defined(__ANDROID__)
- }
-
- std::string escapedOwner =
- folly::uriEscape<std::string>(owner, folly::UriEscapeMode::QUERY);
- std::string escapedApp =
- folly::uriEscape<std::string>(app, folly::UriEscapeMode::QUERY);
- std::string escapedDevice =
- folly::uriEscape<std::string>(device, folly::UriEscapeMode::QUERY);
- std::string msg = folly::to<std::string>(
- "GET /autoattach?title=",
- escapedOwner,
- "&app=",
- escapedApp,
- "&device=",
- escapedDevice,
- " HTTP/1.1\r\n\r\n");
- auto send_resp = ::send(socket_desc, msg.c_str(), msg.length(), 0);
- if (send_resp < 0) {
- ::close(socket_desc);
- return false;
- }
-
- char server_reply[200];
- server_reply[199] = '\0';
- auto recv_resp =
- ::recv(socket_desc, server_reply, sizeof(server_reply) - 1, 0);
- if (recv_resp < 0) {
- ::close(socket_desc);
- return false;
- }
-
- std::string response(server_reply);
- if (response.size() < 25) {
- ::close(socket_desc);
- return false;
- }
- auto responseCandidate = response.substr(response.size() - 25);
- auto found =
- responseCandidate.find("{\"autoattach\":true}") != std::string::npos;
- ::close(socket_desc);
- return found;
-#else //! WITH_FB_DBG_ATTACH_BEFORE_EXEC
- return false;
-#endif // WITH_FB_DBG_ATTACH_BEFORE_EXEC
-}
-
-void JSCExecutor::terminateOnJSVMThread() {
- JSGlobalContextRef context = m_context;
- m_context = nullptr;
- Object::getGlobalObject(context).setPrivate(nullptr);
- m_nativeModules.reset();
-
- if (canUseInspector(context)) {
- auto& globalInspector = facebook::react::getInspectorInstance();
- JSC_JSGlobalContextDisableDebugger(context, globalInspector);
- }
-
- JSC_JSGlobalContextRelease(context);
-}
-
-#ifdef WITH_FBJSCEXTENSIONS
-static const char* explainLoadSourceStatus(JSLoadSourceStatus status) {
- switch (status) {
- case JSLoadSourceIsCompiled:
- return "No error encountered during source load";
-
- case JSLoadSourceErrorOnRead:
- return "Error reading source";
-
- case JSLoadSourceIsNotCompiled:
- return "Source is not compiled";
-
- case JSLoadSourceErrorVersionMismatch:
- return "Source version not supported";
-
- default:
- return "Bad error code";
- }
-}
-#endif
-
-// basename_r isn't in all iOS SDKs, so use this simple version instead.
-static std::string simpleBasename(const std::string& path) {
- size_t pos = path.rfind("/");
- return (pos != std::string::npos) ? path.substr(pos) : path;
-}
-
-void JSCExecutor::loadApplicationScript(
- std::unique_ptr<const JSBigString> script,
- std::string sourceURL) {
- SystraceSection s(
- "JSCExecutor::loadApplicationScript", "sourceURL", sourceURL);
-
- std::string scriptName = simpleBasename(sourceURL);
- ReactMarker::logTaggedMarker(
- ReactMarker::RUN_JS_BUNDLE_START, scriptName.c_str());
- String jsSourceURL(m_context, sourceURL.c_str());
-
-// TODO t15069155: reduce the number of overrides here
-#ifdef WITH_FBJSCEXTENSIONS
- if (auto fileStr = dynamic_cast<const JSBigFileString*>(script.get())) {
- JSContextLock lock(m_context);
- JSLoadSourceStatus jsStatus;
- auto bcSourceCode = JSCreateSourceCodeFromFile(
- fileStr->fd(), jsSourceURL, nullptr, &jsStatus);
-
- switch (jsStatus) {
- case JSLoadSourceIsCompiled:
- if (!bcSourceCode) {
- throw std::runtime_error("Unexpected error opening compiled bundle");
- }
- evaluateSourceCode(m_context, bcSourceCode, jsSourceURL);
-
- flush();
-
- ReactMarker::logMarker(ReactMarker::CREATE_REACT_CONTEXT_STOP);
- ReactMarker::logTaggedMarker(
- ReactMarker::RUN_JS_BUNDLE_STOP, scriptName.c_str());
- return;
-
- case JSLoadSourceErrorVersionMismatch:
- throw RecoverableError(explainLoadSourceStatus(jsStatus));
-
- case JSLoadSourceErrorOnRead:
- case JSLoadSourceIsNotCompiled:
- // Not bytecode, fall through.
- break;
- }
- }
-#elif defined(__APPLE__)
- BundleHeader header;
- memcpy(
- &header, script->c_str(), std::min(script->size(), sizeof(BundleHeader)));
- auto scriptTag = parseTypeFromHeader(header);
-
- if (scriptTag == ScriptTag::BCBundle) {
- using file_ptr = std::unique_ptr<FILE, decltype(&fclose)>;
- file_ptr source(fopen(sourceURL.c_str(), "r"), fclose);
- int sourceFD = fileno(source.get());
-
- JSValueRef jsError;
- JSValueRef result = JSC_JSEvaluateBytecodeBundle(
- m_context, NULL, sourceFD, jsSourceURL, &jsError);
- if (result == nullptr) {
- throw JSException(m_context, jsError, jsSourceURL);
- }
- } else
-#endif
- {
- String jsScript;
- JSContextLock lock(m_context);
- {
- SystraceSection s_(
- "JSCExecutor::loadApplicationScript-createExpectingAscii");
- ReactMarker::logMarker(ReactMarker::JS_BUNDLE_STRING_CONVERT_START);
- jsScript = adoptString(std::move(script));
- ReactMarker::logMarker(ReactMarker::JS_BUNDLE_STRING_CONVERT_STOP);
- }
-
- SystraceSection s_("JSCExecutor::loadApplicationScript-evaluateScript");
- evaluateScript(m_context, jsScript, jsSourceURL);
- }
-
- flush();
-
- ReactMarker::logMarker(ReactMarker::CREATE_REACT_CONTEXT_STOP);
- ReactMarker::logTaggedMarker(
- ReactMarker::RUN_JS_BUNDLE_STOP, scriptName.c_str());
-}
-
-void JSCExecutor::setBundleRegistry(
- std::unique_ptr<RAMBundleRegistry> bundleRegistry) {
- if (!m_bundleRegistry) {
- installNativeHook<&JSCExecutor::nativeRequire>("nativeRequire");
- }
- m_bundleRegistry = std::move(bundleRegistry);
-}
-
-void JSCExecutor::registerBundle(
- uint32_t bundleId,
- const std::string& bundlePath) {
- if (m_bundleRegistry) {
- m_bundleRegistry->registerBundle(bundleId, bundlePath);
- } else {
- auto stPath = JSCExecutor::getSyntheticBundlePath(bundleId, bundlePath);
- auto sourceUrlStr = String(m_context, stPath.c_str());
- auto source = adoptString(JSBigFileString::fromPath(bundlePath));
- evaluateScript(m_context, source, sourceUrlStr);
- }
-}
-
-void JSCExecutor::bindBridge() throw(JSException) {
- SystraceSection s("JSCExecutor::bindBridge");
- std::call_once(m_bindFlag, [this] {
- auto global = Object::getGlobalObject(m_context);
- auto batchedBridgeValue = global.getProperty("__fbBatchedBridge");
- if (batchedBridgeValue.isUndefined()) {
- auto requireBatchedBridge =
- global.getProperty("__fbRequireBatchedBridge");
- if (!requireBatchedBridge.isUndefined()) {
- batchedBridgeValue = requireBatchedBridge.asObject().callAsFunction({});
- }
- if (batchedBridgeValue.isUndefined()) {
- throw JSException(
- "Could not get BatchedBridge, make sure your bundle is packaged correctly");
- }
- }
-
- auto batchedBridge = batchedBridgeValue.asObject();
- m_callFunctionReturnFlushedQueueJS =
- batchedBridge.getProperty("callFunctionReturnFlushedQueue").asObject();
- m_invokeCallbackAndReturnFlushedQueueJS =
- batchedBridge.getProperty("invokeCallbackAndReturnFlushedQueue")
- .asObject();
- m_flushedQueueJS = batchedBridge.getProperty("flushedQueue").asObject();
- m_callFunctionReturnResultAndFlushedQueueJS =
- batchedBridge.getProperty("callFunctionReturnResultAndFlushedQueue")
- .asObject();
- });
-}
-
-void JSCExecutor::callNativeModules(Value&& value) {
- SystraceSection s("JSCExecutor::callNativeModules");
- // If this fails, you need to pass a fully functional delegate with a
- // module registry to the factory/ctor.
- CHECK(m_delegate) << "Attempting to use native modules without a delegate";
- try {
- auto calls = value.toJSONString();
- m_delegate->callNativeModules(*this, folly::parseJson(calls), true);
- } catch (...) {
- std::string message = "Error in callNativeModules()";
- try {
- message += ":" + value.toString().str();
- } catch (...) {
- // ignored
- }
- std::throw_with_nested(std::runtime_error(message));
- }
-}
-
-void JSCExecutor::flush() {
- SystraceSection s("JSCExecutor::flush");
-
- if (m_flushedQueueJS) {
- callNativeModules(m_flushedQueueJS->callAsFunction({}));
- return;
- }
-
- // When a native module is called from JS, BatchedBridge.enqueueNativeCall()
- // is invoked. For that to work, require('BatchedBridge') has to be called,
- // and when that happens, __fbBatchedBridge is set as a side effect.
- auto global = Object::getGlobalObject(m_context);
- auto batchedBridgeValue = global.getProperty("__fbBatchedBridge");
- // So here, if __fbBatchedBridge doesn't exist, then we know no native calls
- // have happened, and we were able to determine this without forcing
- // BatchedBridge to be loaded as a side effect.
- if (!batchedBridgeValue.isUndefined()) {
- // If calls were made, we bind to the JS bridge methods, and use them to
- // get the pending queue of native calls.
- bindBridge();
- callNativeModules(m_flushedQueueJS->callAsFunction({}));
- } else if (m_delegate) {
- // If we have a delegate, we need to call it; we pass a null list to
- // callNativeModules, since we know there are no native calls, without
- // calling into JS again. If no calls were made and there's no delegate,
- // nothing happens, which is correct.
- callNativeModules(Value::makeNull(m_context));
- }
-}
-
-void JSCExecutor::callFunction(
- const std::string& moduleId,
- const std::string& methodId,
- const folly::dynamic& arguments) {
- SystraceSection s("JSCExecutor::callFunction");
- // This weird pattern is because Value is not default constructible.
- // The lambda is inlined, so there's no overhead.
- auto result = [&] {
- JSContextLock lock(m_context);
- try {
- if (!m_callFunctionReturnResultAndFlushedQueueJS) {
- bindBridge();
- }
- return m_callFunctionReturnFlushedQueueJS->callAsFunction(
- {Value(m_context, String::createExpectingAscii(m_context, moduleId)),
- Value(m_context, String::createExpectingAscii(m_context, methodId)),
- Value::fromDynamic(m_context, std::move(arguments))});
- } catch (...) {
- std::throw_with_nested(
- std::runtime_error("Error calling " + moduleId + "." + methodId));
- }
- }();
- callNativeModules(std::move(result));
-}
-
-void JSCExecutor::invokeCallback(
- const double callbackId,
- const folly::dynamic& arguments) {
- SystraceSection s("JSCExecutor::invokeCallback");
- auto result = [&] {
- JSContextLock lock(m_context);
- try {
- if (!m_invokeCallbackAndReturnFlushedQueueJS) {
- bindBridge();
- }
- return m_invokeCallbackAndReturnFlushedQueueJS->callAsFunction(
- {Value::makeNumber(m_context, callbackId),
- Value::fromDynamic(m_context, std::move(arguments))});
- } catch (...) {
- std::throw_with_nested(std::runtime_error(
- folly::to<std::string>("Error invoking callback ", callbackId)));
- }
- }();
- callNativeModules(std::move(result));
-}
-
-void JSCExecutor::setGlobalVariable(
- std::string propName,
- std::unique_ptr<const JSBigString> jsonValue) {
- try {
- SystraceSection s("JSCExecutor::setGlobalVariable", "propName", propName);
- auto valueToInject = Value::fromJSON(adoptString(std::move(jsonValue)));
- Object::getGlobalObject(m_context).setProperty(
- propName.c_str(), valueToInject);
- } catch (...) {
- std::throw_with_nested(
- std::runtime_error("Error setting global variable: " + propName));
- }
-}
-
-std::string JSCExecutor::getDescription() {
-#if defined(__APPLE__)
- if (isCustomJSCPtr(m_context)) {
- return "Custom JSC";
- } else {
- return "System JSC";
- }
-#else
- return "JSC";
-#endif
-}
-
-String JSCExecutor::adoptString(std::unique_ptr<const JSBigString> script) {
-#if defined(WITH_FBJSCEXTENSIONS)
- const JSBigString* string = script.release();
- auto jsString = JSStringCreateAdoptingExternal(
- string->c_str(), string->size(), (void*)string, [](void* s) {
- delete static_cast<JSBigString*>(s);
- });
- return String::adopt(m_context, jsString);
-#else
- return script->isAscii()
- ? String::createExpectingAscii(m_context, script->c_str(), script->size())
- : String(m_context, script->c_str());
-#endif
-}
-
-void* JSCExecutor::getJavaScriptContext() {
- return m_context;
-}
-
-bool JSCExecutor::isInspectable() {
- return canUseInspector(m_context);
-}
-
-void JSCExecutor::handleMemoryPressure(int pressureLevel) {
-#ifdef WITH_JSC_MEMORY_PRESSURE
- JSHandleMemoryPressure(
- this, m_context, static_cast<JSMemoryPressure>(pressureLevel));
-#endif
-}
-
-void JSCExecutor::flushQueueImmediate(Value&& queue) {
- auto queueStr = queue.toJSONString();
- m_delegate->callNativeModules(*this, folly::parseJson(queueStr), false);
-}
-
-void JSCExecutor::loadModule(uint32_t bundleId, uint32_t moduleId) {
- auto module = m_bundleRegistry->getModule(bundleId, moduleId);
- auto sourceUrl = String::createExpectingAscii(m_context, module.name);
- auto source = adoptString(
- std::unique_ptr<JSBigString>(new JSBigStdString(module.code)));
- evaluateScript(m_context, source, sourceUrl);
-}
-
-// Native JS hooks
-template <JSValueRef (JSCExecutor::*method)(size_t, const JSValueRef[])>
-void JSCExecutor::installNativeHook(const char* name) {
- installGlobalFunction(m_context, name, exceptionWrapMethod<method>());
-}
-
-JSValueRef JSCExecutor::getNativeModule(
- JSObjectRef object,
- JSStringRef propertyName) {
- if (JSC_JSStringIsEqualToUTF8CString(m_context, propertyName, "name")) {
- return Value(m_context, String(m_context, "NativeModules"));
- }
-
- return m_nativeModules.getModule(m_context, propertyName);
-}
-
-JSValueRef JSCExecutor::nativeRequire(
- size_t count,
- const JSValueRef arguments[]) {
- if (count > 2 || count == 0) {
- throw std::invalid_argument("Got wrong number of args");
- }
-
- uint32_t moduleId =
- folly::to<uint32_t>(Value(m_context, arguments[0]).getNumberOrThrow());
- uint32_t bundleId = count == 2
- ? folly::to<uint32_t>(Value(m_context, arguments[1]).getNumberOrThrow())
- : 0;
-
- ReactMarker::logMarker(ReactMarker::NATIVE_REQUIRE_START);
- loadModule(bundleId, moduleId);
- ReactMarker::logMarker(ReactMarker::NATIVE_REQUIRE_STOP);
- return Value::makeUndefined(m_context);
-}
-
-JSValueRef JSCExecutor::nativeFlushQueueImmediate(
- size_t argumentCount,
- const JSValueRef arguments[]) {
- if (argumentCount != 1) {
- throw std::invalid_argument("Got wrong number of args");
- }
-
- flushQueueImmediate(Value(m_context, arguments[0]));
- return Value::makeUndefined(m_context);
-}
-
-JSValueRef JSCExecutor::nativeCallSyncHook(
- size_t argumentCount,
- const JSValueRef arguments[]) {
- if (argumentCount != 3) {
- throw std::invalid_argument("Got wrong number of args");
- }
-
- unsigned int moduleId = Value(m_context, arguments[0]).asUnsignedInteger();
- unsigned int methodId = Value(m_context, arguments[1]).asUnsignedInteger();
- folly::dynamic args =
- folly::parseJson(Value(m_context, arguments[2]).toJSONString());
-
- if (!args.isArray()) {
- throw std::invalid_argument(folly::to<std::string>(
- "method parameters should be array, but are ", args.typeName()));
- }
-
- MethodCallResult result = m_delegate->callSerializableNativeHook(
- *this, moduleId, methodId, std::move(args));
- if (!result.hasValue()) {
- return Value::makeUndefined(m_context);
- }
- return Value::fromDynamic(m_context, result.value());
-}
-
-} // namespace react
-} // namespace facebook

ReactCommon/cxxreact/JSCExecutor.h

@@ -1,141 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#pragma once
-
-#include <cstdint>
-#include <memory>
-#include <mutex>
-
-#include <cxxreact/JSCNativeModules.h>
-#include <cxxreact/JSExecutor.h>
-#include <folly/Optional.h>
-#include <folly/json.h>
-#include <jschelpers/JSCHelpers.h>
-#include <jschelpers/JavaScriptCore.h>
-#include <jschelpers/Value.h>
-#include <privatedata/PrivateDataBase.h>
-
-#ifndef RN_EXPORT
-#define RN_EXPORT __attribute__((visibility("default")))
-#endif
-
-namespace facebook {
-namespace react {
-
-class MessageQueueThread;
-class RAMBundleRegistry;
-
-class RN_EXPORT JSCExecutorFactory : public JSExecutorFactory {
-public:
- JSCExecutorFactory(const folly::dynamic& jscConfig) :
- m_jscConfig(jscConfig) {}
- std::unique_ptr<JSExecutor> createJSExecutor(
- std::shared_ptr<ExecutorDelegate> delegate,
- std::shared_ptr<MessageQueueThread> jsQueue) override;
-private:
- std::string m_cacheDir;
- folly::dynamic m_jscConfig;
-};
-
-template<typename T>
-struct JSCValueEncoder {
- // If you get a build error here, it means the compiler can't see the template instantation of toJSCValue
- // applicable to your type.
- static const Value toJSCValue(JSGlobalContextRef ctx, T&& value);
-};
-
-template<>
-struct JSCValueEncoder<folly::dynamic> {
- static const Value toJSCValue(JSGlobalContextRef ctx, const folly::dynamic &&value) {
- return Value::fromDynamic(ctx, value);
- }
-};
-
-class RN_EXPORT JSCExecutor : public JSExecutor, public PrivateDataBase {
-public:
- /**
- * Must be invoked from thread this Executor will run on.
- */
- explicit JSCExecutor(std::shared_ptr<ExecutorDelegate> delegate,
- std::shared_ptr<MessageQueueThread> messageQueueThread,
- const folly::dynamic& jscConfig) throw(JSException);
- ~JSCExecutor() override;
-
- virtual void loadApplicationScript(
- std::unique_ptr<const JSBigString> script,
- std::string sourceURL) override;
-
- virtual void setBundleRegistry(std::unique_ptr<RAMBundleRegistry> bundleRegistry) override;
- virtual void registerBundle(uint32_t bundleId, const std::string& bundlePath) override;
-
- virtual void callFunction(
- const std::string& moduleId,
- const std::string& methodId,
- const folly::dynamic& arguments) override;
-
- virtual void invokeCallback(
- const double callbackId,
- const folly::dynamic& arguments) override;
-
- virtual void setGlobalVariable(
- std::string propName,
- std::unique_ptr<const JSBigString> jsonValue) override;
-
- virtual std::string getDescription() override;
-
- virtual void* getJavaScriptContext() override;
-
- virtual bool isInspectable() override;
-
- virtual void handleMemoryPressure(int pressureLevel) override;
-
- virtual void destroy() override;
-
- void setContextName(const std::string& name);
-
-private:
- JSGlobalContextRef m_context;
- std::shared_ptr<ExecutorDelegate> m_delegate;
- std::shared_ptr<bool> m_isDestroyed = std::shared_ptr<bool>(new bool(false));
- std::shared_ptr<MessageQueueThread> m_messageQueueThread;
- std::unique_ptr<RAMBundleRegistry> m_bundleRegistry;
- JSCNativeModules m_nativeModules;
- folly::dynamic m_jscConfig;
- std::once_flag m_bindFlag;
-
- folly::Optional<Object> m_invokeCallbackAndReturnFlushedQueueJS;
- folly::Optional<Object> m_callFunctionReturnFlushedQueueJS;
- folly::Optional<Object> m_flushedQueueJS;
- folly::Optional<Object> m_callFunctionReturnResultAndFlushedQueueJS;
-
- void initOnJSVMThread() throw(JSException);
- static bool isNetworkInspected(const std::string &owner, const std::string &app, const std::string &device);
- void terminateOnJSVMThread();
- void bindBridge() throw(JSException);
- void callNativeModules(Value&&);
- void flush();
- void flushQueueImmediate(Value&&);
- void loadModule(uint32_t bundleId, uint32_t moduleId);
-
- String adoptString(std::unique_ptr<const JSBigString>);
-
- template<JSValueRef (JSCExecutor::*method)(size_t, const JSValueRef[])>
- void installNativeHook(const char* name);
-
- JSValueRef getNativeModule(JSObjectRef object, JSStringRef propertyName);
-
- JSValueRef nativeRequire(
- size_t argumentCount,
- const JSValueRef arguments[]);
- JSValueRef nativeFlushQueueImmediate(
- size_t argumentCount,
- const JSValueRef arguments[]);
- JSValueRef nativeCallSyncHook(
- size_t argumentCount,
- const JSValueRef arguments[]);
-};
-
-} }

ReactCommon/cxxreact/JSCLegacyTracing.cpp

@@ -1,73 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#include "JSCLegacyTracing.h"
-
-#if defined(WITH_JSC_EXTRA_TRACING)
-
-#include <fbsystrace.h>
-#include <JavaScriptCore/API/JSProfilerPrivate.h>
-#include <jschelpers/JSCHelpers.h>
-#include <jschelpers/Value.h>
-
-static const char *ENABLED_FBSYSTRACE_PROFILE_NAME = "__fbsystrace__";
-
-using namespace facebook::react;
-
-static int64_t int64FromJSValue(JSContextRef ctx, JSValueRef value, JSValueRef* exception) {
- return static_cast<int64_t>(JSC_JSValueToNumber(ctx, value, exception));
-}
-
-static JSValueRef nativeTraceBeginLegacy(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- if (FBSYSTRACE_LIKELY(argumentCount >= 1)) {
- uint64_t tag = int64FromJSValue(ctx, arguments[0], exception);
- if (!fbsystrace_is_tracing(tag)) {
- return Value::makeUndefined(ctx);
- }
- }
-
- JSStartProfiling(ctx, String(ctx, ENABLED_FBSYSTRACE_PROFILE_NAME), true);
-
- return Value::makeUndefined(ctx);
-}
-
-static JSValueRef nativeTraceEndLegacy(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- if (FBSYSTRACE_LIKELY(argumentCount >= 1)) {
- uint64_t tag = int64FromJSValue(ctx, arguments[0], exception);
- if (!fbsystrace_is_tracing(tag)) {
- return Value::makeUndefined(ctx);
- }
- }
-
- JSEndProfiling(ctx, String(ctx, ENABLED_FBSYSTRACE_PROFILE_NAME));
-
- return Value::makeUndefined(ctx);
-}
-
-#endif
-
-namespace facebook {
-namespace react {
-
-void addNativeTracingLegacyHooks(JSGlobalContextRef ctx) {
-#if defined(WITH_JSC_EXTRA_TRACING)
- installGlobalFunction(ctx, "nativeTraceBeginLegacy", nativeTraceBeginLegacy);
- installGlobalFunction(ctx, "nativeTraceEndLegacy", nativeTraceEndLegacy);
-#endif
-}
-
-} }

ReactCommon/cxxreact/JSCLegacyTracing.h

@@ -1,15 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#pragma once
-
-#include <jschelpers/JavaScriptCore.h>
-
-namespace facebook {
-namespace react {
-
-void addNativeTracingLegacyHooks(JSGlobalContextRef ctx);
-
-} }

ReactCommon/cxxreact/JSCMemory.cpp

@@ -1,50 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#include "JSCMemory.h"
-
-#ifdef WITH_FB_MEMORY_PROFILING
-
-#include <stdio.h>
-#include <string.h>
-#include <JavaScriptCore/API/JSProfilerPrivate.h>
-#include <jschelpers/JSCHelpers.h>
-#include <jschelpers/Value.h>
-
-using namespace facebook::react;
-
-static JSValueRef nativeCaptureHeap(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- if (argumentCount < 1) {
- if (exception) {
- *exception = Value::makeError(
- ctx,
- "nativeCaptureHeap requires the path to save the capture");
- }
- return Value::makeUndefined(ctx);
- }
-
- auto outputFilename = Value(ctx, arguments[0]).toString();
- JSCaptureHeap(ctx, outputFilename.str().c_str(), exception);
- return Value::makeUndefined(ctx);
-}
-
-#endif // WITH_FB_MEMORY_PROFILING
-
-namespace facebook {
-namespace react {
-
-void addJSCMemoryHooks(JSGlobalContextRef ctx) {
-#ifdef WITH_FB_MEMORY_PROFILING
- installGlobalFunction(ctx, "nativeCaptureHeap", nativeCaptureHeap);
-#endif // WITH_FB_MEMORY_PROFILING
-}
-
-} }

ReactCommon/cxxreact/JSCMemory.h

@@ -1,15 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#pragma once
-
-#include <jschelpers/JavaScriptCore.h>
-
-namespace facebook {
-namespace react {
-
-void addJSCMemoryHooks(JSGlobalContextRef ctx);
-
-} }

ReactCommon/cxxreact/JSCNativeModules.cpp

@@ -1,76 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#include "JSCNativeModules.h"
-
-#include <string>
-
-#include "ModuleRegistry.h"
-#include "ReactMarker.h"
-
-namespace facebook {
-namespace react {
-
-JSCNativeModules::JSCNativeModules(std::shared_ptr<ModuleRegistry> moduleRegistry) :
- m_moduleRegistry(std::move(moduleRegistry)) {}
-
-JSValueRef JSCNativeModules::getModule(JSContextRef context, JSStringRef jsName) {
- if (!m_moduleRegistry) {
- return nullptr;
- }
-
- std::string moduleName = String::ref(context, jsName).str();
-
- const auto it = m_objects.find(moduleName);
- if (it != m_objects.end()) {
- return static_cast<JSObjectRef>(it->second);
- }
-
- auto module = createModule(moduleName, context);
- if (!module.hasValue()) {
- // Allow lookup to continue in the objects own properties, which allows for overrides of NativeModules
- return nullptr;
- }
-
- // Protect since we'll be holding on to this value, even though JS may not
- module->makeProtected();
-
- auto result = m_objects.emplace(std::move(moduleName), std::move(*module)).first;
- return static_cast<JSObjectRef>(result->second);
-}
-
-void JSCNativeModules::reset() {
- m_genNativeModuleJS = nullptr;
- m_objects.clear();
-}
-
-folly::Optional<Object> JSCNativeModules::createModule(const std::string& name, JSContextRef context) {
- ReactMarker::logTaggedMarker(ReactMarker::NATIVE_MODULE_SETUP_START, name.c_str());
-
- if (!m_genNativeModuleJS) {
- auto global = Object::getGlobalObject(context);
- m_genNativeModuleJS = global.getProperty("__fbGenNativeModule").asObject();
- m_genNativeModuleJS->makeProtected();
- }
-
- auto result = m_moduleRegistry->getConfig(name);
- if (!result.hasValue()) {
- return nullptr;
- }
-
- Value moduleInfo = m_genNativeModuleJS->callAsFunction({
- Value::fromDynamic(context, result->config),
- Value::makeNumber(context, result->index)
- });
- CHECK(!moduleInfo.isNull()) << "Module returned from genNativeModule is null";
-
- folly::Optional<Object> module(moduleInfo.asObject().getProperty("module").asObject());
-
- ReactMarker::logTaggedMarker(ReactMarker::NATIVE_MODULE_SETUP_STOP, name.c_str());
-
- return module;
-}
-
-} }

ReactCommon/cxxreact/JSCNativeModules.h

@@ -1,38 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#pragma once
-
-#include <memory>
-#include <string>
-
-#include <folly/Optional.h>
-#include <jschelpers/Value.h>
-
-namespace facebook {
-namespace react {
-
-class ModuleRegistry;
-
-/**
- * Holds and creates JS representations of the modules in ModuleRegistry
- */
-class JSCNativeModules {
-
-public:
- explicit JSCNativeModules(std::shared_ptr<ModuleRegistry> moduleRegistry);
- JSValueRef getModule(JSContextRef context, JSStringRef name);
- void reset();
-
-private:
- folly::Optional<Object> m_genNativeModuleJS;
- std::shared_ptr<ModuleRegistry> m_moduleRegistry;
- std::unordered_map<std::string, Object> m_objects;
-
- folly::Optional<Object> createModule(const std::string& name, JSContextRef context);
-};
-
-}
-}

ReactCommon/cxxreact/JSCPerfStats.cpp

@@ -1,98 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#include "JSCPerfStats.h"
-
-#ifdef JSC_HAS_PERF_STATS_API
-
-#include <cstdint>
-
-#include <sys/time.h>
-#include <sys/resource.h>
-
-#include <JavaScriptCore/JSPerfStats.h>
-#include <jschelpers/JSCHelpers.h>
-#include <jschelpers/Value.h>
-
-using namespace facebook::react;
-
-static uint64_t toMillis(struct timeval tv) {
- return tv.tv_sec * 1000ULL + tv.tv_usec / 1000ULL;
-}
-
-static JSValueRef nativeGetProcessPerfStats(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- struct rusage usage{};
- if (getrusage(RUSAGE_SELF, &usage) != 0) {
- return Value::makeUndefined(ctx);
- }
-
- auto result = Object::create(ctx);
- uint64_t cpu_time_ms = toMillis(usage.ru_utime) + toMillis(usage.ru_stime);
- result.setProperty("major_faults", Value::makeNumber(ctx, usage.ru_majflt));
- result.setProperty("minor_faults", Value::makeNumber(ctx, usage.ru_minflt));
- result.setProperty("cpu_time_ms", Value::makeNumber(ctx, cpu_time_ms));
- result.setProperty("input_blocks", Value::makeNumber(ctx, usage.ru_inblock));
- result.setProperty("output_blocks", Value::makeNumber(ctx, usage.ru_oublock));
- return static_cast<JSObjectRef>(result);
-}
-
-static JSValueRef nativeGetHeapStats(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- JSHeapStats heapStats = {0};
- JSGetHeapStats(ctx, &heapStats);
-
- auto result = Object::create(ctx);
- result.setProperty("size", Value::makeNumber(ctx, heapStats.size));
- result.setProperty("extra_size", Value::makeNumber(ctx, heapStats.extraSize));
- result.setProperty("capacity", Value::makeNumber(ctx, heapStats.capacity));
- result.setProperty("object_count", Value::makeNumber(ctx, heapStats.objectCount));
- result.setProperty("object_size", Value::makeNumber(ctx, heapStats.objectSizeAfterLastCollect));
- result.setProperty("object_capacity", Value::makeNumber(ctx, heapStats.objectCapacityAfterLastCollect));
- result.setProperty("block_size", Value::makeNumber(ctx, heapStats.blockSize));
- result.setProperty("malloc_size", Value::makeNumber(ctx, heapStats.mallocSize));
- return static_cast<JSObjectRef>(result);
-}
-
-static JSValueRef nativeGetGCStats(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- JSGCStats gcStats = {0};
- JSGetGCStats(ctx, &gcStats);
-
- auto result = Object::create(ctx);
- result.setProperty("last_full_gc_length", Value::makeNumber(ctx, gcStats.lastFullGCLength));
- result.setProperty("last_eden_gc_length", Value::makeNumber(ctx, gcStats.lastEdenGCLength));
- return static_cast<JSObjectRef>(result);
-}
-
-#endif
-
-namespace facebook {
-namespace react {
-
-void addJSCPerfStatsHooks(JSGlobalContextRef ctx) {
-#ifdef JSC_HAS_PERF_STATS_API
- installGlobalFunction(ctx, "nativeGetProcessPerfStats", nativeGetProcessPerfStats);
- installGlobalFunction(ctx, "nativeGetHeapStats", nativeGetHeapStats);
- installGlobalFunction(ctx, "nativeGetGCStats", nativeGetGCStats);
-#endif
-}
-
-} }

ReactCommon/cxxreact/JSCPerfStats.h

@@ -1,15 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#pragma once
-
-#include <jschelpers/JavaScriptCore.h>
-
-namespace facebook {
-namespace react {
-
-void addJSCPerfStatsHooks(JSGlobalContextRef ctx);
-
-} }

ReactCommon/cxxreact/JSCSamplingProfiler.cpp

@@ -1,31 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#include "JSCSamplingProfiler.h"
-
-#include <jschelpers/JSCHelpers.h>
-
-static JSValueRef pokeSamplingProfiler(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- return JSC_JSPokeSamplingProfiler(ctx);
-}
-
-namespace facebook {
-namespace react {
-
-void initSamplingProfilerOnMainJSCThread(JSGlobalContextRef ctx) {
- JSC_JSStartSamplingProfilingOnMainJSCThread(ctx);
-
- // Allow the profiler to be poked from JS as well
- // (see SamplingProfiler.js for an example of how it could be used with the JSCSamplingProfiler module).
- installGlobalFunction(ctx, "pokeSamplingProfiler", pokeSamplingProfiler);
-}
-
-} }

ReactCommon/cxxreact/JSCSamplingProfiler.h

@@ -1,15 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#pragma once
-
-#include <jschelpers/JavaScriptCore.h>
-
-namespace facebook {
-namespace react {
-
-void initSamplingProfilerOnMainJSCThread(JSGlobalContextRef ctx);
-
-} }

ReactCommon/cxxreact/JSCTracing.cpp

@@ -1,323 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#include "JSCTracing.h"
-
-#if defined(WITH_FBSYSTRACE) && (defined(WITH_JSC_EXTRA_TRACING) || DEBUG)
-#define USE_JSCTRACING 1
-#else
-#define USE_JSCTRACING 0
-#endif
-
-#if USE_JSCTRACING
-
-#include <algorithm>
-#include <fbsystrace.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <jschelpers/JavaScriptCore.h>
-#include <jschelpers/JSCHelpers.h>
-#include <jschelpers/Value.h>
-
-using std::min;
-using namespace facebook::react;
-
-static int64_t int64FromJSValue(JSContextRef ctx, JSValueRef value, JSValueRef* exception) {
- return static_cast<int64_t>(JSC_JSValueToNumber(ctx, value, exception));
-}
-
-static size_t copyTruncatedAsciiChars(
- char* buf,
- size_t bufLen,
- JSContextRef ctx,
- JSValueRef value,
- size_t maxLen) {
- JSStringRef jsString = JSC_JSValueToStringCopy(ctx, value, NULL);
- size_t stringLen = JSC_JSStringGetLength(ctx, jsString);
- // Unlike the Java version, we truncate from the end of the string,
- // rather than the beginning.
- size_t toWrite = min(stringLen, min(bufLen, maxLen));
-
- const char *startBuf = buf;
- const JSChar* chars = JSC_JSStringGetCharactersPtr(ctx, jsString);
- while (toWrite-- > 0) {
- *(buf++) = (char)*(chars++);
- }
-
- JSC_JSStringRelease(ctx, jsString);
-
- // Return the number of bytes written
- return buf - startBuf;
-}
-
-static size_t copyArgsToBuffer(
- char* buf,
- size_t bufLen,
- size_t pos,
- JSContextRef ctx,
- size_t argumentCount,
- const JSValueRef arguments[]) {
- char separator = '|';
- for (
- size_t idx = 0;
- idx + 1 < argumentCount; // Make sure key and value are present.
- idx += 2) {
- JSValueRef key = arguments[idx];
- JSValueRef value = arguments[idx+1];
-
- buf[pos++] = separator;
- separator = ';';
- if (FBSYSTRACE_UNLIKELY(pos >= bufLen)) { break; }
- pos += copyTruncatedAsciiChars(
- buf + pos, bufLen - pos, ctx, key, FBSYSTRACE_MAX_MESSAGE_LENGTH);
- if (FBSYSTRACE_UNLIKELY(pos >= bufLen)) { break; }
- buf[pos++] = '=';
- if (FBSYSTRACE_UNLIKELY(pos >= bufLen)) { break; }
- pos += copyTruncatedAsciiChars(
- buf + pos, bufLen - pos, ctx, value, FBSYSTRACE_MAX_MESSAGE_LENGTH);
- if (FBSYSTRACE_UNLIKELY(pos >= bufLen)) { break; }
- }
- return pos;
-}
-
-static JSValueRef nativeTraceBeginSection(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- if (FBSYSTRACE_UNLIKELY(argumentCount < 2)) {
- if (exception) {
- *exception = Value::makeError(
- ctx,
- "nativeTraceBeginSection: requires at least 2 arguments");
- }
- return Value::makeUndefined(ctx);
- }
-
- uint64_t tag = int64FromJSValue(ctx, arguments[0], exception);
- if (!fbsystrace_is_tracing(tag)) {
- return Value::makeUndefined(ctx);
- }
-
- char buf[FBSYSTRACE_MAX_MESSAGE_LENGTH];
- size_t pos = 0;
-
- pos += snprintf(buf + pos, sizeof(buf) - pos, "B|%d|", getpid());
- // Skip the overflow check here because the int will be small.
- pos += copyTruncatedAsciiChars(buf + pos, sizeof(buf) - pos, ctx, arguments[1], FBSYSTRACE_MAX_SECTION_NAME_LENGTH);
- // Skip the overflow check here because the section name will be small-ish.
-
- pos = copyArgsToBuffer(buf, sizeof(buf), pos, ctx, argumentCount - 2, arguments + 2);
- if (FBSYSTRACE_UNLIKELY(pos >= sizeof(buf))) {
- goto flush;
- }
-
-flush:
- fbsystrace_trace_raw(buf, min(pos, sizeof(buf)-1));
-
- return Value::makeUndefined(ctx);
-}
-
-static JSValueRef nativeTraceEndSection(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- if (FBSYSTRACE_UNLIKELY(argumentCount < 1)) {
- if (exception) {
- *exception = Value::makeError(
- ctx,
- "nativeTraceEndSection: requires at least 1 argument");
- }
- return Value::makeUndefined(ctx);
- }
-
- uint64_t tag = int64FromJSValue(ctx, arguments[0], exception);
- if (!fbsystrace_is_tracing(tag)) {
- return Value::makeUndefined(ctx);
- }
-
- if (FBSYSTRACE_LIKELY(argumentCount == 1)) {
- fbsystrace_end_section(tag);
- } else {
- char buf[FBSYSTRACE_MAX_MESSAGE_LENGTH];
- size_t pos = 0;
-
- buf[pos++] = 'E';
- buf[pos++] = '|';
- buf[pos++] = '|';
- pos = copyArgsToBuffer(buf, sizeof(buf), pos, ctx, argumentCount - 1, arguments + 1);
- if (FBSYSTRACE_UNLIKELY(pos >= sizeof(buf))) {
- goto flush;
- }
-
-flush:
- fbsystrace_trace_raw(buf, min(pos, sizeof(buf)-1));
- }
-
- return Value::makeUndefined(ctx);
-}
-
-static JSValueRef beginOrEndAsync(
- bool isEnd,
- bool isFlow,
- JSContextRef ctx,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- if (FBSYSTRACE_UNLIKELY(argumentCount < 3)) {
- if (exception) {
- *exception = Value::makeError(
- ctx,
- "beginOrEndAsync: requires at least 3 arguments");
- }
- return Value::makeUndefined(ctx);
- }
-
- uint64_t tag = int64FromJSValue(ctx, arguments[0], exception);
- if (!fbsystrace_is_tracing(tag)) {
- return Value::makeUndefined(ctx);
- }
-
- char buf[FBSYSTRACE_MAX_MESSAGE_LENGTH];
- size_t pos = 0;
-
- // This uses an if-then-else instruction in ARMv7, which should be cheaper
- // than a full branch.
- buf[pos++] = ((isFlow) ? (isEnd ? 'f' : 's') : (isEnd ? 'F' : 'S'));
- pos += snprintf(buf + pos, sizeof(buf) - pos, "|%d|", getpid());
- // Skip the overflow check here because the int will be small.
- pos += copyTruncatedAsciiChars(buf + pos, sizeof(buf) - pos, ctx, arguments[1], FBSYSTRACE_MAX_SECTION_NAME_LENGTH);
- // Skip the overflow check here because the section name will be small-ish.
-
- // I tried some trickery to avoid a branch here, but gcc did not cooperate.
- // We could consider changing the implementation to be lest branchy in the
- // future.
- // This is not required for flow use an or to avoid introducing another branch
- if (!(isEnd | isFlow)) {
- buf[pos++] = '<';
- buf[pos++] = '0';
- buf[pos++] = '>';
- }
- buf[pos++] = '|';
-
- // Append the cookie. It should be an integer, but copyTruncatedAsciiChars
- // will automatically convert it to a string. We might be able to get more
- // performance by just getting the number and doing to string
- // conversion ourselves. We truncate to FBSYSTRACE_MAX_SECTION_NAME_LENGTH
- // just to make sure we can avoid the overflow check even if the caller
- // passes in something bad.
- pos += copyTruncatedAsciiChars(buf + pos, sizeof(buf) - pos, ctx, arguments[2], FBSYSTRACE_MAX_SECTION_NAME_LENGTH);
-
- pos = copyArgsToBuffer(buf, sizeof(buf), pos, ctx, argumentCount - 3, arguments + 3);
- if (FBSYSTRACE_UNLIKELY(pos >= sizeof(buf))) {
- goto flush;
- }
-
-flush:
- fbsystrace_trace_raw(buf, min(pos, sizeof(buf)-1));
-
- return Value::makeUndefined(ctx);
-}
-
-static JSValueRef nativeTraceBeginAsyncSection(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- return beginOrEndAsync(false /* isEnd */, false /* isFlow */,
- ctx, argumentCount, arguments, exception);
-}
-
-static JSValueRef nativeTraceEndAsyncSection(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- return beginOrEndAsync(true /* isEnd */, false /* isFlow */,
- ctx, argumentCount, arguments, exception);
-}
-
-static JSValueRef nativeTraceBeginAsyncFlow(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- return beginOrEndAsync(false /* isEnd */, true /* isFlow */,
- ctx, argumentCount, arguments, exception);
-}
-
-static JSValueRef nativeTraceEndAsyncFlow(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- return beginOrEndAsync(true /* isEnd */, true /* isFlow */,
- ctx, argumentCount, arguments, exception);
-}
-
-static JSValueRef nativeTraceCounter(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- if (FBSYSTRACE_UNLIKELY(argumentCount < 3)) {
- if (exception) {
- *exception = Value::makeError(
- ctx,
- "nativeTraceCounter: requires at least 3 arguments");
- }
- return Value::makeUndefined(ctx);
- }
-
- uint64_t tag = int64FromJSValue(ctx, arguments[0], exception);
- if (!fbsystrace_is_tracing(tag)) {
- return Value::makeUndefined(ctx);
- }
-
- char buf[FBSYSTRACE_MAX_MESSAGE_LENGTH];
- size_t len = copyTruncatedAsciiChars(buf, sizeof(buf), ctx,
- arguments[1], FBSYSTRACE_MAX_SECTION_NAME_LENGTH);
- buf[min(len,(FBSYSTRACE_MAX_MESSAGE_LENGTH-1))] = 0;
- int64_t value = int64FromJSValue(ctx, arguments[2], exception);
-
- fbsystrace_counter(tag, buf, value);
-
- return Value::makeUndefined(ctx);
-}
-
-#endif
-
-namespace facebook {
-namespace react {
-
-void addNativeTracingHooks(JSGlobalContextRef ctx) {
-#if USE_JSCTRACING
- installGlobalFunction(ctx, "nativeTraceBeginSection", nativeTraceBeginSection);
- installGlobalFunction(ctx, "nativeTraceEndSection", nativeTraceEndSection);
- installGlobalFunction(ctx, "nativeTraceBeginAsyncSection", nativeTraceBeginAsyncSection);
- installGlobalFunction(ctx, "nativeTraceEndAsyncSection", nativeTraceEndAsyncSection);
- installGlobalFunction(ctx, "nativeTraceBeginAsyncFlow", nativeTraceBeginAsyncFlow);
- installGlobalFunction(ctx, "nativeTraceEndAsyncFlow", nativeTraceEndAsyncFlow);
- installGlobalFunction(ctx, "nativeTraceCounter", nativeTraceCounter);
-#endif
-}
-
-} }

ReactCommon/cxxreact/JSCTracing.h

@@ -1,15 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#pragma once
-
-#include <jschelpers/JavaScriptCore.h>
-
-namespace facebook {
-namespace react {
-
-void addNativeTracingHooks(JSGlobalContextRef ctx);
-
-} }

ReactCommon/cxxreact/JSCUtils.cpp

@@ -1,24 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#include "JSCUtils.h"
-
-#include "RAMBundleRegistry.h"
-
-#include <folly/Conv.h>
-
-namespace facebook {
-namespace react {
-
-String jsStringFromBigString(JSContextRef ctx, const JSBigString& bigstr) {
- if (bigstr.isAscii()) {
- return String::createExpectingAscii(ctx, bigstr.c_str(), bigstr.size());
- } else {
- return String(ctx, bigstr.c_str());
- }
-}
-
-}
-}

ReactCommon/cxxreact/JSCUtils.h

@@ -1,18 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#pragma once
-
-#include <cxxreact/JSBigString.h>
-#include <jschelpers/JavaScriptCore.h>
-#include <jschelpers/Value.h>
-
-namespace facebook {
-namespace react {
-
-String jsStringFromBigString(JSContextRef ctx, const JSBigString& bigstr);
-
-}
-}

ReactCommon/cxxreact/JSDeltaBundleClient.cpp

@@ -1,3 +1,8 @@
+// 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.
+
#include "JSDeltaBundleClient.h"
#include <sstream>
@@ -13,9 +18,7 @@
for (auto section : {pre, post}) {
if (section != nullptr) {
- for (folly::dynamic pair : *section) {
- startupCode << pair[1].getString() << '\n';
- }
+ startupCode << section->getString() << '\n';
}
}
@@ -23,31 +26,55 @@
}
} // namespace
+void JSDeltaBundleClient::patchModules(const folly::dynamic *modules) {
+ for (const folly::dynamic pair : *modules) {
+ auto id = pair[0].getInt();
+ auto module = pair[1];
+ modules_[id] = std::move(module.getString());
+ }
+}
+
void JSDeltaBundleClient::patch(const folly::dynamic& delta) {
- auto const reset = delta.get_ptr("reset");
- if (reset != nullptr && reset->asBool()) {
+ auto const base = delta.get_ptr("base");
+
+ if (base != nullptr && base->asBool()) {
clear();
- }
auto const pre = delta.get_ptr("pre");
auto const post = delta.get_ptr("post");
- if ((pre != nullptr && pre->size() > 0) || (post != nullptr && post->size() > 0)) {
startupCode_ = startupCode(pre, post);
- }
- const folly::dynamic *modules = delta.get_ptr("delta");
+ const folly::dynamic *modules = delta.get_ptr("modules");
if (modules != nullptr) {
- for (const folly::dynamic pair : *modules) {
- auto id = pair[0].getInt();
- auto module = pair[1];
- if (module.isNull()) {
- modules_.erase(id);
+ patchModules(modules);
+ }
} else {
- modules_.emplace(id, module.getString());
+ const folly::dynamic *deleted = delta.get_ptr("deleted");
+ if (deleted != nullptr) {
+ for (const folly::dynamic id : *deleted) {
+ modules_.erase(id.getInt());
}
}
+
+ // TODO T37123645 This is deprecated but necessary in order to support older
+ // versions of the Metro server.
+ const folly::dynamic *modules = delta.get_ptr("modules");
+ if (modules != nullptr) {
+ patchModules(modules);
}
+
+ const folly::dynamic *added = delta.get_ptr("added");
+ if (added != nullptr) {
+ patchModules(added);
+ }
+
+ const folly::dynamic *modified = delta.get_ptr("modified");
+ if (modified != nullptr) {
+ patchModules(modified);
+ }
+ }
+
}
JSModulesUnbundle::Module JSDeltaBundleClient::getModule(uint32_t moduleId) const {

ReactCommon/cxxreact/JSDeltaBundleClient.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -27,6 +27,8 @@
private:
std::unordered_map<uint32_t, std::string> modules_;
std::string startupCode_;
+
+ void patchModules(const folly::dynamic *delta);
};
class JSDeltaBundleClientRAMBundle : public JSModulesUnbundle {

ReactCommon/cxxreact/JSExecutor.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactCommon/cxxreact/JSExecutor.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -82,8 +82,7 @@
*/
virtual void invokeCallback(const double callbackId, const folly::dynamic& arguments) = 0;
- virtual void setGlobalVariable(std::string propName,
- std::unique_ptr<const JSBigString> jsonValue) = 0;
+ virtual void setGlobalVariable(std::string propName, std::unique_ptr<const JSBigString> jsonValue) = 0;
virtual void* getJavaScriptContext() {
return nullptr;

ReactCommon/cxxreact/JSIndexedRAMBundle.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactCommon/cxxreact/JSIndexedRAMBundle.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactCommon/cxxreact/JSModulesUnbundle.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactCommon/cxxreact/MessageQueueThread.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactCommon/cxxreact/MethodCall.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -18,7 +18,7 @@
static const char *errorPrefix = "Malformed calls from JS: ";
-std::vector<MethodCall> parseMethodCalls(folly::dynamic&& jsonData) throw(std::invalid_argument) {
+std::vector<MethodCall> parseMethodCalls(folly::dynamic&& jsonData) {
if (jsonData.isNull()) {
return {};
}

ReactCommon/cxxreact/MethodCall.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -27,6 +27,7 @@
, callId(cid) {}
};
-std::vector<MethodCall> parseMethodCalls(folly::dynamic&& calls) throw(std::invalid_argument);
+/// \throws std::invalid_argument
+std::vector<MethodCall> parseMethodCalls(folly::dynamic&& calls);
} }

ReactCommon/cxxreact/ModuleRegistry.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -90,13 +90,13 @@
if (it == modulesByName_.end()) {
if (unknownModules_.find(name) != unknownModules_.end()) {
- return nullptr;
+ return folly::none;
}
if (!moduleNotFoundCallback_ ||
!moduleNotFoundCallback_(name) ||
(it = modulesByName_.find(name)) == modulesByName_.end()) {
unknownModules_.insert(name);
- return nullptr;
+ return folly::none;
}
}
size_t index = it->second;
@@ -143,7 +143,7 @@
if (config.size() == 2 && config[1].empty()) {
// no constants or methods
- return nullptr;
+ return folly::none;
} else {
return ModuleConfig{index, config};
}

ReactCommon/cxxreact/ModuleRegistry.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactCommon/cxxreact/NativeModule.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactCommon/cxxreact/NativeToJsBridge.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -38,6 +38,10 @@
return m_registry;
}
+ bool isBatchActive() {
+ return m_batchHadNativeModuleCalls;
+ }
+
void callNativeModules(
JSExecutor& executor, folly::dynamic&& calls, bool isEndOfBatch) override {
@@ -223,6 +228,10 @@
return m_executor->isInspectable();
}
+bool NativeToJsBridge::isBatchActive() {
+ return m_delegate->isBatchActive();
+}
+
void NativeToJsBridge::handleMemoryPressure(int pressureLevel) {
runOnExecutorQueue([=] (JSExecutor* executor) {
executor->handleMemoryPressure(pressureLevel);

ReactCommon/cxxreact/NativeToJsBridge.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -75,6 +75,7 @@
void setGlobalVariable(std::string propName, std::unique_ptr<const JSBigString> jsonValue);
void* getJavaScriptContext();
bool isInspectable();
+ bool isBatchActive();
void handleMemoryPressure(int pressureLevel);

ReactCommon/cxxreact/Platform.cpp

@@ -1,28 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#include "Platform.h"
-
-namespace facebook {
-namespace react {
-
-#if __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wglobal-constructors"
-#endif
-
-namespace JSCNativeHooks {
-
-Hook loggingHook = nullptr;
-Hook nowHook = nullptr;
-ConfigurationHook installPerfHooks = nullptr;
-
-}
-
-#if __clang__
-#pragma clang diagnostic pop
-#endif
-
-} }

ReactCommon/cxxreact/Platform.h

@@ -1,39 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#pragma once
-
-#include <functional>
-#include <memory>
-#include <string>
-
-#include <cxxreact/ReactMarker.h>
-#include <jschelpers/JavaScriptCore.h>
-
-#ifndef RN_EXPORT
-#define RN_EXPORT __attribute__((visibility("default")))
-#endif
-
-namespace facebook {
-namespace react {
-
-namespace JSCNativeHooks {
-
-using Hook = JSValueRef(*)(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef *exception);
-extern RN_EXPORT Hook loggingHook;
-extern RN_EXPORT Hook nowHook;
-
-typedef void(*ConfigurationHook)(JSGlobalContextRef);
-extern RN_EXPORT ConfigurationHook installPerfHooks;
-
-}
-
-} }

ReactCommon/cxxreact/RAMBundleRegistry.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -8,8 +8,6 @@
#include <folly/Memory.h>
#include <folly/String.h>
-#include <libgen.h>
-
namespace facebook {
namespace react {

ReactCommon/cxxreact/RAMBundleRegistry.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactCommon/cxxreact/ReactMarker.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactCommon/cxxreact/ReactMarker.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactCommon/cxxreact/RecoverableError.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -23,7 +23,7 @@
: m_what { "facebook::react::Recoverable: " + what_ }
{}
- virtual const char* what() const throw() override { return m_what.c_str(); }
+ virtual const char* what() const noexcept override { return m_what.c_str(); }
/**
* runRethrowingAsRecoverable

ReactCommon/cxxreact/SampleCxxModule.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -114,6 +114,25 @@
sample_->hello();
return nullptr;
}, SyncTag),
+ Method("addIfPositiveAsPromise", [](dynamic args, Callback cb, Callback cbError) {
+ auto a = jsArgAsDouble(args, 0);
+ auto b = jsArgAsDouble(args, 1);
+ if (a < 0 || b < 0) {
+ cbError({"Negative number!"});
+ } else {
+ cb({a + b});
+ }
+ }),
+ Method("addIfPositiveAsAsync", [](dynamic args, Callback cb, Callback cbError) {
+ auto a = jsArgAsDouble(args, 0);
+ auto b = jsArgAsDouble(args, 1);
+ if (a < 0 || b < 0) {
+ cbError({"Negative number!"});
+ } else {
+ cb({a + b});
+ }
+ }, AsyncTag),
+
};
}

ReactCommon/cxxreact/SampleCxxModule.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactCommon/cxxreact/SharedProxyCxxModule.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactCommon/cxxreact/SystraceSection.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactCommon/cxxreact/tests/BUCK

@@ -1,21 +1,17 @@
load(
"//tools/build_defs/oss:rn_defs.bzl",
- "ANDROID_JSC_DEPS",
"APPLE",
- "APPLE_JSC_DEPS",
- "react_native_xplat_target",
- "jni_instrumentation_test_lib",
"fb_xplat_cxx_test",
+ "jni_instrumentation_test_lib",
+ "react_native_xplat_target",
)
TEST_SRCS = [
"RecoverableErrorTest.cpp",
+ "JSDeltaBundleClientTest.cpp",
"jsarg_helpers.cpp",
"jsbigstring.cpp",
- "jscexecutor.cpp",
- "jsclogging.cpp",
"methodcall.cpp",
- "value.cpp",
]
jni_instrumentation_test_lib(
@@ -32,10 +28,13 @@
"fbandroid//instrumentation_tests/...",
],
deps = [
- "xplat//third-party/linker_lib:android",
+ "xplat//folly:dynamic",
"xplat//third-party/gmock:gtest",
+ "xplat//third-party/linker_lib:android",
+ "xplat//third-party/linker_lib:atomic",
react_native_xplat_target("cxxreact:bridge"),
- ] + ANDROID_JSC_DEPS,
+ react_native_xplat_target("cxxreact:jsbigstring"),
+ ],
)
fb_xplat_cxx_test(
@@ -53,6 +52,6 @@
"xplat//folly:molly",
"xplat//third-party/gmock:gtest",
react_native_xplat_target("cxxreact:bridge"),
- react_native_xplat_target("jschelpers:jschelpers"),
- ] + APPLE_JSC_DEPS,
+ react_native_xplat_target("cxxreact:jsbigstring"),
+ ],
)

ReactCommon/cxxreact/tests/jsarg_helpers.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactCommon/cxxreact/tests/jsbigstring.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactCommon/cxxreact/tests/jscexecutor.cpp

@@ -1,273 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#include <gtest/gtest.h>
-#include <cxxreact/JSCExecutor.h>
-#include <cxxreact/MessageQueueThread.h>
-#include <cxxreact/MethodCall.h>
-
-using namespace facebook;
-using namespace facebook::react;
-
-
-// TODO(12340362): Fix these tests. And add checks for sizes.
-/*
-
-namespace {
-
-std::string capturedMethodCalls;
-
-struct NullDelegate : ExecutorDelegate {
- virtual void registerExecutor(std::unique_ptr<JSExecutor> executor,
- std::shared_ptr<MessageQueueThread> queue) {
- std::terminate();
- }
-
- virtual std::unique_ptr<JSExecutor> unregisterExecutor(JSExecutor& executor) {
- std::terminate();
- }
-
- virtual std::vector<std::string> moduleNames() {
- return std::vector<std::string>{};
- }
-
- virtual folly::dynamic getModuleConfig(const std::string& name) {
- std::terminate();
- }
- virtual void callNativeModules(
- JSExecutor& executor, std::string callJSON, bool isEndOfBatch) {
- // TODO: capture calljson
- std::terminate();
- }
- virtual MethodCallResult callSerializableNativeHook(
- JSExecutor& executor, unsigned int moduleId, unsigned int methodId, folly::dynamic&& args) {
- std::terminate();
- }
-};
-
-struct FakeMessageQueue : MessageQueueThread {
- virtual void runOnQueue(std::function<void()>&& runnable) {
- // This is wrong, but oh well.
- runnable();
- }
-
- virtual void runOnQueueSync(std::function<void()>&& runnable) {
- runnable();
- }
-
- virtual void quitSynchronous() {
- std::terminate();
- }
-};
-
-std::vector<MethodCall> executeForMethodCalls(
- JSCExecutor& e,
- int moduleId,
- int methodId,
- folly::dynamic args = folly::dynamic::array()) {
- e.callFunction(folly::to<std::string>(moduleId), folly::to<std::string>(methodId), std::move(args));
- return parseMethodCalls(capturedMethodCalls);
-}
-
-void loadApplicationScript(JSCExecutor& e, std::string jsText) {
- e.loadApplicationScript(std::unique_ptr<JSBigString>(new JSBigStdString(jsText)), "");
-}
-
-void setGlobalVariable(JSCExecutor& e, std::string name, std::string jsonObject) {
- e.setGlobalVariable(name, std::unique_ptr<JSBigString>(new JSBigStdString(jsonObject)));
-}
-
-}
-
-TEST(JSCExecutor, Initialize) {
- JSCExecutor executor(std::make_shared<NullDelegate>(), std::make_shared<FakeMessageQueue>(), "", folly::dynamic::object);
-}
-
-TEST(JSCExecutor, Two) {
- JSCExecutor exec1(std::make_shared<NullDelegate>(), std::make_shared<FakeMessageQueue>(), "", folly::dynamic::object);
- JSCExecutor exec2(std::make_shared<NullDelegate>(), std::make_shared<FakeMessageQueue>(), "", folly::dynamic::object);
-}
-
-TEST(JSCExecutor, CallFunction) {
- auto jsText = ""
- "var Bridge = {"
- " callFunctionReturnFlushedQueue: function (module, method, args) {"
- " return [[module + 1], [method + 1], [args]];"
- " },"
- "};"
- "function require() { return Bridge; }"
- "";
- JSCExecutor e(std::make_shared<NullDelegate>(), std::make_shared<FakeMessageQueue>(), "", folly::dynamic::object);
- loadApplicationScript(e, jsText);
- folly::dynamic args = folly::dynamic::array();
- args.push_back(true);
- args.push_back(0.4);
- args.push_back("hello, world");
- args.push_back(4.0);
- auto returnedCalls = executeForMethodCalls(e, 10, 9, args);
- ASSERT_EQ(1, returnedCalls.size());
- auto returnedCall = returnedCalls[0];
- EXPECT_EQ(11, returnedCall.moduleId);
- EXPECT_EQ(10, returnedCall.methodId);
- ASSERT_EQ(4, returnedCall.arguments.size());
- EXPECT_EQ(args[0], returnedCall.arguments[0]);
- EXPECT_EQ(args[1], returnedCall.arguments[1]);
- EXPECT_EQ(args[2], returnedCall.arguments[2]);
- EXPECT_EQ(folly::dynamic(4.0), returnedCall.arguments[3]);
-}
-
-TEST(JSCExecutor, CallFunctionWithMap) {
- auto jsText = ""
- "var Bridge = {"
- " callFunctionReturnFlushedQueue: function (module, method, args) {"
- " var s = args[0].foo + args[0].bar + args[0].baz;"
- " return [[module], [method], [[s]]];"
- " },"
- "};"
- "function require() { return Bridge; }"
- "";
- JSCExecutor e(std::make_shared<NullDelegate>(), std::make_shared<FakeMessageQueue>(), "", folly::dynamic::object);
- loadApplicationScript(e, jsText);
- folly::dynamic args = folly::dynamic::array();
- folly::dynamic map = folly::dynamic::object
- ("foo", folly::dynamic("hello"))
- ("bar", folly::dynamic(4.0))
- ("baz", folly::dynamic(true))
- ;
- args.push_back(std::move(map));
- auto returnedCalls = executeForMethodCalls(e, 10, 9, args);
- ASSERT_EQ(1, returnedCalls.size());
- auto returnedCall = returnedCalls[0];
- ASSERT_EQ(1, returnedCall.arguments.size());
- EXPECT_EQ("hello4true", returnedCall.arguments[0].getString());
-}
-
-TEST(JSCExecutor, CallFunctionReturningMap) {
- auto jsText = ""
- "var Bridge = {"
- " callFunctionReturnFlushedQueue: function (module, method, args) {"
- " var s = { foo: 4, bar: true };"
- " return [[module], [method], [[s]]];"
- " },"
- "};"
- "function require() { return Bridge; }"
- "";
- JSCExecutor e(std::make_shared<NullDelegate>(), std::make_shared<FakeMessageQueue>(), "", folly::dynamic::object);
- loadApplicationScript(e, jsText);
- auto returnedCalls = executeForMethodCalls(e, 10, 9);
- ASSERT_EQ(1, returnedCalls.size());
- auto returnedCall = returnedCalls[0];
- ASSERT_EQ(1, returnedCall.arguments.size());
- ASSERT_EQ(folly::dynamic::OBJECT, returnedCall.arguments[0].type());
- auto& returnedMap = returnedCall.arguments[0];
- auto foo = returnedMap.at("foo");
- EXPECT_EQ(folly::dynamic(4.0), foo);
- auto bar = returnedMap.at("bar");
- EXPECT_EQ(folly::dynamic(true), bar);
-}
-
-TEST(JSCExecutor, CallFunctionWithArray) {
- auto jsText = ""
- "var Bridge = {"
- " callFunctionReturnFlushedQueue: function (module, method, args) {"
- " var s = args[0][0]+ args[0][1] + args[0][2] + args[0].length;"
- " return [[module], [method], [[s]]];"
- " },"
- "};"
- "function require() { return Bridge; }"
- "";
- JSCExecutor e(std::make_shared<NullDelegate>(), std::make_shared<FakeMessageQueue>(), "", folly::dynamic::object);
- loadApplicationScript(e, jsText);
- std::vector<folly::dynamic> args;
- std::vector<folly::dynamic> array {
- folly::dynamic("hello"),
- folly::dynamic(4.0),
- folly::dynamic(true),
- };
- args.push_back(std::move(array));
- auto returnedCalls = executeForMethodCalls(e, 10, 9, args);
- ASSERT_EQ(1, returnedCalls.size());
- auto returnedCall = returnedCalls[0];
- ASSERT_EQ(1, returnedCall.arguments.size());
- EXPECT_EQ("hello4true3", returnedCall.arguments[0].getString());
-}
-
-TEST(JSCExecutor, CallFunctionReturningNumberArray) {
- auto jsText = ""
- "var Bridge = {"
- " callFunctionReturnFlushedQueue: function (module, method, args) {"
- " var s = [3, 1, 4];"
- " return [[module], [method], [[s]]];"
- " },"
- "};"
- "function require() { return Bridge; }"
- "";
- JSCExecutor e(std::make_shared<NullDelegate>(), std::make_shared<FakeMessageQueue>(), "", folly::dynamic::object);
- loadApplicationScript(e, jsText);
- auto returnedCalls = executeForMethodCalls(e, 10, 9);
- ASSERT_EQ(1, returnedCalls.size());
- auto returnedCall = returnedCalls[0];
- ASSERT_EQ(1, returnedCall.arguments.size());
- ASSERT_EQ(folly::dynamic::ARRAY, returnedCall.arguments[0].type());
-
- auto& array = returnedCall.arguments[0];
- EXPECT_EQ(3, array.size());
- EXPECT_EQ(folly::dynamic(3.0), array[0]);
- EXPECT_EQ(folly::dynamic(4.0), array[2]);
-}
-
-TEST(JSCExecutor, SetSimpleGlobalVariable) {
- auto jsText = ""
- "var Bridge = {"
- " callFunctionReturnFlushedQueue: function (module, method, args) {"
- " return [[module], [method], [[__foo]]];"
- " },"
- "};"
- "function require() { return Bridge; }"
- "";
- JSCExecutor e(std::make_shared<NullDelegate>(), std::make_shared<FakeMessageQueue>(), "", folly::dynamic::object);
- loadApplicationScript(e, jsText);
- setGlobalVariable(e, "__foo", "42");
- auto returnedCalls = executeForMethodCalls(e, 10, 9);
- ASSERT_EQ(1, returnedCalls.size());
- auto returnedCall = returnedCalls[0];
- ASSERT_EQ(1, returnedCall.arguments.size());
- ASSERT_EQ(42.0, returnedCall.arguments[0].getDouble());
-}
-
-TEST(JSCExecutor, SetObjectGlobalVariable) {
- auto jsText = ""
- "var Bridge = {"
- " callFunctionReturnFlushedQueue: function (module, method, args) {"
- " return [[module], [method], [[__foo]]];"
- " },"
- "};"
- "function require() { return Bridge; }"
- "";
- JSCExecutor e(std::make_shared<NullDelegate>(), std::make_shared<FakeMessageQueue>(), "", folly::dynamic::object);
- loadApplicationScript(e, jsText);
- auto jsonObject = ""
- "{"
- " \"foo\": \"hello\","
- " \"bar\": 4,"
- " \"baz\": true"
- "}"
- "";
- setGlobalVariable(e, "__foo", jsonObject);
- auto returnedCalls = executeForMethodCalls(e, 10, 9);
- ASSERT_EQ(1, returnedCalls.size());
- auto returnedCall = returnedCalls[0];
- ASSERT_EQ(1, returnedCall.arguments.size());
- ASSERT_EQ(folly::dynamic::OBJECT, returnedCall.arguments[0].type());
- auto& returnedMap = returnedCall.arguments[0];
- auto foo = returnedMap.at("foo");
- EXPECT_EQ(folly::dynamic("hello"), foo);
- auto bar = returnedMap.at("bar");
- EXPECT_EQ(folly::dynamic(4.0), bar);
- auto baz = returnedMap.at("baz");
- EXPECT_EQ(folly::dynamic(true), baz);
-}
-
-*/

ReactCommon/cxxreact/tests/jsclogging.cpp

@@ -1,47 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#include <gtest/gtest.h>
-#include <cxxreact/JSCExecutor.h>
-
-using namespace facebook;
-using namespace facebook::react;
-
-/*
-static const char* expectedLogMessageSubstring = NULL;
-static bool hasSeenExpectedLogMessage = false;
-
-static void mockLogHandler(int pri, const char *tag, const char *msg) {
- if (expectedLogMessageSubstring == NULL) {
- return;
- }
-
- hasSeenExpectedLogMessage |= (strstr(msg, expectedLogMessageSubstring) != NULL);
-}
-
-class JSCLoggingTest : public testing::Test {
- protected:
- virtual void SetUp() override {
- setLogHandler(&mockLogHandler);
- }
-
- virtual void TearDown() override {
- setLogHandler(NULL);
- expectedLogMessageSubstring = NULL;
- hasSeenExpectedLogMessage = false;
- }
-
-};
-
-TEST_F(JSCLoggingTest, LogException) {
- auto jsText = "throw new Error('I am a banana!');";
- expectedLogMessageSubstring = "I am a banana!";
-
- JSCExecutor e;
- e.loadApplicationScript(jsText, "");
-
- ASSERT_TRUE(hasSeenExpectedLogMessage);
-}
-*/

ReactCommon/cxxreact/tests/JSDeltaBundleClientTest.cpp

@@ -0,0 +1,131 @@
+// 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.
+
+#include <gtest/gtest.h>
+
+#include <exception>
+#include <iostream>
+#include <stdexcept>
+
+#include <cxxreact/JSDeltaBundleClient.h>
+#include <folly/dynamic.h>
+#include <folly/json.h>
+
+using namespace facebook::react;
+
+TEST(JSDeltaBundleClient, PatchStartupCode) {
+ JSDeltaBundleClient client;
+
+ folly::dynamic delta1 = folly::parseJson(R"({
+ "base": true,
+ "revisionId": "rev0",
+ "pre": "pre",
+ "post": "post",
+ "modules": [
+ [0, "0"],
+ [1, "1"]
+ ]
+ })");
+
+ client.patch(delta1);
+
+ EXPECT_STREQ(client.getStartupCode()->c_str(), "pre\npost\n");
+
+ folly::dynamic delta2 = folly::parseJson(R"({
+ "base": true,
+ "revisionId": "rev1",
+ "pre": "pre2",
+ "post": "post2",
+ "modules": []
+ })");
+
+ client.patch(delta2);
+
+ EXPECT_STREQ(client.getStartupCode()->c_str(), "pre2\npost2\n");
+}
+
+TEST(JSDeltaBundleClient, PatchModule) {
+ JSDeltaBundleClient client;
+
+ folly::dynamic delta1 = folly::parseJson(R"({
+ "base": true,
+ "revisionId": "rev0",
+ "pre": "pre",
+ "post": "post",
+ "modules": [
+ [0, "0"],
+ [1, "1"]
+ ]
+ })");
+
+ client.patch(delta1);
+
+ EXPECT_EQ(client.getModule(0).code, "0");
+ EXPECT_EQ(client.getModule(1).code, "1");
+
+ ASSERT_THROW(client.getModule(2), JSModulesUnbundle::ModuleNotFound);
+
+ folly::dynamic delta2 = folly::parseJson(R"({
+ "base": false,
+ "revisionId": "rev1",
+ "added": [
+ [2, "2"]
+ ],
+ "modified": [
+ [0, "0.1"]
+ ],
+ "deleted": [1]
+ })");
+
+ client.patch(delta2);
+
+ EXPECT_EQ(client.getModule(0).code, "0.1");
+ EXPECT_EQ(client.getModule(2).code, "2");
+ ASSERT_THROW(client.getModule(1), JSModulesUnbundle::ModuleNotFound);
+
+ folly::dynamic delta3 = folly::parseJson(R"({
+ "base": true,
+ "revisionId": "rev2",
+ "pre": "pre",
+ "post": "post",
+ "modules": [
+ [3, "3"],
+ [4, "4"]
+ ]
+ })");
+
+ client.patch(delta3);
+
+ ASSERT_THROW(client.getModule(0), JSModulesUnbundle::ModuleNotFound);
+ ASSERT_THROW(client.getModule(1), JSModulesUnbundle::ModuleNotFound);
+ ASSERT_THROW(client.getModule(2), JSModulesUnbundle::ModuleNotFound);
+
+ EXPECT_EQ(client.getModule(3).code, "3");
+ EXPECT_EQ(client.getModule(4).code, "4");
+}
+
+TEST(JSDeltaBundleClient, Clear) {
+ JSDeltaBundleClient client;
+
+ folly::dynamic delta1 = folly::parseJson(R"({
+ "base": true,
+ "revisionId": "rev0",
+ "pre": "pre",
+ "post": "post",
+ "modules": [
+ [0, "0"],
+ [1, "1"]
+ ]
+ })");
+
+ client.patch(delta1);
+
+ client.clear();
+
+ ASSERT_THROW(client.getModule(0), JSModulesUnbundle::ModuleNotFound);
+ ASSERT_THROW(client.getModule(1), JSModulesUnbundle::ModuleNotFound);
+
+ EXPECT_STREQ(client.getStartupCode()->c_str(), "");
+}

ReactCommon/cxxreact/tests/methodcall.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactCommon/cxxreact/tests/RecoverableErrorTest.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactCommon/cxxreact/tests/value.cpp

@@ -1,108 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-#include <string>
-#include <gtest/gtest.h>
-#include <folly/json.h>
-#include <jschelpers/Value.h>
-
-#ifdef WITH_FBJSCEXTENSION
-#undef ASSERT
-#include <JavaScriptCore/config.h>
-#include "OpaqueJSString.h"
-#endif
-
-#include <stdexcept>
-
-using namespace facebook::react;
-
-#ifdef ANDROID
-#include <android/looper.h>
-static void prepare() {
- ALooper_prepare(0);
-}
-#else
-static void prepare() {}
-#endif
-
-TEST(Value, Undefined) {
- prepare();
- JSGlobalContextRef ctx = JSC_JSGlobalContextCreateInGroup(false, nullptr, nullptr);
- auto v = Value::makeUndefined(ctx);
- auto s = String::adopt(ctx, JSC_JSValueToStringCopy(ctx, v, nullptr));
- EXPECT_EQ("undefined", s.str());
- JSC_JSGlobalContextRelease(ctx);
-}
-
-TEST(Value, FromJSON) {
- prepare();
- JSGlobalContextRef ctx = JSC_JSGlobalContextCreateInGroup(false, nullptr, nullptr);
- String s(ctx, "{\"a\": 4}");
- Value v(Value::fromJSON(s));
- EXPECT_TRUE(v.isObject());
- JSC_JSGlobalContextRelease(ctx);
-}
-
-TEST(Value, ToJSONString) {
- prepare();
- JSGlobalContextRef ctx = JSC_JSGlobalContextCreateInGroup(false, nullptr, nullptr);
- String s(ctx, "{\"a\": 4}");
- Value v(Value::fromJSON(s));
- folly::dynamic dyn = folly::parseJson(v.toJSONString());
- ASSERT_NE(nullptr, dyn);
- EXPECT_TRUE(dyn.isObject());
- auto val = dyn.at("a");
- ASSERT_NE(nullptr, val);
- ASSERT_TRUE(val.isNumber());
- EXPECT_EQ(4, val.asInt());
- EXPECT_EQ(4.0f, val.asDouble());
-
- JSC_JSGlobalContextRelease(ctx);
-}
-
-#ifdef WITH_FBJSCEXTENSION
-// Just test that handling invalid data doesn't crash.
-TEST(Value, FromBadUtf8) {
- prepare();
- JSGlobalContextRef ctx = JSC_JSGlobalContextCreateInGroup(false, nullptr, nullptr);
- // 110xxxxx 10xxxxxx
- auto dyn = folly::dynamic("\xC0");
- Value::fromDynamic(ctx, dyn);
- dyn = folly::dynamic("\xC0\x00");
- Value::fromDynamic(ctx, dyn);
- // 1110xxxx 10xxxxxx 10xxxxxx
- dyn = "\xE0";
- Value::fromDynamic(ctx, dyn);
- Value(ctx, Value::fromDynamic(ctx, dyn)).toJSONString();
- dyn = "\xE0\x00";
- Value::fromDynamic(ctx, dyn);
- Value(ctx, Value::fromDynamic(ctx, dyn)).toJSONString();
- dyn = "\xE0\x00\x00";
- Value::fromDynamic(ctx, dyn);
- Value(ctx, Value::fromDynamic(ctx, dyn)).toJSONString();
- dyn = "\xE0\xA0\x00";
- Value::fromDynamic(ctx, dyn);
- // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
- dyn = "\xF0";
- Value::fromDynamic(ctx, dyn);
- Value(ctx, Value::fromDynamic(ctx, dyn)).toJSONString();
- dyn = "\xF0\x00\x00\x00";
- Value::fromDynamic(ctx, dyn);
- dyn = "\xF0\x80\x80\x00";
- Value::fromDynamic(ctx, dyn);
- Value(ctx, Value::fromDynamic(ctx, dyn)).toJSONString();
- JSC_JSGlobalContextRelease(ctx);
-}
-
-// Just test that handling invalid data doesn't crash.
-TEST(Value, BadUtf16) {
- prepare();
- JSGlobalContextRef ctx = JSC_JSGlobalContextCreateInGroup(false, nullptr, nullptr);
- UChar buf[] = { 0xDD00, 0xDD00, 0xDD00, 0x1111 };
- JSStringRef ref = OpaqueJSString::create(buf, 4).leakRef();
- Value v(ctx, ref);
- v.toJSONString(0);
- JSC_JSGlobalContextRelease(ctx);
-}
-#endif

ReactCommon/fabric/attributedstring/AttributedString.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,7 +7,7 @@
#include "AttributedString.h"
-#include <fabric/debug/DebugStringConvertibleItem.h>
+#include <react/debug/DebugStringConvertibleItem.h>
namespace facebook {
namespace react {
@@ -15,6 +15,23 @@
using Fragment = AttributedString::Fragment;
using Fragments = AttributedString::Fragments;
+#pragma mark - Fragment
+
+bool Fragment::operator==(const Fragment &rhs) const {
+ return std::tie(string, textAttributes, shadowView, parentShadowView) ==
+ std::tie(
+ rhs.string,
+ rhs.textAttributes,
+ rhs.shadowView,
+ rhs.parentShadowView);
+}
+
+bool Fragment::operator!=(const Fragment &rhs) const {
+ return !(*this == rhs);
+}
+
+#pragma mark - AttributedString
+
void AttributedString::appendFragment(const Fragment &fragment) {
ensureUnsealed();
fragments_.push_back(fragment);
@@ -25,14 +42,22 @@
fragments_.insert(fragments_.begin(), fragment);
}
-void AttributedString::appendAttributedString(const AttributedString &attributedString) {
+void AttributedString::appendAttributedString(
+ const AttributedString &attributedString) {
ensureUnsealed();
- fragments_.insert(fragments_.end(), attributedString.fragments_.begin(), attributedString.fragments_.end());
+ fragments_.insert(
+ fragments_.end(),
+ attributedString.fragments_.begin(),
+ attributedString.fragments_.end());
}
-void AttributedString::prependAttributedString(const AttributedString &attributedString) {
+void AttributedString::prependAttributedString(
+ const AttributedString &attributedString) {
ensureUnsealed();
- fragments_.insert(fragments_.begin(), attributedString.fragments_.begin(), attributedString.fragments_.end());
+ fragments_.insert(
+ fragments_.begin(),
+ attributedString.fragments_.begin(),
+ attributedString.fragments_.end());
}
const std::vector<Fragment> &AttributedString::getFragments() const {
@@ -40,37 +65,41 @@
}
std::string AttributedString::getString() const {
- std::string string;
+ auto string = std::string{};
for (const auto &fragment : fragments_) {
string += fragment.string;
}
return string;
}
+bool AttributedString::operator==(const AttributedString &rhs) const {
+ return fragments_ == rhs.fragments_;
+}
+
+bool AttributedString::operator!=(const AttributedString &rhs) const {
+ return !(*this == rhs);
+}
+
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList AttributedString::getDebugChildren() const {
- SharedDebugStringConvertibleList list = {};
+ auto list = SharedDebugStringConvertibleList{};
for (auto &&fragment : fragments_) {
- auto propsList = fragment.textAttributes.DebugStringConvertible::getDebugProps();
-
- if (fragment.shadowNode) {
- propsList.push_back(std::make_shared<DebugStringConvertibleItem>("shadowNode", fragment.shadowNode->getDebugDescription()));
- }
+ auto propsList =
+ fragment.textAttributes.DebugStringConvertible::getDebugProps();
- list.push_back(
- std::make_shared<DebugStringConvertibleItem>(
+ list.push_back(std::make_shared<DebugStringConvertibleItem>(
"Fragment",
fragment.string,
SharedDebugStringConvertibleList(),
- propsList
- )
- );
+ propsList));
}
return list;
}
+#endif
} // namespace react
} // namespace facebook

ReactCommon/fabric/attributedstring/AttributedString.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,13 +7,16 @@
#pragma once
+#include <functional>
#include <memory>
-#include <fabric/attributedstring/TextAttributes.h>
-#include <fabric/core/Sealable.h>
-#include <fabric/core/ShadowNode.h>
-#include <fabric/debug/DebugStringConvertible.h>
+#include <folly/Hash.h>
#include <folly/Optional.h>
+#include <react/attributedstring/TextAttributes.h>
+#include <react/core/Sealable.h>
+#include <react/core/ShadowNode.h>
+#include <react/debug/DebugStringConvertible.h>
+#include <react/mounting/ShadowView.h>
namespace facebook {
namespace react {
@@ -28,17 +31,17 @@
* `AttributedString` is basically a list of `Fragments` which have `string` and
* `textAttributes` + `shadowNode` associated with the `string`.
*/
-class AttributedString:
- public Sealable,
- public DebugStringConvertible {
-
-public:
-
+class AttributedString : public Sealable, public DebugStringConvertible {
+ public:
class Fragment {
public:
std::string string;
TextAttributes textAttributes;
- SharedShadowNode shadowNode;
+ ShadowView shadowView;
+ ShadowView parentShadowView;
+
+ bool operator==(const Fragment &rhs) const;
+ bool operator!=(const Fragment &rhs) const;
};
using Fragments = std::vector<Fragment>;
@@ -66,14 +69,49 @@
*/
std::string getString() const;
+ bool operator==(const AttributedString &rhs) const;
+ bool operator!=(const AttributedString &rhs) const;
+
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList getDebugChildren() const override;
+#endif
-private:
-
+ private:
Fragments fragments_;
};
} // namespace react
} // namespace facebook
+
+namespace std {
+template <>
+struct hash<facebook::react::AttributedString::Fragment> {
+ size_t operator()(
+ const facebook::react::AttributedString::Fragment &fragment) const {
+ auto seed = size_t{0};
+ folly::hash::hash_combine(
+ seed,
+ fragment.string,
+ fragment.textAttributes,
+ fragment.shadowView,
+ fragment.parentShadowView);
+ return seed;
+ }
+};
+
+template <>
+struct hash<facebook::react::AttributedString> {
+ size_t operator()(
+ const facebook::react::AttributedString &attributedString) const {
+ auto seed = size_t{0};
+
+ for (const auto &fragment : attributedString.getFragments()) {
+ folly::hash::hash_combine(seed, fragment);
+ }
+
+ return seed;
+ }
+};
+} // namespace std

ReactCommon/fabric/attributedstring/BUCK

@@ -1,14 +1,14 @@
-load("//configurations/buck/apple:flag_defs.bzl", "OBJC_ARC_PREPROCESSOR_FLAGS", "get_application_ios_flags", "get_debug_preprocessor_flags")
+load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags")
load(
"//tools/build_defs/oss:rn_defs.bzl",
"ANDROID",
"APPLE",
+ "fb_xplat_cxx_test",
+ "get_apple_compiler_flags",
"get_apple_inspector_flags",
"react_native_xplat_target",
- "get_apple_compiler_flags",
- "subdir_glob",
- "fb_xplat_cxx_test",
"rn_xplat_cxx_library",
+ "subdir_glob",
)
APPLE_COMPILER_FLAGS = get_apple_compiler_flags()
@@ -28,7 +28,7 @@
[
("", "*.h"),
],
- prefix = "fabric/attributedstring",
+ prefix = "react/attributedstring",
),
compiler_flags = [
"-fexceptions",
@@ -38,9 +38,6 @@
],
fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
- fbobjc_tests = [
- ":tests",
- ],
force_static = True,
macosx_tests_override = [],
platforms = (ANDROID, APPLE),
@@ -48,7 +45,7 @@
"-DLOG_TAG=\"ReactNative\"",
"-DWITH_FBSYSTRACE=1",
],
- tests = [],
+ tests = [":tests"],
visibility = ["PUBLIC"],
deps = [
"xplat//fbsystrace:fbsystrace",
@@ -56,9 +53,11 @@
"xplat//folly:memory",
"xplat//folly:molly",
"xplat//third-party/glog:glog",
+ react_native_xplat_target("utils:utils"),
react_native_xplat_target("fabric/debug:debug"),
react_native_xplat_target("fabric/core:core"),
react_native_xplat_target("fabric/graphics:graphics"),
+ react_native_xplat_target("fabric/mounting:mounting"),
],
)
@@ -73,7 +72,7 @@
"-Wall",
],
contacts = ["oncall+react_native@xmail.facebook.com"],
- platforms = APPLE,
+ platforms = (ANDROID, APPLE),
deps = [
"xplat//folly:molly",
"xplat//third-party/gmock:gtest",

ReactCommon/fabric/attributedstring/conversions.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,45 +7,106 @@
#pragma once
-#include <fabric/attributedstring/primitives.h>
-#include <fabric/graphics/Geometry.h>
#include <folly/dynamic.h>
+#include <react/attributedstring/AttributedString.h>
+#include <react/attributedstring/ParagraphAttributes.h>
+#include <react/attributedstring/TextAttributes.h>
+#include <react/attributedstring/conversions.h>
+#include <react/attributedstring/primitives.h>
+#include <react/core/LayoutableShadowNode.h>
+#include <react/core/ShadowNode.h>
+#include <react/core/conversions.h>
+#include <react/graphics/Geometry.h>
+#include <react/graphics/conversions.h>
+#include <cmath>
namespace facebook {
namespace react {
inline std::string toString(const EllipsizeMode &ellipsisMode) {
switch (ellipsisMode) {
- case EllipsizeMode::Clip: return "clip";
- case EllipsizeMode::Head: return "head";
- case EllipsizeMode::Tail: return "tail";
- case EllipsizeMode::Middle: return "middle";
+ case EllipsizeMode::Clip:
+ return "clip";
+ case EllipsizeMode::Head:
+ return "head";
+ case EllipsizeMode::Tail:
+ return "tail";
+ case EllipsizeMode::Middle:
+ return "middle";
}
}
-inline void fromDynamic(const folly::dynamic &value, EllipsizeMode &result) {
- auto string = value.getString();
- if (string == "clip") { result = EllipsizeMode::Clip; return; }
- if (string == "head") { result = EllipsizeMode::Head; return; }
- if (string == "tail") { result = EllipsizeMode::Tail; return; }
- if (string == "middle") { result = EllipsizeMode::Middle; return; }
+inline void fromRawValue(const RawValue &value, EllipsizeMode &result) {
+ auto string = (std::string)value;
+ if (string == "clip") {
+ result = EllipsizeMode::Clip;
+ return;
+ }
+ if (string == "head") {
+ result = EllipsizeMode::Head;
+ return;
+ }
+ if (string == "tail") {
+ result = EllipsizeMode::Tail;
+ return;
+ }
+ if (string == "middle") {
+ result = EllipsizeMode::Middle;
+ return;
+ }
abort();
}
-inline void fromDynamic(const folly::dynamic &value, FontWeight &result) {
- auto string = value.asString();
- if (string == "normal") { result = FontWeight::Regular; return; }
- if (string == "regular") { result = FontWeight::Regular; return; }
- if (string == "bold") { result = FontWeight::Bold; return; }
- if (string == "100") { result = FontWeight::Weight100; return; }
- if (string == "200") { result = FontWeight::Weight200; return; }
- if (string == "300") { result = FontWeight::Weight300; return; }
- if (string == "400") { result = FontWeight::Weight400; return; }
- if (string == "500") { result = FontWeight::Weight500; return; }
- if (string == "600") { result = FontWeight::Weight600; return; }
- if (string == "700") { result = FontWeight::Weight700; return; }
- if (string == "800") { result = FontWeight::Weight800; return; }
- if (string == "900") { result = FontWeight::Weight900; return; }
+inline void fromRawValue(const RawValue &value, FontWeight &result) {
+ auto string = (std::string)value;
+ if (string == "normal") {
+ result = FontWeight::Regular;
+ return;
+ }
+ if (string == "regular") {
+ result = FontWeight::Regular;
+ return;
+ }
+ if (string == "bold") {
+ result = FontWeight::Bold;
+ return;
+ }
+ if (string == "100") {
+ result = FontWeight::Weight100;
+ return;
+ }
+ if (string == "200") {
+ result = FontWeight::Weight200;
+ return;
+ }
+ if (string == "300") {
+ result = FontWeight::Weight300;
+ return;
+ }
+ if (string == "400") {
+ result = FontWeight::Weight400;
+ return;
+ }
+ if (string == "500") {
+ result = FontWeight::Weight500;
+ return;
+ }
+ if (string == "600") {
+ result = FontWeight::Weight600;
+ return;
+ }
+ if (string == "700") {
+ result = FontWeight::Weight700;
+ return;
+ }
+ if (string == "800") {
+ result = FontWeight::Weight800;
+ return;
+ }
+ if (string == "900") {
+ result = FontWeight::Weight900;
+ return;
+ }
abort();
}
@@ -53,43 +114,80 @@
return folly::to<std::string>((int)fontWeight);
}
-inline void fromDynamic(const folly::dynamic &value, FontStyle &result) {
- auto string = value.asString();
- if (string == "normal") { result = FontStyle::Normal; return; }
- if (string == "italic") { result = FontStyle::Italic; return; }
- if (string == "oblique") { result = FontStyle::Oblique; return; }
+inline void fromRawValue(const RawValue &value, FontStyle &result) {
+ auto string = (std::string)value;
+ if (string == "normal") {
+ result = FontStyle::Normal;
+ return;
+ }
+ if (string == "italic") {
+ result = FontStyle::Italic;
+ return;
+ }
+ if (string == "oblique") {
+ result = FontStyle::Oblique;
+ return;
+ }
abort();
}
inline std::string toString(const FontStyle &fontStyle) {
switch (fontStyle) {
- case FontStyle::Normal: return "normal";
- case FontStyle::Italic: return "italic";
- case FontStyle::Oblique: return "oblique";
+ case FontStyle::Normal:
+ return "normal";
+ case FontStyle::Italic:
+ return "italic";
+ case FontStyle::Oblique:
+ return "oblique";
}
}
-inline void fromDynamic(const folly::dynamic &value, FontVariant &result) {
- assert(value.isArray());
+inline void fromRawValue(const RawValue &value, FontVariant &result) {
+ assert(value.hasType<std::vector<std::string>>());
result = FontVariant::Default;
- for (auto &&item : value) {
- auto string = item.asString();
- if (string == "small-caps") { result = (FontVariant)((int)result | (int)FontVariant::SmallCaps); continue; }
- if (string == "oldstyle-nums") { result = (FontVariant)((int)result | (int)FontVariant::OldstyleNums); continue; }
- if (string == "lining-nums") { result = (FontVariant)((int)result | (int)FontVariant::LiningNums); continue; }
- if (string == "tabular-nums") { result = (FontVariant)((int)result | (int)FontVariant::TabularNums); continue; }
- if (string == "proportional-nums") { result = (FontVariant)((int)result | (int)FontVariant::ProportionalNums); continue; }
+ auto items = std::vector<std::string>{value};
+ for (const auto &item : items) {
+ if (item == "small-caps") {
+ result = (FontVariant)((int)result | (int)FontVariant::SmallCaps);
+ continue;
+ }
+ if (item == "oldstyle-nums") {
+ result = (FontVariant)((int)result | (int)FontVariant::OldstyleNums);
+ continue;
+ }
+ if (item == "lining-nums") {
+ result = (FontVariant)((int)result | (int)FontVariant::LiningNums);
+ continue;
+ }
+ if (item == "tabular-nums") {
+ result = (FontVariant)((int)result | (int)FontVariant::TabularNums);
+ continue;
+ }
+ if (item == "proportional-nums") {
+ result = (FontVariant)((int)result | (int)FontVariant::ProportionalNums);
+ continue;
+ }
}
}
inline std::string toString(const FontVariant &fontVariant) {
- std::string result;
- std::string separator = ", ";
- if ((int)fontVariant & (int)FontVariant::SmallCaps) { result += "small-caps" + separator; }
- if ((int)fontVariant & (int)FontVariant::OldstyleNums) { result += "oldstyle-nums" + separator; }
- if ((int)fontVariant & (int)FontVariant::LiningNums) { result += "lining-nums" + separator; }
- if ((int)fontVariant & (int)FontVariant::TabularNums) { result += "tabular-nums" + separator; }
- if ((int)fontVariant & (int)FontVariant::ProportionalNums) { result += "proportional-nums" + separator; }
+ auto result = std::string{};
+ auto separator = std::string{", "};
+ if ((int)fontVariant & (int)FontVariant::SmallCaps) {
+ result += "small-caps" + separator;
+ }
+ if ((int)fontVariant & (int)FontVariant::OldstyleNums) {
+ result += "oldstyle-nums" + separator;
+ }
+ if ((int)fontVariant & (int)FontVariant::LiningNums) {
+ result += "lining-nums" + separator;
+ }
+ if ((int)fontVariant & (int)FontVariant::TabularNums) {
+ result += "tabular-nums" + separator;
+ }
+ if ((int)fontVariant & (int)FontVariant::ProportionalNums) {
+ result += "proportional-nums" + separator;
+ }
if (!result.empty()) {
result.erase(result.length() - separator.length());
@@ -98,95 +196,303 @@
return result;
}
-inline void fromDynamic(const folly::dynamic &value, TextAlignment &result) {
- auto string = value.asString();
- if (string == "natural") { result = TextAlignment::Natural; return; }
- if (string == "left") { result = TextAlignment::Left; return; }
- if (string == "center") { result = TextAlignment::Center; return; }
- if (string == "right") { result = TextAlignment::Right; return; }
- if (string == "justified") { result = TextAlignment::Justified; return; }
+inline void fromRawValue(const RawValue &value, TextAlignment &result) {
+ auto string = (std::string)value;
+ if (string == "natural") {
+ result = TextAlignment::Natural;
+ return;
+ }
+ if (string == "left") {
+ result = TextAlignment::Left;
+ return;
+ }
+ if (string == "center") {
+ result = TextAlignment::Center;
+ return;
+ }
+ if (string == "right") {
+ result = TextAlignment::Right;
+ return;
+ }
+ if (string == "justified") {
+ result = TextAlignment::Justified;
+ return;
+ }
abort();
}
inline std::string toString(const TextAlignment &textAlignment) {
switch (textAlignment) {
- case TextAlignment::Natural: return "natural";
- case TextAlignment::Left: return "left";
- case TextAlignment::Center: return "center";
- case TextAlignment::Right: return "right";
- case TextAlignment::Justified: return "justified";
+ case TextAlignment::Natural:
+ return "natural";
+ case TextAlignment::Left:
+ return "left";
+ case TextAlignment::Center:
+ return "center";
+ case TextAlignment::Right:
+ return "right";
+ case TextAlignment::Justified:
+ return "justified";
}
}
-inline void fromDynamic(const folly::dynamic &value, WritingDirection &result) {
- auto string = value.asString();
- if (string == "natural") { result = WritingDirection::Natural; return; }
- if (string == "ltr") { result = WritingDirection::LeftToRight; return; }
- if (string == "rtl") { result = WritingDirection::RightToLeft; return; }
+inline void fromRawValue(const RawValue &value, WritingDirection &result) {
+ auto string = (std::string)value;
+ if (string == "natural") {
+ result = WritingDirection::Natural;
+ return;
+ }
+ if (string == "ltr") {
+ result = WritingDirection::LeftToRight;
+ return;
+ }
+ if (string == "rtl") {
+ result = WritingDirection::RightToLeft;
+ return;
+ }
abort();
}
inline std::string toString(const WritingDirection &writingDirection) {
switch (writingDirection) {
- case WritingDirection::Natural: return "natural";
- case WritingDirection::LeftToRight: return "ltr";
- case WritingDirection::RightToLeft: return "rtl";
+ case WritingDirection::Natural:
+ return "natural";
+ case WritingDirection::LeftToRight:
+ return "ltr";
+ case WritingDirection::RightToLeft:
+ return "rtl";
}
}
-inline void fromDynamic(const folly::dynamic &value, TextDecorationLineType &result) {
- auto string = value.asString();
- if (string == "none") { result = TextDecorationLineType::None; return; }
- if (string == "underline") { result = TextDecorationLineType::Underline; return; }
- if (string == "strikethrough") { result = TextDecorationLineType::Strikethrough; return; }
- if (string == "underline-strikethrough") { result = TextDecorationLineType::UnderlineStrikethrough; return; }
+inline void fromRawValue(
+ const RawValue &value,
+ TextDecorationLineType &result) {
+ auto string = (std::string)value;
+ if (string == "none") {
+ result = TextDecorationLineType::None;
+ return;
+ }
+ if (string == "underline") {
+ result = TextDecorationLineType::Underline;
+ return;
+ }
+ if (string == "strikethrough") {
+ result = TextDecorationLineType::Strikethrough;
+ return;
+ }
+ if (string == "underline-strikethrough") {
+ result = TextDecorationLineType::UnderlineStrikethrough;
+ return;
+ }
abort();
}
-inline std::string toString(const TextDecorationLineType &textDecorationLineType) {
+inline std::string toString(
+ const TextDecorationLineType &textDecorationLineType) {
switch (textDecorationLineType) {
- case TextDecorationLineType::None: return "none";
- case TextDecorationLineType::Underline: return "underline";
- case TextDecorationLineType::Strikethrough: return "strikethrough";
- case TextDecorationLineType::UnderlineStrikethrough: return "underline-strikethrough";
+ case TextDecorationLineType::None:
+ return "none";
+ case TextDecorationLineType::Underline:
+ return "underline";
+ case TextDecorationLineType::Strikethrough:
+ return "strikethrough";
+ case TextDecorationLineType::UnderlineStrikethrough:
+ return "underline-strikethrough";
}
}
-inline void fromDynamic(const folly::dynamic &value, TextDecorationLineStyle &result) {
- auto string = value.asString();
- if (string == "single") { result = TextDecorationLineStyle::Single; return; }
- if (string == "thick") { result = TextDecorationLineStyle::Thick; return; }
- if (string == "double") { result = TextDecorationLineStyle::Double; return; }
+inline void fromRawValue(
+ const RawValue &value,
+ TextDecorationLineStyle &result) {
+ auto string = (std::string)value;
+ if (string == "single") {
+ result = TextDecorationLineStyle::Single;
+ return;
+ }
+ if (string == "thick") {
+ result = TextDecorationLineStyle::Thick;
+ return;
+ }
+ if (string == "double") {
+ result = TextDecorationLineStyle::Double;
+ return;
+ }
abort();
}
-inline std::string toString(const TextDecorationLineStyle &textDecorationLineStyle) {
+inline std::string toString(
+ const TextDecorationLineStyle &textDecorationLineStyle) {
switch (textDecorationLineStyle) {
- case TextDecorationLineStyle::Single: return "single";
- case TextDecorationLineStyle::Thick: return "thick";
- case TextDecorationLineStyle::Double: return "double";
+ case TextDecorationLineStyle::Single:
+ return "single";
+ case TextDecorationLineStyle::Thick:
+ return "thick";
+ case TextDecorationLineStyle::Double:
+ return "double";
}
}
-inline void fromDynamic(const folly::dynamic &value, TextDecorationLinePattern &result) {
- auto string = value.asString();
- if (string == "solid") { result = TextDecorationLinePattern::Solid; return; }
- if (string == "dot") { result = TextDecorationLinePattern::Dot; return; }
- if (string == "dash") { result = TextDecorationLinePattern::Dash; return; }
- if (string == "dash-dot") { result = TextDecorationLinePattern::DashDot; return; }
- if (string == "dash-dot-dot") { result = TextDecorationLinePattern::DashDotDot; return; }
+inline void fromRawValue(
+ const RawValue &value,
+ TextDecorationLinePattern &result) {
+ auto string = (std::string)value;
+ if (string == "solid") {
+ result = TextDecorationLinePattern::Solid;
+ return;
+ }
+ if (string == "dot") {
+ result = TextDecorationLinePattern::Dot;
+ return;
+ }
+ if (string == "dash") {
+ result = TextDecorationLinePattern::Dash;
+ return;
+ }
+ if (string == "dash-dot") {
+ result = TextDecorationLinePattern::DashDot;
+ return;
+ }
+ if (string == "dash-dot-dot") {
+ result = TextDecorationLinePattern::DashDotDot;
+ return;
+ }
abort();
}
-inline std::string toString(const TextDecorationLinePattern &textDecorationLinePattern) {
+inline std::string toString(
+ const TextDecorationLinePattern &textDecorationLinePattern) {
switch (textDecorationLinePattern) {
- case TextDecorationLinePattern::Solid: return "solid";
- case TextDecorationLinePattern::Dot: return "dot";
- case TextDecorationLinePattern::Dash: return "dash";
- case TextDecorationLinePattern::DashDot: return "dash-dot";
- case TextDecorationLinePattern::DashDotDot: return "dash-dot-dot";
+ case TextDecorationLinePattern::Solid:
+ return "solid";
+ case TextDecorationLinePattern::Dot:
+ return "dot";
+ case TextDecorationLinePattern::Dash:
+ return "dash";
+ case TextDecorationLinePattern::DashDot:
+ return "dash-dot";
+ case TextDecorationLinePattern::DashDotDot:
+ return "dash-dot-dot";
}
}
+#ifdef ANDROID
+
+inline folly::dynamic toDynamic(
+ const ParagraphAttributes &paragraphAttributes) {
+ auto values = folly::dynamic::object();
+ values("maximumNumberOfLines", paragraphAttributes.maximumNumberOfLines);
+ values("ellipsizeMode", toString(paragraphAttributes.ellipsizeMode));
+ values("adjustsFontSizeToFit", paragraphAttributes.adjustsFontSizeToFit);
+ return values;
+}
+
+inline folly::dynamic toDynamic(const TextAttributes &textAttributes) {
+ auto _textAttributes = folly::dynamic::object();
+ if (textAttributes.foregroundColor) {
+ _textAttributes(
+ "foregroundColor", toDynamic(textAttributes.foregroundColor));
+ }
+ if (textAttributes.backgroundColor) {
+ _textAttributes(
+ "backgroundColor", toDynamic(textAttributes.backgroundColor));
+ }
+ if (!std::isnan(textAttributes.opacity)) {
+ _textAttributes("opacity", textAttributes.opacity);
+ }
+ if (!textAttributes.fontFamily.empty()) {
+ _textAttributes("fontFamily", textAttributes.fontFamily);
+ }
+ if (!std::isnan(textAttributes.fontSize)) {
+ _textAttributes("fontSize", textAttributes.fontSize);
+ }
+ if (!std::isnan(textAttributes.fontSizeMultiplier)) {
+ _textAttributes("fontSizeMultiplier", textAttributes.fontSizeMultiplier);
+ }
+ if (textAttributes.fontWeight.has_value()) {
+ _textAttributes("fontWeight", toString(*textAttributes.fontWeight));
+ }
+ if (textAttributes.fontStyle.has_value()) {
+ _textAttributes("fontStyle", toString(*textAttributes.fontStyle));
+ }
+ if (textAttributes.fontVariant.has_value()) {
+ _textAttributes("fontVariant", toString(*textAttributes.fontVariant));
+ }
+ if (textAttributes.allowFontScaling.has_value()) {
+ _textAttributes("allowFontScaling", *textAttributes.allowFontScaling);
+ }
+ if (!std::isnan(textAttributes.letterSpacing)) {
+ _textAttributes("letterSpacing", textAttributes.letterSpacing);
+ }
+ if (!std::isnan(textAttributes.lineHeight)) {
+ _textAttributes("lineHeight", textAttributes.lineHeight);
+ }
+ if (textAttributes.alignment.has_value()) {
+ _textAttributes("alignment", toString(*textAttributes.alignment));
+ }
+ if (textAttributes.baseWritingDirection.has_value()) {
+ _textAttributes(
+ "baseWritingDirection", toString(*textAttributes.baseWritingDirection));
+ }
+ // Decoration
+ if (textAttributes.textDecorationColor) {
+ _textAttributes(
+ "textDecorationColor", toDynamic(textAttributes.textDecorationColor));
+ }
+ if (textAttributes.textDecorationLineType.has_value()) {
+ _textAttributes(
+ "textDecorationLine", toString(*textAttributes.textDecorationLineType));
+ }
+ if (textAttributes.textDecorationLineStyle.has_value()) {
+ _textAttributes(
+ "textDecorationLineStyle",
+ toString(*textAttributes.textDecorationLineStyle));
+ }
+ if (textAttributes.textDecorationLinePattern.has_value()) {
+ _textAttributes(
+ "textDecorationLinePattern",
+ toString(*textAttributes.textDecorationLinePattern));
+ }
+ // Shadow
+ // textShadowOffset = textAttributes.textShadowOffset.has_value() ?
+ // textAttributes.textShadowOffset.value() : textShadowOffset;
+ if (!std::isnan(textAttributes.textShadowRadius)) {
+ _textAttributes("textShadowRadius", textAttributes.textShadowRadius);
+ }
+ if (textAttributes.textShadowColor) {
+ _textAttributes(
+ "textShadowColor", toDynamic(textAttributes.textShadowColor));
+ }
+ // Special
+ if (textAttributes.isHighlighted.has_value()) {
+ _textAttributes("isHighlighted", *textAttributes.isHighlighted);
+ }
+ if (textAttributes.layoutDirection.has_value()) {
+ _textAttributes(
+ "layoutDirection", toString(*textAttributes.layoutDirection));
+ }
+ return _textAttributes;
+}
+
+inline folly::dynamic toDynamic(const AttributedString &attributedString) {
+ auto value = folly::dynamic::object();
+ auto fragments = folly::dynamic::array();
+ for (auto fragment : attributedString.getFragments()) {
+ folly::dynamic dynamicFragment = folly::dynamic::object();
+ dynamicFragment["string"] = fragment.string;
+ if (fragment.parentShadowView.componentHandle) {
+ dynamicFragment["reactTag"] = fragment.parentShadowView.tag;
+ }
+ dynamicFragment["textAttributes"] = toDynamic(fragment.textAttributes);
+ fragments.push_back(dynamicFragment);
+ }
+ value("fragments", fragments);
+ value(
+ "hash", std::hash<facebook::react::AttributedString>{}(attributedString));
+ value("string", attributedString.getString());
+ return value;
+}
+
+#endif
+
} // namespace react
} // namespace facebook

ReactCommon/fabric/attributedstring/ParagraphAttributes.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,24 +7,40 @@
#include "ParagraphAttributes.h"
-#include <fabric/attributedstring/conversions.h>
-#include <fabric/graphics/conversions.h>
-#include <fabric/debug/debugStringConvertibleUtils.h>
+#include <react/attributedstring/conversions.h>
+#include <react/debug/debugStringConvertibleUtils.h>
+#include <react/graphics/conversions.h>
+#include <react/utils/FloatComparison.h>
namespace facebook {
namespace react {
+bool ParagraphAttributes::operator==(const ParagraphAttributes &rhs) const {
+ return std::tie(maximumNumberOfLines, ellipsizeMode, adjustsFontSizeToFit) ==
+ std::tie(
+ rhs.maximumNumberOfLines,
+ rhs.ellipsizeMode,
+ rhs.adjustsFontSizeToFit) &&
+ floatEquality(minimumFontSize, rhs.minimumFontSize) &&
+ floatEquality(maximumFontSize, rhs.maximumFontSize);
+}
+
+bool ParagraphAttributes::operator!=(const ParagraphAttributes &rhs) const {
+ return !(*this == rhs);
+}
+
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList ParagraphAttributes::getDebugProps() const {
return {
debugStringConvertibleItem("maximumNumberOfLines", maximumNumberOfLines),
debugStringConvertibleItem("ellipsizeMode", ellipsizeMode),
debugStringConvertibleItem("adjustsFontSizeToFit", adjustsFontSizeToFit),
debugStringConvertibleItem("minimumFontSize", minimumFontSize),
- debugStringConvertibleItem("maximumFontSize", maximumFontSize)
- };
+ debugStringConvertibleItem("maximumFontSize", maximumFontSize)};
}
+#endif
} // namespace react
} // namespace facebook

ReactCommon/fabric/attributedstring/ParagraphAttributes.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,9 +9,10 @@
#include <limits>
-#include <fabric/attributedstring/primitives.h>
-#include <fabric/debug/DebugStringConvertible.h>
-#include <fabric/graphics/Geometry.h>
+#include <folly/Hash.h>
+#include <react/attributedstring/primitives.h>
+#include <react/debug/DebugStringConvertible.h>
+#include <react/graphics/Geometry.h>
namespace facebook {
namespace react {
@@ -25,41 +26,62 @@
* Two data structures, ParagraphAttributes and AttributedText, should be
* enough to define visual representation of a piece of text on the screen.
*/
-class ParagraphAttributes:
- public DebugStringConvertible {
-
-public:
-
+class ParagraphAttributes : public DebugStringConvertible {
+ public:
#pragma mark - Fields
/*
* Maximum number of lines which paragraph can take.
* Zero value represents "no limit".
*/
- int maximumNumberOfLines {};
+ int maximumNumberOfLines{};
/*
* In case if a text cannot fit given boundaries, defines a place where
* an ellipsize should be placed.
*/
- EllipsizeMode ellipsizeMode {};
+ EllipsizeMode ellipsizeMode{};
/*
* Enables font size adjustment to fit constrained boundaries.
*/
- bool adjustsFontSizeToFit {};
+ bool adjustsFontSizeToFit{};
/*
* In case of font size adjustment enabled, defines minimum and maximum
* font sizes.
*/
- Float minimumFontSize {std::numeric_limits<Float>::quiet_NaN()};
- Float maximumFontSize {std::numeric_limits<Float>::quiet_NaN()};
+ Float minimumFontSize{std::numeric_limits<Float>::quiet_NaN()};
+ Float maximumFontSize{std::numeric_limits<Float>::quiet_NaN()};
+
+ bool operator==(const ParagraphAttributes &) const;
+ bool operator!=(const ParagraphAttributes &) const;
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList getDebugProps() const override;
+#endif
};
} // namespace react
} // namespace facebook
+
+namespace std {
+
+template <>
+struct hash<facebook::react::ParagraphAttributes> {
+ size_t operator()(
+ const facebook::react::ParagraphAttributes &attributes) const {
+ auto seed = size_t{0};
+ folly::hash::hash_combine(
+ seed,
+ attributes.maximumNumberOfLines,
+ attributes.ellipsizeMode,
+ attributes.adjustsFontSizeToFit,
+ attributes.minimumFontSize,
+ attributes.maximumFontSize);
+ return seed;
+ }
+};
+} // namespace std

ReactCommon/fabric/attributedstring/primitives.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,16 +7,15 @@
#pragma once
+#include <functional>
+#include <limits>
+
namespace facebook {
namespace react {
-enum class FontStyle {
- Normal,
- Italic,
- Oblique
-};
+enum class FontStyle { Normal, Italic, Oblique };
-enum class FontWeight: int {
+enum class FontWeight : int {
Weight100 = 100,
UltraLight = 100,
Weight200 = 200,
@@ -38,7 +37,7 @@
Black = 900
};
-enum class FontVariant: int {
+enum class FontVariant : int {
Default = 0,
SmallCaps = 1 << 1,
OldstyleNums = 1 << 2,
@@ -63,7 +62,8 @@
};
enum class WritingDirection {
- Natural, // Determines direction using the Unicode Bidi Algorithm rules P2 and P3.
+ Natural, // Determines direction using the Unicode Bidi Algorithm rules P2 and
+ // P3.
LeftToRight, // Left to right writing direction.
RightToLeft // Right to left writing direction.
};
@@ -75,11 +75,7 @@
UnderlineStrikethrough
};
-enum class TextDecorationLineStyle {
- Single,
- Thick,
- Double
-};
+enum class TextDecorationLineStyle { Single, Thick, Double };
enum class TextDecorationLinePattern {
Solid,
@@ -92,3 +88,67 @@
} // namespace react
} // namespace facebook
+namespace std {
+template <>
+struct hash<facebook::react::FontVariant> {
+ size_t operator()(const facebook::react::FontVariant &v) const {
+ return hash<int>()(static_cast<int>(v));
+ }
+};
+
+template <>
+struct hash<facebook::react::TextAlignment> {
+ size_t operator()(const facebook::react::TextAlignment &v) const {
+ return hash<int>()(static_cast<int>(v));
+ }
+};
+
+template <>
+struct hash<facebook::react::FontStyle> {
+ size_t operator()(const facebook::react::FontStyle &v) const {
+ return hash<int>()(static_cast<int>(v));
+ }
+};
+
+template <>
+struct hash<facebook::react::TextDecorationLineType> {
+ size_t operator()(const facebook::react::TextDecorationLineType &v) const {
+ return hash<int>()(static_cast<int>(v));
+ }
+};
+
+template <>
+struct hash<facebook::react::WritingDirection> {
+ size_t operator()(const facebook::react::WritingDirection &v) const {
+ return hash<int>()(static_cast<int>(v));
+ }
+};
+
+template <>
+struct hash<facebook::react::TextDecorationLinePattern> {
+ size_t operator()(const facebook::react::TextDecorationLinePattern &v) const {
+ return hash<int>()(static_cast<int>(v));
+ }
+};
+
+template <>
+struct hash<facebook::react::TextDecorationLineStyle> {
+ size_t operator()(const facebook::react::TextDecorationLineStyle &v) const {
+ return hash<int>()(static_cast<int>(v));
+ }
+};
+
+template <>
+struct hash<facebook::react::FontWeight> {
+ size_t operator()(const facebook::react::FontWeight &v) const {
+ return hash<int>()(static_cast<int>(v));
+ }
+};
+
+template <>
+struct hash<facebook::react::EllipsizeMode> {
+ size_t operator()(const facebook::react::EllipsizeMode &v) const {
+ return hash<int>()(static_cast<int>(v));
+ }
+};
+} // namespace std

ReactCommon/fabric/attributedstring/tests/AttributedStringTest.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,8 +7,44 @@
#include <memory>
+#include <assert.h>
#include <gtest/gtest.h>
+#include <react/attributedstring/TextAttributes.h>
+#include <react/attributedstring/conversions.h>
+#include <react/attributedstring/primitives.h>
+#include <react/graphics/conversions.h>
-TEST(AttributedStringTest, testSomething) {
- // TODO
+namespace facebook {
+namespace react {
+
+#ifdef ANDROID
+
+TEST(AttributedStringTest, testToDynamic) {
+ auto attString = new AttributedString();
+ auto fragment = new AttributedString::Fragment();
+ fragment->string = "test";
+
+ auto text = new TextAttributes();
+ text->foregroundColor = {
+ colorFromComponents({100 / 255.0, 153 / 255.0, 200 / 255.0, 1.0})};
+ text->opacity = 0.5;
+ text->fontStyle = FontStyle::Italic;
+ text->fontWeight = FontWeight::Thin;
+ text->fontVariant = FontVariant::TabularNums;
+ fragment->textAttributes = *text;
+
+ attString->prependFragment(*fragment);
+
+ auto result = toDynamic(*attString);
+ assert(result["string"] == fragment->string);
+ auto textAttribute = result["fragments"][0]["textAttributes"];
+ assert(textAttribute["foregroundColor"] == toDynamic(text->foregroundColor));
+ assert(textAttribute["opacity"] == text->opacity);
+ assert(textAttribute["fontStyle"] == toString(*text->fontStyle));
+ assert(textAttribute["fontWeight"] == toString(*text->fontWeight));
}
+
+#endif
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/attributedstring/tests/ParagraphAttributesTest.cpp

@@ -0,0 +1,41 @@
+/**
+ * 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.
+ */
+
+#include <memory>
+
+#include <assert.h>
+#include <gtest/gtest.h>
+#include <react/attributedstring/ParagraphAttributes.h>
+#include <react/attributedstring/conversions.h>
+#include <react/attributedstring/primitives.h>
+
+namespace facebook {
+namespace react {
+
+#ifdef ANDROID
+
+TEST(ParagraphAttributesTest, testToDynamic) {
+ auto paragraphAttributes = ParagraphAttributes();
+ paragraphAttributes.maximumNumberOfLines = 2;
+ paragraphAttributes.adjustsFontSizeToFit = false;
+ paragraphAttributes.ellipsizeMode = EllipsizeMode::Middle;
+
+ auto result = toDynamic(paragraphAttributes);
+ assert(
+ result["maximumNumberOfLines"] ==
+ paragraphAttributes.maximumNumberOfLines);
+ assert(
+ result["adjustsFontSizeToFit"] ==
+ paragraphAttributes.adjustsFontSizeToFit);
+ assert(
+ result["ellipsizeMode"] == toString(paragraphAttributes.ellipsizeMode));
+}
+
+#endif
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/attributedstring/tests/TextAttributesTest.cpp

@@ -0,0 +1,41 @@
+/**
+ * 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.
+ */
+
+#include <memory>
+
+#include <assert.h>
+#include <gtest/gtest.h>
+#include <react/attributedstring/TextAttributes.h>
+#include <react/attributedstring/conversions.h>
+#include <react/attributedstring/primitives.h>
+#include <react/graphics/conversions.h>
+
+namespace facebook {
+namespace react {
+
+#ifdef ANDROID
+
+TEST(TextAttributesTest, testToDynamic) {
+ auto text = TextAttributes();
+ text.foregroundColor = {
+ colorFromComponents({200 / 255.0, 153 / 255.0, 100 / 255.0, 1.0})};
+ text.opacity = 0.5;
+ text.fontStyle = FontStyle::Italic;
+ text.fontWeight = FontWeight::Thin;
+ text.fontVariant = FontVariant::TabularNums;
+
+ auto result = toDynamic(text);
+ assert(result["foregroundColor"] == toDynamic(text.foregroundColor));
+ assert(result["opacity"] == text.opacity);
+ assert(result["fontStyle"] == toString(*text.fontStyle));
+ assert(result["fontWeight"] == toString(*text.fontWeight));
+}
+
+#endif
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/attributedstring/TextAttributes.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,54 +7,161 @@
#include "TextAttributes.h"
-#include <fabric/attributedstring/conversions.h>
-#include <fabric/core/conversions.h>
-#include <fabric/graphics/conversions.h>
+#include <react/attributedstring/conversions.h>
+#include <react/core/conversions.h>
+#include <react/graphics/conversions.h>
+#include <react/utils/FloatComparison.h>
+#include <cmath>
-#include <fabric/debug/debugStringConvertibleUtils.h>
+#include <react/debug/debugStringConvertibleUtils.h>
namespace facebook {
namespace react {
void TextAttributes::apply(TextAttributes textAttributes) {
// Color
- foregroundColor = textAttributes.foregroundColor ? textAttributes.foregroundColor : foregroundColor;
- backgroundColor = textAttributes.backgroundColor ? textAttributes.backgroundColor : backgroundColor;
- opacity = !isnan(textAttributes.opacity) ? textAttributes.opacity : opacity;
+ foregroundColor = textAttributes.foregroundColor
+ ? textAttributes.foregroundColor
+ : foregroundColor;
+ backgroundColor = textAttributes.backgroundColor
+ ? textAttributes.backgroundColor
+ : backgroundColor;
+ opacity =
+ !std::isnan(textAttributes.opacity) ? textAttributes.opacity : opacity;
// Font
- fontFamily = !textAttributes.fontFamily.empty() ? textAttributes.fontFamily : fontFamily;
- fontSize = !isnan(textAttributes.fontSize) ? textAttributes.fontSize : fontSize;
- fontSizeMultiplier = !isnan(textAttributes.fontSizeMultiplier) ? textAttributes.fontSizeMultiplier : fontSizeMultiplier;
- fontWeight = textAttributes.fontWeight.hasValue() ? textAttributes.fontWeight : fontWeight;
- fontStyle = textAttributes.fontStyle.hasValue() ? textAttributes.fontStyle : fontStyle;
- fontVariant = textAttributes.fontVariant.hasValue() ? textAttributes.fontVariant : fontVariant;
- allowFontScaling = textAttributes.allowFontScaling.hasValue() ? textAttributes.allowFontScaling : allowFontScaling;
- letterSpacing = !isnan(textAttributes.letterSpacing) ? textAttributes.letterSpacing : letterSpacing;
+ fontFamily = !textAttributes.fontFamily.empty() ? textAttributes.fontFamily
+ : fontFamily;
+ fontSize =
+ !std::isnan(textAttributes.fontSize) ? textAttributes.fontSize : fontSize;
+ fontSizeMultiplier = !std::isnan(textAttributes.fontSizeMultiplier)
+ ? textAttributes.fontSizeMultiplier
+ : fontSizeMultiplier;
+ fontWeight = textAttributes.fontWeight.hasValue() ? textAttributes.fontWeight
+ : fontWeight;
+ fontStyle = textAttributes.fontStyle.hasValue() ? textAttributes.fontStyle
+ : fontStyle;
+ fontVariant = textAttributes.fontVariant.hasValue()
+ ? textAttributes.fontVariant
+ : fontVariant;
+ allowFontScaling = textAttributes.allowFontScaling.hasValue()
+ ? textAttributes.allowFontScaling
+ : allowFontScaling;
+ letterSpacing = !std::isnan(textAttributes.letterSpacing)
+ ? textAttributes.letterSpacing
+ : letterSpacing;
// Paragraph Styles
- lineHeight = !isnan(textAttributes.lineHeight) ? textAttributes.lineHeight : lineHeight;
- alignment = textAttributes.alignment.hasValue() ? textAttributes.alignment : alignment;
- baseWritingDirection = textAttributes.baseWritingDirection.hasValue() ? textAttributes.baseWritingDirection : baseWritingDirection;
+ lineHeight = !std::isnan(textAttributes.lineHeight)
+ ? textAttributes.lineHeight
+ : lineHeight;
+ alignment = textAttributes.alignment.hasValue() ? textAttributes.alignment
+ : alignment;
+ baseWritingDirection = textAttributes.baseWritingDirection.hasValue()
+ ? textAttributes.baseWritingDirection
+ : baseWritingDirection;
// Decoration
- textDecorationColor = textAttributes.textDecorationColor ? textAttributes.textDecorationColor : textDecorationColor;
- textDecorationLineType = textAttributes.textDecorationLineType.hasValue() ? textAttributes.textDecorationLineType : textDecorationLineType;
- textDecorationLineStyle = textAttributes.textDecorationLineStyle.hasValue() ? textAttributes.textDecorationLineStyle : textDecorationLineStyle;
- textDecorationLinePattern = textAttributes.textDecorationLinePattern.hasValue() ? textAttributes.textDecorationLinePattern : textDecorationLinePattern;
+ textDecorationColor = textAttributes.textDecorationColor
+ ? textAttributes.textDecorationColor
+ : textDecorationColor;
+ textDecorationLineType = textAttributes.textDecorationLineType.hasValue()
+ ? textAttributes.textDecorationLineType
+ : textDecorationLineType;
+ textDecorationLineStyle = textAttributes.textDecorationLineStyle.hasValue()
+ ? textAttributes.textDecorationLineStyle
+ : textDecorationLineStyle;
+ textDecorationLinePattern =
+ textAttributes.textDecorationLinePattern.hasValue()
+ ? textAttributes.textDecorationLinePattern
+ : textDecorationLinePattern;
// Shadow
- textShadowOffset = textAttributes.textShadowOffset.hasValue() ? textAttributes.textShadowOffset.value() : textShadowOffset;
- textShadowRadius = !isnan(textAttributes.textShadowRadius) ? textAttributes.textShadowRadius : textShadowRadius;
- textShadowColor = textAttributes.textShadowColor ? textAttributes.textShadowColor : textShadowColor;
+ textShadowOffset = textAttributes.textShadowOffset.hasValue()
+ ? textAttributes.textShadowOffset.value()
+ : textShadowOffset;
+ textShadowRadius = !std::isnan(textAttributes.textShadowRadius)
+ ? textAttributes.textShadowRadius
+ : textShadowRadius;
+ textShadowColor = textAttributes.textShadowColor
+ ? textAttributes.textShadowColor
+ : textShadowColor;
// Special
- isHighlighted = textAttributes.isHighlighted.hasValue() ? textAttributes.isHighlighted : isHighlighted;
- layoutDirection = textAttributes.layoutDirection.hasValue() ? textAttributes.layoutDirection : layoutDirection;
+ isHighlighted = textAttributes.isHighlighted.hasValue()
+ ? textAttributes.isHighlighted
+ : isHighlighted;
+ layoutDirection = textAttributes.layoutDirection.hasValue()
+ ? textAttributes.layoutDirection
+ : layoutDirection;
+}
+
+#pragma mark - Operators
+
+bool TextAttributes::operator==(const TextAttributes &rhs) const {
+ return std::tie(
+ foregroundColor,
+ backgroundColor,
+ fontFamily,
+ fontWeight,
+ fontStyle,
+ fontVariant,
+ allowFontScaling,
+ alignment,
+ baseWritingDirection,
+ textDecorationColor,
+ textDecorationLineType,
+ textDecorationLineStyle,
+ textDecorationLinePattern,
+ textShadowOffset,
+ textShadowColor,
+ isHighlighted,
+ layoutDirection) ==
+ std::tie(
+ rhs.foregroundColor,
+ rhs.backgroundColor,
+ rhs.fontFamily,
+ rhs.fontWeight,
+ rhs.fontStyle,
+ rhs.fontVariant,
+ rhs.allowFontScaling,
+ rhs.alignment,
+ rhs.baseWritingDirection,
+ rhs.textDecorationColor,
+ rhs.textDecorationLineType,
+ rhs.textDecorationLineStyle,
+ rhs.textDecorationLinePattern,
+ rhs.textShadowOffset,
+ rhs.textShadowColor,
+ rhs.isHighlighted,
+ rhs.layoutDirection) &&
+ floatEquality(opacity, rhs.opacity) &&
+ floatEquality(fontSize, rhs.fontSize) &&
+ floatEquality(fontSizeMultiplier, rhs.fontSizeMultiplier) &&
+ floatEquality(letterSpacing, rhs.letterSpacing) &&
+ floatEquality(lineHeight, rhs.lineHeight) &&
+ floatEquality(textShadowRadius, rhs.textShadowRadius);
+}
+
+bool TextAttributes::operator!=(const TextAttributes &rhs) const {
+ return !(*this == rhs);
+}
+
+TextAttributes TextAttributes::defaultTextAttributes() {
+ static auto textAttributes = [] {
+ auto textAttributes = TextAttributes{};
+ // Non-obvious (can be different among platforms) default text attributes.
+ textAttributes.foregroundColor = blackColor();
+ textAttributes.backgroundColor = clearColor();
+ textAttributes.fontSize = 14.0;
+ return textAttributes;
+ }();
+ return textAttributes;
}
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList TextAttributes::getDebugProps() const {
return {
// Color
@@ -79,9 +186,12 @@
// Decoration
debugStringConvertibleItem("textDecorationColor", textDecorationColor),
- debugStringConvertibleItem("textDecorationLineType", textDecorationLineType),
- debugStringConvertibleItem("textDecorationLineStyle", textDecorationLineStyle),
- debugStringConvertibleItem("textDecorationLinePattern", textDecorationLinePattern),
+ debugStringConvertibleItem(
+ "textDecorationLineType", textDecorationLineType),
+ debugStringConvertibleItem(
+ "textDecorationLineStyle", textDecorationLineStyle),
+ debugStringConvertibleItem(
+ "textDecorationLinePattern", textDecorationLinePattern),
// Shadow
debugStringConvertibleItem("textShadowOffset", textShadowOffset),
@@ -93,6 +203,7 @@
debugStringConvertibleItem("layoutDirection", layoutDirection),
};
}
+#endif
} // namespace react
} // namespace facebook

ReactCommon/fabric/attributedstring/TextAttributes.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,15 +7,17 @@
#pragma once
+#include <functional>
#include <limits>
-#include <fabric/attributedstring/primitives.h>
-#include <fabric/core/LayoutPrimitives.h>
-#include <fabric/core/ReactPrimitives.h>
-#include <fabric/debug/DebugStringConvertible.h>
-#include <fabric/graphics/Color.h>
-#include <fabric/graphics/Geometry.h>
+#include <folly/Hash.h>
#include <folly/Optional.h>
+#include <react/attributedstring/primitives.h>
+#include <react/core/LayoutPrimitives.h>
+#include <react/core/ReactPrimitives.h>
+#include <react/debug/DebugStringConvertible.h>
+#include <react/graphics/Color.h>
+#include <react/graphics/Geometry.h>
namespace facebook {
namespace react {
@@ -24,57 +26,105 @@
using SharedTextAttributes = std::shared_ptr<const TextAttributes>;
-class TextAttributes:
- public DebugStringConvertible {
-public:
+class TextAttributes : public DebugStringConvertible {
+ public:
+ /*
+ * Returns TextAttribute object which has actual default attribute values
+ * (e.g. `foregroundColor = black`), in oppose to TextAttribute's default
+ * constructor which creates an object with nulled attributes.
+ */
+ static TextAttributes defaultTextAttributes();
#pragma mark - Fields
// Color
- SharedColor foregroundColor {};
- SharedColor backgroundColor {};
- Float opacity {std::numeric_limits<Float>::quiet_NaN()};
+ SharedColor foregroundColor{};
+ SharedColor backgroundColor{};
+ Float opacity{std::numeric_limits<Float>::quiet_NaN()};
// Font
- std::string fontFamily {""};
- Float fontSize {std::numeric_limits<Float>::quiet_NaN()};
- Float fontSizeMultiplier {std::numeric_limits<Float>::quiet_NaN()};
- folly::Optional<FontWeight> fontWeight {};
- folly::Optional<FontStyle> fontStyle {};
- folly::Optional<FontVariant> fontVariant {};
- folly::Optional<bool> allowFontScaling {};
- Float letterSpacing {std::numeric_limits<Float>::quiet_NaN()};
+ std::string fontFamily{""};
+ Float fontSize{std::numeric_limits<Float>::quiet_NaN()};
+ Float fontSizeMultiplier{std::numeric_limits<Float>::quiet_NaN()};
+ folly::Optional<FontWeight> fontWeight{};
+ folly::Optional<FontStyle> fontStyle{};
+ folly::Optional<FontVariant> fontVariant{};
+ folly::Optional<bool> allowFontScaling{};
+ Float letterSpacing{std::numeric_limits<Float>::quiet_NaN()};
// Paragraph Styles
- Float lineHeight {std::numeric_limits<Float>::quiet_NaN()};
- folly::Optional<TextAlignment> alignment {};
- folly::Optional<WritingDirection> baseWritingDirection {};
+ Float lineHeight{std::numeric_limits<Float>::quiet_NaN()};
+ folly::Optional<TextAlignment> alignment{};
+ folly::Optional<WritingDirection> baseWritingDirection{};
// Decoration
- SharedColor textDecorationColor {};
- folly::Optional<TextDecorationLineType> textDecorationLineType {};
- folly::Optional<TextDecorationLineStyle> textDecorationLineStyle {};
- folly::Optional<TextDecorationLinePattern> textDecorationLinePattern {};
+ SharedColor textDecorationColor{};
+ folly::Optional<TextDecorationLineType> textDecorationLineType{};
+ folly::Optional<TextDecorationLineStyle> textDecorationLineStyle{};
+ folly::Optional<TextDecorationLinePattern> textDecorationLinePattern{};
// Shadow
// TODO: Use `Point` type instead of `Size` for `textShadowOffset` attribute.
- folly::Optional<Size> textShadowOffset {};
- Float textShadowRadius {std::numeric_limits<Float>::quiet_NaN()};
- SharedColor textShadowColor {};
+ folly::Optional<Size> textShadowOffset{};
+ Float textShadowRadius{std::numeric_limits<Float>::quiet_NaN()};
+ SharedColor textShadowColor{};
// Special
- folly::Optional<bool> isHighlighted {};
- folly::Optional<LayoutDirection> layoutDirection {};
+ folly::Optional<bool> isHighlighted{};
+ folly::Optional<LayoutDirection> layoutDirection{};
#pragma mark - Operations
void apply(TextAttributes textAttributes);
+#pragma mark - Operators
+
+ bool operator==(const TextAttributes &rhs) const;
+ bool operator!=(const TextAttributes &rhs) const;
+
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList getDebugProps() const override;
+#endif
};
} // namespace react
} // namespace facebook
+namespace std {
+
+template <>
+struct hash<facebook::react::TextAttributes> {
+ size_t operator()(
+ const facebook::react::TextAttributes &textAttributes) const {
+ auto seed = size_t{0};
+ folly::hash::hash_combine(
+ seed,
+ textAttributes.foregroundColor,
+ textAttributes.backgroundColor,
+ textAttributes.opacity,
+ textAttributes.fontFamily,
+ textAttributes.fontSize,
+ textAttributes.fontSizeMultiplier,
+ textAttributes.fontWeight,
+ textAttributes.fontStyle,
+ textAttributes.fontVariant,
+ textAttributes.allowFontScaling,
+ textAttributes.letterSpacing,
+ textAttributes.lineHeight,
+ textAttributes.alignment,
+ textAttributes.baseWritingDirection,
+ textAttributes.textDecorationColor,
+ textAttributes.textDecorationLineType,
+ textAttributes.textDecorationLineStyle,
+ textAttributes.textDecorationLinePattern,
+ textAttributes.textShadowOffset,
+ textAttributes.textShadowRadius,
+ textAttributes.textShadowColor,
+ textAttributes.isHighlighted,
+ textAttributes.layoutDirection);
+ return seed;
+ }
+};
+} // namespace std

ReactCommon/fabric/components/activityindicator/ActivityIndicatorViewComponentDescriptor.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,13 +7,14 @@
#pragma once
-#include <fabric/components/activityindicator/ActivityIndicatorViewShadowNode.h>
-#include <fabric/core/ConcreteComponentDescriptor.h>
+#include <react/components/activityindicator/ActivityIndicatorViewShadowNode.h>
+#include <react/core/ConcreteComponentDescriptor.h>
namespace facebook {
namespace react {
-using ActivityIndicatorViewComponentDescriptor = ConcreteComponentDescriptor<ActivityIndicatorViewShadowNode>;
+using ActivityIndicatorViewComponentDescriptor =
+ ConcreteComponentDescriptor<ActivityIndicatorViewShadowNode>;
} // namespace react
} // namespace facebook

ReactCommon/fabric/components/activityindicator/ActivityIndicatorViewProps.cpp

@@ -1,22 +1,27 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
*/
-#include <fabric/components/activityindicator/ActivityIndicatorViewProps.h>
-#include <fabric/components/activityindicator/conversions.h>
-#include <fabric/core/propsConversions.h>
+#include <react/components/activityindicator/ActivityIndicatorViewProps.h>
+#include <react/components/activityindicator/conversions.h>
+#include <react/core/propsConversions.h>
namespace facebook {
namespace react {
-ActivityIndicatorViewProps::ActivityIndicatorViewProps(const ActivityIndicatorViewProps &sourceProps, const RawProps &rawProps):
- ViewProps(sourceProps, rawProps),
+ActivityIndicatorViewProps::ActivityIndicatorViewProps(
+ const ActivityIndicatorViewProps &sourceProps,
+ const RawProps &rawProps)
+ : ViewProps(sourceProps, rawProps),
animating(convertRawProp(rawProps, "animating", sourceProps.animating)),
color(convertRawProp(rawProps, "color", sourceProps.color)),
- hidesWhenStopped(convertRawProp(rawProps, "hidesWhenStopped", sourceProps.hidesWhenStopped)),
+ hidesWhenStopped(convertRawProp(
+ rawProps,
+ "hidesWhenStopped",
+ sourceProps.hidesWhenStopped)),
size(convertRawProp(rawProps, "size", sourceProps.size)) {}
} // namespace react

ReactCommon/fabric/components/activityindicator/ActivityIndicatorViewProps.h

@@ -1,31 +1,32 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
*/
-#include <fabric/components/activityindicator/primitives.h>
-#include <fabric/components/view/ViewProps.h>
-#include <fabric/graphics/Color.h>
+#include <react/components/activityindicator/primitives.h>
+#include <react/components/view/ViewProps.h>
+#include <react/graphics/Color.h>
namespace facebook {
namespace react {
// TODO (T28334063): Consider for codegen.
-class ActivityIndicatorViewProps final:
- public ViewProps {
-
-public:
+class ActivityIndicatorViewProps final : public ViewProps {
+ public:
ActivityIndicatorViewProps() = default;
- ActivityIndicatorViewProps(const ActivityIndicatorViewProps &sourceProps, const RawProps &rawProps);
+ ActivityIndicatorViewProps(
+ const ActivityIndicatorViewProps &sourceProps,
+ const RawProps &rawProps);
#pragma mark - Props
- const bool animating {true};
- const SharedColor color {colorFromComponents({153/255.0, 153/255.0, 153/255.0, 1.0})}; // #999999
- const bool hidesWhenStopped {true};
- const ActivityIndicatorViewSize size {ActivityIndicatorViewSize::Small};
+ const bool animating{true};
+ const SharedColor color{colorFromComponents(
+ {153 / 255.0, 153 / 255.0, 153 / 255.0, 1.0})}; // #999999
+ const bool hidesWhenStopped{true};
+ const ActivityIndicatorViewSize size{ActivityIndicatorViewSize::Small};
};
} // namespace react

ReactCommon/fabric/components/activityindicator/ActivityIndicatorViewShadowNode.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactCommon/fabric/components/activityindicator/ActivityIndicatorViewShadowNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,8 +7,8 @@
#pragma once
-#include <fabric/components/activityindicator/ActivityIndicatorViewProps.h>
-#include <fabric/components/view/ConcreteViewShadowNode.h>
+#include <react/components/activityindicator/ActivityIndicatorViewProps.h>
+#include <react/components/view/ConcreteViewShadowNode.h>
namespace facebook {
namespace react {
@@ -18,11 +18,9 @@
/*
* `ShadowNode` for <ActivityIndicatorView> component.
*/
-using ActivityIndicatorViewShadowNode =
- ConcreteViewShadowNode<
+using ActivityIndicatorViewShadowNode = ConcreteViewShadowNode<
ActivityIndicatorViewComponentName,
- ActivityIndicatorViewProps
- >;
+ ActivityIndicatorViewProps>;
} // namespace react
} // namespace facebook

ReactCommon/fabric/components/activityindicator/BUCK

@@ -1,5 +1,5 @@
-load("//configurations/buck/apple:flag_defs.bzl", "OBJC_ARC_PREPROCESSOR_FLAGS", "get_application_ios_flags", "get_debug_preprocessor_flags")
-load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", "subdir_glob", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", "react_native_xplat_target", "rn_xplat_cxx_library")
+load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags")
+load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", "react_native_xplat_target", "rn_xplat_cxx_library", "subdir_glob")
APPLE_COMPILER_FLAGS = get_apple_compiler_flags()
@@ -15,7 +15,7 @@
[
("", "*.h"),
],
- prefix = "fabric/components/activityindicator",
+ prefix = "react/components/activityindicator",
),
compiler_flags = [
"-fexceptions",
@@ -25,16 +25,13 @@
],
fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
- fbobjc_tests = [
- ":tests",
- ],
macosx_tests_override = [],
platforms = (ANDROID, APPLE),
preprocessor_flags = [
"-DLOG_TAG=\"ReactNative\"",
"-DWITH_FBSYSTRACE=1",
],
- tests = [],
+ tests = [":tests"],
visibility = ["PUBLIC"],
deps = [
"xplat//fbsystrace:fbsystrace",
@@ -60,7 +57,7 @@
"-std=c++14",
"-Wall",
],
- platforms = APPLE,
+ platforms = (ANDROID, APPLE),
deps = [
"xplat//folly:molly",
"xplat//third-party/gmock:gtest",

ReactCommon/fabric/components/activityindicator/conversions.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,23 +7,33 @@
#pragma once
-#include <fabric/components/activityindicator/primitives.h>
#include <folly/dynamic.h>
+#include <react/components/activityindicator/primitives.h>
namespace facebook {
namespace react {
-inline void fromDynamic(const folly::dynamic &value, ActivityIndicatorViewSize &result) {
- auto string = value.asString();
- if (string == "large") { result = ActivityIndicatorViewSize::Large; return; }
- if (string == "small") { result = ActivityIndicatorViewSize::Small; return; }
+inline void fromRawValue(
+ const RawValue &value,
+ ActivityIndicatorViewSize &result) {
+ auto string = (std::string)value;
+ if (string == "large") {
+ result = ActivityIndicatorViewSize::Large;
+ return;
+ }
+ if (string == "small") {
+ result = ActivityIndicatorViewSize::Small;
+ return;
+ }
abort();
}
inline std::string toString(const ActivityIndicatorViewSize &value) {
switch (value) {
- case ActivityIndicatorViewSize::Large: return "large";
- case ActivityIndicatorViewSize::Small: return "small";
+ case ActivityIndicatorViewSize::Large:
+ return "large";
+ case ActivityIndicatorViewSize::Small:
+ return "small";
}
}

ReactCommon/fabric/components/activityindicator/primitives.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactCommon/fabric/components/activityindicator/tests/ActivityIndicatorViewTest.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactCommon/fabric/components/image/BUCK

@@ -1,4 +1,4 @@
-load("//configurations/buck/apple:flag_defs.bzl", "OBJC_ARC_PREPROCESSOR_FLAGS", "get_application_ios_flags", "get_debug_preprocessor_flags")
+load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags")
load(
"//tools/build_defs/oss:rn_defs.bzl",
"ANDROID",
@@ -25,7 +25,7 @@
[
("", "*.h"),
],
- prefix = "fabric/components/image",
+ prefix = "react/components/image",
),
compiler_flags = [
"-fexceptions",
@@ -35,16 +35,13 @@
],
fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
- fbobjc_tests = [
- ":tests",
- ],
macosx_tests_override = [],
platforms = (ANDROID, APPLE),
preprocessor_flags = [
"-DLOG_TAG=\"ReactNative\"",
"-DWITH_FBSYSTRACE=1",
],
- tests = [],
+ tests = [":tests"],
visibility = ["PUBLIC"],
deps = [
"xplat//fbsystrace:fbsystrace",
@@ -73,7 +70,7 @@
"-Wall",
],
contacts = ["oncall+react_native@xmail.facebook.com"],
- platforms = APPLE,
+ platforms = (ANDROID, APPLE),
deps = [
"xplat//folly:molly",
"xplat//third-party/gmock:gtest",

ReactCommon/fabric/components/image/conversions.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,51 +7,50 @@
#pragma once
-#include <fabric/imagemanager/primitives.h>
-#include <fabric/graphics/conversions.h>
#include <folly/dynamic.h>
+#include <react/graphics/conversions.h>
+#include <react/imagemanager/primitives.h>
namespace facebook {
namespace react {
-inline void fromDynamic(const folly::dynamic &value, ImageSource &result) {
- if (value.isString()) {
- result = {
- .type = ImageSource::Type::Remote,
- .uri = value.asString()
- };
+inline void fromRawValue(const RawValue &value, ImageSource &result) {
+ if (value.hasType<std::string>()) {
+ result = {.type = ImageSource::Type::Remote, .uri = (std::string)value};
return;
}
- if (value.isObject()) {
+ if (value.hasType<std::unordered_map<std::string, RawValue>>()) {
+ auto items = (std::unordered_map<std::string, RawValue>)value;
result = {};
result.type = ImageSource::Type::Remote;
- if (value.count("__packager_asset")) {
+ if (items.find("__packager_asset") != items.end()) {
result.type = ImageSource::Type::Local;
}
- if (value.count("width") && value.count("height")) {
- fromDynamic(value, result.size);
+ if (items.find("width") != items.end() &&
+ items.find("height") != items.end()) {
+ result.size = {(Float)items.at("width"), (Float)items.at("height")};
}
- if (value.count("scale")) {
- result.scale = (Float)value["scale"].asDouble();
+ if (items.find("scale") != items.end()) {
+ result.scale = (Float)items.at("scale");
} else {
- result.scale = value.count("deprecated") ? 0.0 : 1.0;
+ result.scale = items.find("deprecated") != items.end() ? 0.0 : 1.0;
}
- if (value.count("url")) {
- result.uri = value["url"].asString();
+ if (items.find("url") != items.end()) {
+ result.uri = (std::string)items.at("url");
}
- if (value.count("uri")) {
- result.uri = value["uri"].asString();
+ if (items.find("uri") != items.end()) {
+ result.uri = (std::string)items.at("uri");
}
- if (value.count("bundle")) {
- result.bundle = value["bundle"].asString();
+ if (items.find("bundle") != items.end()) {
+ result.bundle = (std::string)items.at("bundle");
result.type = ImageSource::Type::Local;
}
@@ -65,24 +64,44 @@
return "{uri: " + value.uri + "}";
}
-inline void fromDynamic(const folly::dynamic &value, ImageResizeMode &result) {
- assert(value.isString());
- auto stringValue = value.asString();
- if (stringValue == "cover") { result = ImageResizeMode::Cover; return; }
- if (stringValue == "contain") { result = ImageResizeMode::Contain; return; }
- if (stringValue == "stretch") { result = ImageResizeMode::Stretch; return; }
- if (stringValue == "center") { result = ImageResizeMode::Center; return; }
- if (stringValue == "repeat") { result = ImageResizeMode::Repeat; return; }
+inline void fromRawValue(const RawValue &value, ImageResizeMode &result) {
+ assert(value.hasType<std::string>());
+ auto stringValue = (std::string)value;
+ if (stringValue == "cover") {
+ result = ImageResizeMode::Cover;
+ return;
+ }
+ if (stringValue == "contain") {
+ result = ImageResizeMode::Contain;
+ return;
+ }
+ if (stringValue == "stretch") {
+ result = ImageResizeMode::Stretch;
+ return;
+ }
+ if (stringValue == "center") {
+ result = ImageResizeMode::Center;
+ return;
+ }
+ if (stringValue == "repeat") {
+ result = ImageResizeMode::Repeat;
+ return;
+ }
abort();
}
inline std::string toString(const ImageResizeMode &value) {
switch (value) {
- case ImageResizeMode::Cover: return "cover";
- case ImageResizeMode::Contain: return "contain";
- case ImageResizeMode::Stretch: return "stretch";
- case ImageResizeMode::Center: return "center";
- case ImageResizeMode::Repeat: return "repeat";
+ case ImageResizeMode::Cover:
+ return "cover";
+ case ImageResizeMode::Contain:
+ return "contain";
+ case ImageResizeMode::Stretch:
+ return "stretch";
+ case ImageResizeMode::Center:
+ return "center";
+ case ImageResizeMode::Repeat:
+ return "repeat";
}
}

ReactCommon/fabric/components/image/ImageComponentDescriptor.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,10 +7,10 @@
#pragma once
-#include <fabric/components/image/ImageShadowNode.h>
-#include <fabric/core/ConcreteComponentDescriptor.h>
-#include <fabric/imagemanager/ImageManager.h>
-#include <fabric/uimanager/ContextContainer.h>
+#include <react/components/image/ImageShadowNode.h>
+#include <react/core/ConcreteComponentDescriptor.h>
+#include <react/imagemanager/ImageManager.h>
+#include <react/uimanager/ContextContainer.h>
namespace facebook {
namespace react {
@@ -18,26 +18,32 @@
/*
* Descriptor for <Image> component.
*/
-class ImageComponentDescriptor final:
- public ConcreteComponentDescriptor<ImageShadowNode> {
-
-public:
- ImageComponentDescriptor(SharedEventDispatcher eventDispatcher, const SharedContextContainer &contextContainer):
- ConcreteComponentDescriptor(eventDispatcher),
- imageManager_(contextContainer->getInstance<SharedImageManager>()) {}
+class ImageComponentDescriptor final
+ : public ConcreteComponentDescriptor<ImageShadowNode> {
+ public:
+ ImageComponentDescriptor(
+ SharedEventDispatcher eventDispatcher,
+ const SharedContextContainer &contextContainer)
+ : ConcreteComponentDescriptor(eventDispatcher),
+ imageManager_(
+ contextContainer
+ ? contextContainer->getInstance<SharedImageManager>(
+ "ImageManager")
+ : nullptr) {}
void adopt(UnsharedShadowNode shadowNode) const override {
ConcreteComponentDescriptor::adopt(shadowNode);
assert(std::dynamic_pointer_cast<ImageShadowNode>(shadowNode));
- auto imageShadowNode = std::static_pointer_cast<ImageShadowNode>(shadowNode);
+ auto imageShadowNode =
+ std::static_pointer_cast<ImageShadowNode>(shadowNode);
// `ImageShadowNode` uses `ImageManager` to initiate image loading and
// communicate the loading state and results to mounting layer.
imageShadowNode->setImageManager(imageManager_);
}
-private:
+ private:
const SharedImageManager imageManager_;
};

ReactCommon/fabric/components/image/ImageEventEmitter.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -22,8 +22,12 @@
dispatchEvent("loadEnd");
}
-void ImageEventEmitter::onProgress() const {
- dispatchEvent("progress");
+void ImageEventEmitter::onProgress(double progress) const {
+ dispatchEvent("progress", [=](jsi::Runtime &runtime) {
+ auto payload = jsi::Object(runtime);
+ payload.setProperty(runtime, "progress", progress);
+ return payload;
+ });
}
void ImageEventEmitter::onError() const {

ReactCommon/fabric/components/image/ImageEventEmitter.h

@@ -1,26 +1,24 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
*/
#pragma once
-#include <fabric/components/view/ViewEventEmitter.h>
+#include <react/components/view/ViewEventEmitter.h>
namespace facebook {
namespace react {
-class ImageEventEmitter:
- public ViewEventEmitter {
-
-public:
+class ImageEventEmitter : public ViewEventEmitter {
+ public:
using ViewEventEmitter::ViewEventEmitter;
void onLoadStart() const;
void onLoad() const;
void onLoadEnd() const;
- void onProgress() const;
+ void onProgress(double) const;
void onError() const;
void onPartialLoad() const;
};

ReactCommon/fabric/components/image/ImageLocalData.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,8 +7,8 @@
#include "ImageLocalData.h"
-#include <fabric/components/image/conversions.h>
-#include <fabric/debug/debugStringConvertibleUtils.h>
+#include <react/components/image/conversions.h>
+#include <react/debug/debugStringConvertibleUtils.h>
namespace facebook {
namespace react {
@@ -23,15 +23,15 @@
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
std::string ImageLocalData::getDebugName() const {
return "ImageLocalData";
}
SharedDebugStringConvertibleList ImageLocalData::getDebugProps() const {
- return {
- debugStringConvertibleItem("imageSource", imageSource_)
- };
+ return {debugStringConvertibleItem("imageSource", imageSource_)};
}
+#endif
} // namespace react
} // namespace facebook

ReactCommon/fabric/components/image/ImageLocalData.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,9 +7,9 @@
#pragma once
-#include <fabric/core/LocalData.h>
-#include <fabric/imagemanager/primitives.h>
-#include <fabric/imagemanager/ImageRequest.h>
+#include <react/core/LocalData.h>
+#include <react/imagemanager/ImageRequest.h>
+#include <react/imagemanager/primitives.h>
namespace facebook {
namespace react {
@@ -22,14 +22,10 @@
* LocalData for <Image> component.
* Represents the image request state and (possible) retrieved image bitmap.
*/
-class ImageLocalData:
- public LocalData {
-
-public:
-
- ImageLocalData(const ImageSource &imageSource, ImageRequest imageRequest):
- imageSource_(imageSource),
- imageRequest_(std::move(imageRequest)) {};
+class ImageLocalData : public LocalData {
+ public:
+ ImageLocalData(const ImageSource &imageSource, ImageRequest imageRequest)
+ : imageSource_(imageSource), imageRequest_(std::move(imageRequest)){};
/*
* Returns stored ImageSource object.
@@ -44,11 +40,12 @@
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
std::string getDebugName() const override;
SharedDebugStringConvertibleList getDebugProps() const override;
+#endif
-private:
-
+ private:
ImageSource imageSource_;
ImageRequest imageRequest_;
};

ReactCommon/fabric/components/image/ImageProps.cpp

@@ -1,23 +1,31 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
*/
-#include <fabric/components/image/conversions.h>
-#include <fabric/components/image/ImageProps.h>
-#include <fabric/core/propsConversions.h>
+#include <react/components/image/ImageProps.h>
+#include <react/components/image/conversions.h>
+#include <react/core/propsConversions.h>
namespace facebook {
namespace react {
-ImageProps::ImageProps(const ImageProps &sourceProps, const RawProps &rawProps):
- ViewProps(sourceProps, rawProps),
+ImageProps::ImageProps(const ImageProps &sourceProps, const RawProps &rawProps)
+ : ViewProps(sourceProps, rawProps),
sources(convertRawProp(rawProps, "source", sourceProps.sources)),
- defaultSources(convertRawProp(rawProps, "defaultSource", sourceProps.defaultSources)),
- resizeMode(convertRawProp(rawProps, "resizeMode", sourceProps.resizeMode, ImageResizeMode::Stretch)),
- blurRadius(convertRawProp(rawProps, "blurRadius", sourceProps.blurRadius)),
+ defaultSources(convertRawProp(
+ rawProps,
+ "defaultSource",
+ sourceProps.defaultSources)),
+ resizeMode(convertRawProp(
+ rawProps,
+ "resizeMode",
+ sourceProps.resizeMode,
+ ImageResizeMode::Stretch)),
+ blurRadius(
+ convertRawProp(rawProps, "blurRadius", sourceProps.blurRadius)),
capInsets(convertRawProp(rawProps, "capInsets", sourceProps.capInsets)),
tintColor(convertRawProp(rawProps, "tintColor", sourceProps.tintColor)) {}

ReactCommon/fabric/components/image/ImageProps.h

@@ -1,33 +1,31 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
*/
-#include <fabric/components/view/ViewProps.h>
-#include <fabric/graphics/Color.h>
-#include <fabric/imagemanager/primitives.h>
+#include <react/components/view/ViewProps.h>
+#include <react/graphics/Color.h>
+#include <react/imagemanager/primitives.h>
namespace facebook {
namespace react {
// TODO (T28334063): Consider for codegen.
-class ImageProps final:
- public ViewProps {
-
-public:
+class ImageProps final : public ViewProps {
+ public:
ImageProps() = default;
ImageProps(const ImageProps &sourceProps, const RawProps &rawProps);
#pragma mark - Props
- const ImageSources sources {};
- const ImageSources defaultSources {};
- const ImageResizeMode resizeMode {ImageResizeMode::Stretch};
- const Float blurRadius {};
- const EdgeInsets capInsets {};
- const SharedColor tintColor {};
+ const ImageSources sources{};
+ const ImageSources defaultSources{};
+ const ImageResizeMode resizeMode{ImageResizeMode::Stretch};
+ const Float blurRadius{};
+ const EdgeInsets capInsets{};
+ const SharedColor tintColor{};
};
} // namespace react

ReactCommon/fabric/components/image/ImageShadowNode.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,9 +7,9 @@
#include <cstdlib>
-#include <fabric/components/image/ImageShadowNode.h>
-#include <fabric/components/image/ImageLocalData.h>
-#include <fabric/core/LayoutContext.h>
+#include <react/components/image/ImageLocalData.h>
+#include <react/components/image/ImageShadowNode.h>
+#include <react/core/LayoutContext.h>
namespace facebook {
namespace react {
@@ -26,7 +26,8 @@
const auto &currentLocalData = getLocalData();
if (currentLocalData) {
assert(std::dynamic_pointer_cast<const ImageLocalData>(currentLocalData));
- auto currentImageLocalData = std::static_pointer_cast<const ImageLocalData>(currentLocalData);
+ auto currentImageLocalData =
+ std::static_pointer_cast<const ImageLocalData>(currentLocalData);
if (currentImageLocalData->getImageSource() == imageSource) {
// Same `imageSource` is already in `localData`,
// no need to (re)request an image resource.
@@ -38,7 +39,8 @@
ensureUnsealed();
auto imageRequest = imageManager_->requestImage(imageSource);
- auto imageLocalData = std::make_shared<ImageLocalData>(imageSource, std::move(imageRequest));
+ auto imageLocalData =
+ std::make_shared<ImageLocalData>(imageSource, std::move(imageRequest));
setLocalData(imageLocalData);
}
@@ -59,7 +61,7 @@
auto targetImageArea = size.width * size.height * scale * scale;
auto bestFit = kFloatMax;
- ImageSource bestSource;
+ auto bestSource = ImageSource{};
for (const auto &source : sources) {
auto sourceSize = source.size;

ReactCommon/fabric/components/image/ImageShadowNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,11 +7,11 @@
#pragma once
-#include <fabric/components/image/ImageEventEmitter.h>
-#include <fabric/components/image/ImageProps.h>
-#include <fabric/components/view/ConcreteViewShadowNode.h>
-#include <fabric/imagemanager/ImageManager.h>
-#include <fabric/imagemanager/primitives.h>
+#include <react/components/image/ImageEventEmitter.h>
+#include <react/components/image/ImageProps.h>
+#include <react/components/view/ConcreteViewShadowNode.h>
+#include <react/imagemanager/ImageManager.h>
+#include <react/imagemanager/primitives.h>
namespace facebook {
namespace react {
@@ -21,15 +21,11 @@
/*
* `ShadowNode` for <Image> component.
*/
-class ImageShadowNode final:
- public ConcreteViewShadowNode<
+class ImageShadowNode final : public ConcreteViewShadowNode<
ImageComponentName,
ImageProps,
- ImageEventEmitter
- > {
-
-public:
-
+ ImageEventEmitter> {
+ public:
using ConcreteViewShadowNode::ConcreteViewShadowNode;
/*
@@ -41,8 +37,7 @@
void layout(LayoutContext layoutContext) override;
-private:
-
+ private:
/*
* (Re)Creates a `LocalData` object (with `ImageRequest`) if needed.
*/

ReactCommon/fabric/components/image/tests/ImageTest.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,6 +9,6 @@
#include <gtest/gtest.h>
-TEST(SwitchTest, testSomething) {
+TEST(ImageTest, testSomething) {
// TODO
}

ReactCommon/fabric/components/root/BUCK

@@ -1,14 +1,14 @@
-load("//configurations/buck/apple:flag_defs.bzl", "OBJC_ARC_PREPROCESSOR_FLAGS", "get_application_ios_flags", "get_debug_preprocessor_flags")
+load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags")
load(
"//tools/build_defs/oss:rn_defs.bzl",
"ANDROID",
"APPLE",
- "subdir_glob",
"fb_xplat_cxx_test",
"get_apple_compiler_flags",
"get_apple_inspector_flags",
"react_native_xplat_target",
"rn_xplat_cxx_library",
+ "subdir_glob",
)
APPLE_COMPILER_FLAGS = get_apple_compiler_flags()
@@ -25,7 +25,7 @@
[
("", "*.h"),
],
- prefix = "fabric/components/root",
+ prefix = "react/components/root",
),
compiler_flags = [
"-fexceptions",
@@ -35,16 +35,14 @@
],
fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
- fbobjc_tests = [
- ":tests",
- ],
macosx_tests_override = [],
platforms = (ANDROID, APPLE),
preprocessor_flags = [
"-DLOG_TAG=\"ReactNative\"",
- "-DWITH_FBSYSTRACE=1",
+ # Systraces are temporary disabled.
+ # "-DWITH_FBSYSTRACE=1",
],
- tests = [],
+ tests = [":tests"],
visibility = ["PUBLIC"],
deps = [
"xplat//fbsystrace:fbsystrace",
@@ -71,7 +69,7 @@
"-Wall",
],
contacts = ["oncall+react_native@xmail.facebook.com"],
- platforms = APPLE,
+ platforms = (ANDROID, APPLE),
deps = [
"xplat//folly:molly",
"xplat//third-party/gmock:gtest",

ReactCommon/fabric/components/root/RootProps.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,14 +7,15 @@
#include "RootProps.h"
-#include <fabric/components/view/conversions.h>
-#include <fabric/components/view/YogaLayoutableShadowNode.h>
+#include <react/components/view/YogaLayoutableShadowNode.h>
+#include <react/components/view/conversions.h>
namespace facebook {
namespace react {
-static YGStyle yogaStyleFromLayoutConstraints(const LayoutConstraints &layoutConstraints) {
- YGStyle yogaStyle;
+static YGStyle yogaStyleFromLayoutConstraints(
+ const LayoutConstraints &layoutConstraints) {
+ auto yogaStyle = YGStyle{};
yogaStyle.minDimensions[YGDimensionWidth] =
yogaStyleValueFromFloat(layoutConstraints.minimumSize.width);
yogaStyle.minDimensions[YGDimensionHeight] =
@@ -25,17 +26,19 @@
yogaStyle.maxDimensions[YGDimensionHeight] =
yogaStyleValueFromFloat(layoutConstraints.maximumSize.height);
+ yogaStyle.direction =
+ yogaDirectionFromLayoutDirection(layoutConstraints.layoutDirection);
+
return yogaStyle;
}
RootProps::RootProps(
const RootProps &sourceProps,
const LayoutConstraints &layoutConstraints,
- const LayoutContext &layoutContext
-):
- ViewProps(yogaStyleFromLayoutConstraints(layoutConstraints)),
+ const LayoutContext &layoutContext)
+ : ViewProps(yogaStyleFromLayoutConstraints(layoutConstraints)),
layoutConstraints(layoutConstraints),
- layoutContext(layoutContext) {};
+ layoutContext(layoutContext){};
} // namespace react
} // namespace facebook

ReactCommon/fabric/components/root/RootProps.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,9 +9,9 @@
#include <memory>
-#include <fabric/components/view/ViewProps.h>
-#include <fabric/core/LayoutConstraints.h>
-#include <fabric/core/LayoutContext.h>
+#include <react/components/view/ViewProps.h>
+#include <react/core/LayoutConstraints.h>
+#include <react/core/LayoutContext.h>
namespace facebook {
namespace react {
@@ -20,21 +20,18 @@
using SharedRootProps = std::shared_ptr<const RootProps>;
-class RootProps final:
- public ViewProps {
-
-public:
+class RootProps final : public ViewProps {
+ public:
RootProps() = default;
RootProps(
const RootProps &sourceProps,
const LayoutConstraints &layoutConstraints,
- const LayoutContext &layoutContext
- );
+ const LayoutContext &layoutContext);
#pragma mark - Props
- const LayoutConstraints layoutConstraints {};
- const LayoutContext layoutContext {};
+ const LayoutConstraints layoutConstraints{};
+ const LayoutContext layoutContext{};
};
} // namespace react

ReactCommon/fabric/components/root/RootShadowNode.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,7 +7,8 @@
#include "RootShadowNode.h"
-#include <fabric/components/view/conversions.h>
+#include <react/components/view/conversions.h>
+#include <react/debug/SystraceSection.h>
namespace facebook {
namespace react {
@@ -15,6 +16,7 @@
const char RootComponentName[] = "RootView";
void RootShadowNode::layout() {
+ SystraceSection s("RootShadowNode::layout");
ensureUnsealed();
layout(getProps()->layoutContext);
@@ -23,5 +25,44 @@
setLayoutMetrics(layoutMetricsFromYogaNode(yogaNode_));
}
+UnsharedRootShadowNode RootShadowNode::clone(
+ const LayoutConstraints &layoutConstraints,
+ const LayoutContext &layoutContext) const {
+ auto props = std::make_shared<const RootProps>(
+ *getProps(), layoutConstraints, layoutContext);
+ auto newRootShadowNode = std::make_shared<RootShadowNode>(
+ *this, ShadowNodeFragment{.props = props});
+ return newRootShadowNode;
+}
+
+UnsharedRootShadowNode RootShadowNode::clone(
+ const SharedShadowNode &oldShadowNode,
+ const SharedShadowNode &newShadowNode) const {
+ std::vector<std::reference_wrapper<const ShadowNode>> ancestors;
+ oldShadowNode->constructAncestorPath(*this, ancestors);
+
+ if (ancestors.size() == 0) {
+ return UnsharedRootShadowNode{nullptr};
+ }
+
+ auto oldChild = oldShadowNode;
+ auto newChild = newShadowNode;
+
+ SharedShadowNodeUnsharedList sharedChildren;
+
+ for (const auto &ancestor : ancestors) {
+ auto children = ancestor.get().getChildren();
+ std::replace(children.begin(), children.end(), oldChild, newChild);
+
+ sharedChildren = std::make_shared<SharedShadowNodeList>(children);
+
+ oldChild = ancestor.get().shared_from_this();
+ newChild = oldChild->clone(ShadowNodeFragment{.children = sharedChildren});
+ }
+
+ return std::make_shared<RootShadowNode>(
+ *this, ShadowNodeFragment{.children = sharedChildren});
+}
+
} // namespace react
} // namespace facebook

ReactCommon/fabric/components/root/RootShadowNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,9 +9,9 @@
#include <memory>
-#include <fabric/components/root/RootProps.h>
-#include <fabric/components/view/ConcreteViewShadowNode.h>
-#include <fabric/core/LayoutContext.h>
+#include <react/components/root/RootProps.h>
+#include <react/components/view/ConcreteViewShadowNode.h>
+#include <react/core/LayoutContext.h>
namespace facebook {
namespace react {
@@ -29,14 +29,9 @@
* props which represent external layout constraints and context of the
* shadow tree.
*/
-class RootShadowNode final:
- public ConcreteViewShadowNode<
- RootComponentName,
- RootProps
- > {
-
-public:
-
+class RootShadowNode final
+ : public ConcreteViewShadowNode<RootComponentName, RootProps> {
+ public:
using ConcreteViewShadowNode::ConcreteViewShadowNode;
/*
@@ -44,8 +39,24 @@
*/
void layout();
-private:
+ /*
+ * Clones the node with given `layoutConstraints` and `layoutContext`.
+ */
+ UnsharedRootShadowNode clone(
+ const LayoutConstraints &layoutConstraints,
+ const LayoutContext &layoutContext) const;
+
+ /*
+ * Clones the node replacing a given old shadow node with a new one in the
+ * tree by cloning all nodes on the path to the root node and then complete
+ * the tree. Returns `nullptr` if the operation cannot be finished
+ * successfully.
+ */
+ UnsharedRootShadowNode clone(
+ const SharedShadowNode &oldShadowNode,
+ const SharedShadowNode &newShadowNode) const;
+ private:
using YogaLayoutableShadowNode::layout;
};

ReactCommon/fabric/components/root/tests/RootShadowNodeTest.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactCommon/fabric/components/scrollview/BUCK

@@ -1,4 +1,4 @@
-load("//configurations/buck/apple:flag_defs.bzl", "OBJC_ARC_PREPROCESSOR_FLAGS", "get_application_ios_flags", "get_debug_preprocessor_flags")
+load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags")
load(
"//tools/build_defs/oss:rn_defs.bzl",
"ANDROID",
@@ -28,7 +28,7 @@
[
("", "*.h"),
],
- prefix = "fabric/components/scrollview",
+ prefix = "react/components/scrollview",
),
compiler_flags = [
"-fexceptions",
@@ -38,9 +38,6 @@
],
fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
- fbobjc_tests = [
- ":tests",
- ],
force_static = True,
macosx_tests_override = [],
platforms = (ANDROID, APPLE),
@@ -48,7 +45,7 @@
"-DLOG_TAG=\"ReactNative\"",
"-DWITH_FBSYSTRACE=1",
],
- tests = [],
+ tests = [":tests"],
visibility = ["PUBLIC"],
deps = [
"xplat//fbsystrace:fbsystrace",
@@ -75,7 +72,7 @@
"-Wall",
],
contacts = ["oncall+react_native@xmail.facebook.com"],
- platforms = APPLE,
+ platforms = (ANDROID, APPLE),
deps = [
"xplat//folly:molly",
"xplat//third-party/gmock:gtest",

ReactCommon/fabric/components/scrollview/conversions.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,57 +7,99 @@
#pragma once
-#include <fabric/components/scrollview/primitives.h>
#include <folly/dynamic.h>
+#include <react/components/scrollview/primitives.h>
namespace facebook {
namespace react {
-inline void fromDynamic(const folly::dynamic &value, ScrollViewSnapToAlignment &result) {
- auto string = value.asString();
- if (string == "start") { result = ScrollViewSnapToAlignment::Start; return; }
- if (string == "center") { result = ScrollViewSnapToAlignment::Center; return; }
- if (string == "end") { result = ScrollViewSnapToAlignment::End; return; }
+inline void fromRawValue(
+ const RawValue &value,
+ ScrollViewSnapToAlignment &result) {
+ auto string = (std::string)value;
+ if (string == "start") {
+ result = ScrollViewSnapToAlignment::Start;
+ return;
+ }
+ if (string == "center") {
+ result = ScrollViewSnapToAlignment::Center;
+ return;
+ }
+ if (string == "end") {
+ result = ScrollViewSnapToAlignment::End;
+ return;
+ }
abort();
}
-inline void fromDynamic(const folly::dynamic &value, ScrollViewIndicatorStyle &result) {
- auto string = value.asString();
- if (string == "default") { result = ScrollViewIndicatorStyle::Default; return; }
- if (string == "black") { result = ScrollViewIndicatorStyle::Black; return; }
- if (string == "white") { result = ScrollViewIndicatorStyle::White; return; }
+inline void fromRawValue(
+ const RawValue &value,
+ ScrollViewIndicatorStyle &result) {
+ auto string = (std::string)value;
+ if (string == "default") {
+ result = ScrollViewIndicatorStyle::Default;
+ return;
+ }
+ if (string == "black") {
+ result = ScrollViewIndicatorStyle::Black;
+ return;
+ }
+ if (string == "white") {
+ result = ScrollViewIndicatorStyle::White;
+ return;
+ }
abort();
}
-inline void fromDynamic(const folly::dynamic &value, ScrollViewKeyboardDismissMode &result) {
- auto string = value.asString();
- if (string == "none") { result = ScrollViewKeyboardDismissMode::None; return; }
- if (string == "on-drag") { result = ScrollViewKeyboardDismissMode::OnDrag; return; }
- if (string == "interactive") { result = ScrollViewKeyboardDismissMode::Interactive; return; }
+inline void fromRawValue(
+ const RawValue &value,
+ ScrollViewKeyboardDismissMode &result) {
+ auto string = (std::string)value;
+ if (string == "none") {
+ result = ScrollViewKeyboardDismissMode::None;
+ return;
+ }
+ if (string == "on-drag") {
+ result = ScrollViewKeyboardDismissMode::OnDrag;
+ return;
+ }
+ if (string == "interactive") {
+ result = ScrollViewKeyboardDismissMode::Interactive;
+ return;
+ }
abort();
}
inline std::string toString(const ScrollViewSnapToAlignment &value) {
switch (value) {
- case ScrollViewSnapToAlignment::Start: return "start";
- case ScrollViewSnapToAlignment::Center: return "center";
- case ScrollViewSnapToAlignment::End: return "end";
+ case ScrollViewSnapToAlignment::Start:
+ return "start";
+ case ScrollViewSnapToAlignment::Center:
+ return "center";
+ case ScrollViewSnapToAlignment::End:
+ return "end";
}
}
inline std::string toString(const ScrollViewIndicatorStyle &value) {
switch (value) {
- case ScrollViewIndicatorStyle::Default: return "default";
- case ScrollViewIndicatorStyle::Black: return "black";
- case ScrollViewIndicatorStyle::White: return "white";
+ case ScrollViewIndicatorStyle::Default:
+ return "default";
+ case ScrollViewIndicatorStyle::Black:
+ return "black";
+ case ScrollViewIndicatorStyle::White:
+ return "white";
}
}
inline std::string toString(const ScrollViewKeyboardDismissMode &value) {
switch (value) {
- case ScrollViewKeyboardDismissMode::None: return "none";
- case ScrollViewKeyboardDismissMode::OnDrag: return "on-drag";
- case ScrollViewKeyboardDismissMode::Interactive: return "interactive";
+ case ScrollViewKeyboardDismissMode::None:
+ return "none";
+ case ScrollViewKeyboardDismissMode::OnDrag:
+ return "on-drag";
+ case ScrollViewKeyboardDismissMode::Interactive:
+ return "interactive";
}
}

ReactCommon/fabric/components/scrollview/primitives.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,23 +10,11 @@
namespace facebook {
namespace react {
-enum class ScrollViewSnapToAlignment {
- Start,
- Center,
- End
-};
-
-enum class ScrollViewIndicatorStyle {
- Default,
- Black,
- White
-};
-
-enum class ScrollViewKeyboardDismissMode {
- None,
- OnDrag,
- Interactive
-};
+enum class ScrollViewSnapToAlignment { Start, Center, End };
+
+enum class ScrollViewIndicatorStyle { Default, Black, White };
+
+enum class ScrollViewKeyboardDismissMode { None, OnDrag, Interactive };
} // namespace react
} // namespace facebook

ReactCommon/fabric/components/scrollview/ScrollViewComponentDescriptor.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,13 +7,14 @@
#pragma once
-#include <fabric/components/scrollview/ScrollViewShadowNode.h>
-#include <fabric/core/ConcreteComponentDescriptor.h>
+#include <react/components/scrollview/ScrollViewShadowNode.h>
+#include <react/core/ConcreteComponentDescriptor.h>
namespace facebook {
namespace react {
-using ScrollViewComponentDescriptor = ConcreteComponentDescriptor<ScrollViewShadowNode>;
+using ScrollViewComponentDescriptor =
+ ConcreteComponentDescriptor<ScrollViewShadowNode>;
} // namespace react
} // namespace facebook

ReactCommon/fabric/components/scrollview/ScrollViewEventEmitter.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,54 +10,89 @@
namespace facebook {
namespace react {
-void ScrollViewEventEmitter::onScroll(const ScrollViewMetrics &scrollViewMetrics) const {
+static jsi::Value scrollViewMetricsPayload(
+ jsi::Runtime &runtime,
+ const ScrollViewMetrics &scrollViewMetrics) {
+ auto payload = jsi::Object(runtime);
+
+ {
+ auto contentOffset = jsi::Object(runtime);
+ contentOffset.setProperty(runtime, "x", scrollViewMetrics.contentOffset.x);
+ contentOffset.setProperty(runtime, "y", scrollViewMetrics.contentOffset.y);
+ payload.setProperty(runtime, "contentOffset", contentOffset);
+ }
+
+ {
+ auto contentInset = jsi::Object(runtime);
+ contentInset.setProperty(
+ runtime, "top", scrollViewMetrics.contentInset.top);
+ contentInset.setProperty(
+ runtime, "left", scrollViewMetrics.contentInset.left);
+ contentInset.setProperty(
+ runtime, "bottom", scrollViewMetrics.contentInset.bottom);
+ contentInset.setProperty(
+ runtime, "right", scrollViewMetrics.contentInset.right);
+ payload.setProperty(runtime, "contentInset", contentInset);
+ }
+
+ {
+ auto contentSize = jsi::Object(runtime);
+ contentSize.setProperty(
+ runtime, "width", scrollViewMetrics.contentSize.width);
+ contentSize.setProperty(
+ runtime, "height", scrollViewMetrics.contentSize.height);
+ payload.setProperty(runtime, "contentSize", contentSize);
+ }
+
+ {
+ auto containerSize = jsi::Object(runtime);
+ containerSize.setProperty(
+ runtime, "width", scrollViewMetrics.containerSize.width);
+ containerSize.setProperty(
+ runtime, "height", scrollViewMetrics.containerSize.height);
+ payload.setProperty(runtime, "layoutMeasurement", containerSize);
+ }
+
+ payload.setProperty(runtime, "zoomScale", scrollViewMetrics.zoomScale);
+
+ return payload;
+}
+
+void ScrollViewEventEmitter::onScroll(
+ const ScrollViewMetrics &scrollViewMetrics) const {
dispatchScrollViewEvent("scroll", scrollViewMetrics);
}
-void ScrollViewEventEmitter::onScrollBeginDrag(const ScrollViewMetrics &scrollViewMetrics) const {
+void ScrollViewEventEmitter::onScrollBeginDrag(
+ const ScrollViewMetrics &scrollViewMetrics) const {
dispatchScrollViewEvent("scrollBeginDrag", scrollViewMetrics);
}
-void ScrollViewEventEmitter::onScrollEndDrag(const ScrollViewMetrics &scrollViewMetrics) const {
+void ScrollViewEventEmitter::onScrollEndDrag(
+ const ScrollViewMetrics &scrollViewMetrics) const {
dispatchScrollViewEvent("scrollEndDrag", scrollViewMetrics);
}
-void ScrollViewEventEmitter::onMomentumScrollBegin(const ScrollViewMetrics &scrollViewMetrics) const {
+void ScrollViewEventEmitter::onMomentumScrollBegin(
+ const ScrollViewMetrics &scrollViewMetrics) const {
dispatchScrollViewEvent("momentumScrollBegin", scrollViewMetrics);
}
-void ScrollViewEventEmitter::onMomentumScrollEnd(const ScrollViewMetrics &scrollViewMetrics) const {
+void ScrollViewEventEmitter::onMomentumScrollEnd(
+ const ScrollViewMetrics &scrollViewMetrics) const {
dispatchScrollViewEvent("momentumScrollEnd", scrollViewMetrics);
}
-void ScrollViewEventEmitter::dispatchScrollViewEvent(const std::string &name, const ScrollViewMetrics &scrollViewMetrics, const folly::dynamic &payload) const {
- folly::dynamic compoundPayload = folly::dynamic::object();
-
- compoundPayload["contentOffset"] = folly::dynamic::object
- ("x", scrollViewMetrics.contentOffset.x)
- ("y", scrollViewMetrics.contentOffset.y);
-
- compoundPayload["contentInset"] = folly::dynamic::object
- ("top", scrollViewMetrics.contentInset.top)
- ("left", scrollViewMetrics.contentInset.left)
- ("bottom", scrollViewMetrics.contentInset.bottom)
- ("right", scrollViewMetrics.contentInset.right);
-
- compoundPayload["contentSize"] = folly::dynamic::object
- ("width", scrollViewMetrics.contentSize.width)
- ("height", scrollViewMetrics.contentSize.height);
-
- compoundPayload["layoutMeasurement"] = folly::dynamic::object
- ("width", scrollViewMetrics.containerSize.width)
- ("height", scrollViewMetrics.containerSize.height);
-
- compoundPayload["zoomScale"] = scrollViewMetrics.zoomScale;
-
- if (!payload.isNull()) {
- compoundPayload.merge_patch(payload);
- }
-
- dispatchEvent(name, compoundPayload);
+void ScrollViewEventEmitter::dispatchScrollViewEvent(
+ const std::string &name,
+ const ScrollViewMetrics &scrollViewMetrics,
+ EventPriority priority) const {
+ dispatchEvent(
+ name,
+ [scrollViewMetrics](jsi::Runtime &runtime) {
+ return scrollViewMetricsPayload(runtime, scrollViewMetrics);
+ },
+ priority);
}
} // namespace react

ReactCommon/fabric/components/scrollview/ScrollViewEventEmitter.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -8,16 +8,16 @@
#include <memory>
-#include <fabric/components/view/ViewEventEmitter.h>
-#include <fabric/events/EventEmitter.h>
-#include <fabric/graphics/Geometry.h>
#include <folly/dynamic.h>
+#include <react/components/view/ViewEventEmitter.h>
+#include <react/events/EventEmitter.h>
+#include <react/graphics/Geometry.h>
namespace facebook {
namespace react {
class ScrollViewMetrics {
-public:
+ public:
Size contentSize;
Point contentOffset;
EdgeInsets contentInset;
@@ -27,13 +27,11 @@
class ScrollViewEventEmitter;
-using SharedScrollViewEventEmitter = std::shared_ptr<const ScrollViewEventEmitter>;
-
-class ScrollViewEventEmitter:
- public ViewEventEmitter {
-
-public:
+using SharedScrollViewEventEmitter =
+ std::shared_ptr<const ScrollViewEventEmitter>;
+class ScrollViewEventEmitter : public ViewEventEmitter {
+ public:
using ViewEventEmitter::ViewEventEmitter;
void onScroll(const ScrollViewMetrics &scrollViewMetrics) const;
@@ -42,9 +40,11 @@
void onMomentumScrollBegin(const ScrollViewMetrics &scrollViewMetrics) const;
void onMomentumScrollEnd(const ScrollViewMetrics &scrollViewMetrics) const;
-private:
-
- void dispatchScrollViewEvent(const std::string &name, const ScrollViewMetrics &scrollViewMetrics, const folly::dynamic &payload = {}) const;
+ private:
+ void dispatchScrollViewEvent(
+ const std::string &name,
+ const ScrollViewMetrics &scrollViewMetrics,
+ EventPriority priority = EventPriority::AsynchronousBatched) const;
};
} // namespace react

ReactCommon/fabric/components/scrollview/ScrollViewLocalData.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,30 +7,31 @@
#include "ScrollViewLocalData.h"
-#include <fabric/debug/debugStringConvertibleUtils.h>
-#include <fabric/graphics/conversions.h>
+#include <react/debug/debugStringConvertibleUtils.h>
+#include <react/graphics/conversions.h>
namespace facebook {
namespace react {
-ScrollViewLocalData::ScrollViewLocalData(Rect contentBoundingRect):
- contentBoundingRect(contentBoundingRect) {}
+ScrollViewLocalData::ScrollViewLocalData(Rect contentBoundingRect)
+ : contentBoundingRect(contentBoundingRect) {}
Size ScrollViewLocalData::getContentSize() const {
- return Size {contentBoundingRect.getMaxX(), contentBoundingRect.getMaxY()};
+ return Size{contentBoundingRect.getMaxX(), contentBoundingRect.getMaxY()};
}
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
std::string ScrollViewLocalData::getDebugName() const {
return "ScrollViewLocalData";
}
SharedDebugStringConvertibleList ScrollViewLocalData::getDebugProps() const {
return {
- debugStringConvertibleItem("contentBoundingRect", contentBoundingRect)
- };
+ debugStringConvertibleItem("contentBoundingRect", contentBoundingRect)};
}
+#endif
} // namespace react
} // namespace facebook

ReactCommon/fabric/components/scrollview/ScrollViewLocalData.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,8 +7,8 @@
#pragma once
-#include <fabric/core/LocalData.h>
-#include <fabric/graphics/Geometry.h>
+#include <react/core/LocalData.h>
+#include <react/graphics/Geometry.h>
namespace facebook {
namespace react {
@@ -20,10 +20,8 @@
/*
* LocalData for <ScrollView> component.
*/
-class ScrollViewLocalData:
- public LocalData {
-
-public:
+class ScrollViewLocalData : public LocalData {
+ public:
ScrollViewLocalData(Rect contentBoundingRect);
/*
@@ -38,8 +36,10 @@
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
std::string getDebugName() const override;
SharedDebugStringConvertibleList getDebugProps() const override;
+#endif
};
} // namespace react

ReactCommon/fabric/components/scrollview/ScrollViewProps.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,78 +7,226 @@
#include "ScrollViewProps.h"
-#include <fabric/components/scrollview/conversions.h>
-#include <fabric/debug/debugStringConvertibleUtils.h>
-#include <fabric/graphics/conversions.h>
+#include <react/components/scrollview/conversions.h>
+#include <react/debug/debugStringConvertibleUtils.h>
+#include <react/graphics/conversions.h>
-#include <fabric/core/propsConversions.h>
+#include <react/core/propsConversions.h>
namespace facebook {
namespace react {
-ScrollViewProps::ScrollViewProps(const ScrollViewProps &sourceProps, const RawProps &rawProps):
- ViewProps(sourceProps, rawProps),
- alwaysBounceHorizontal(convertRawProp(rawProps, "alwaysBounceHorizontal", sourceProps.alwaysBounceHorizontal, true)),
- alwaysBounceVertical(convertRawProp(rawProps, "alwaysBounceVertical", sourceProps.alwaysBounceVertical, true)),
+ScrollViewProps::ScrollViewProps(
+ const ScrollViewProps &sourceProps,
+ const RawProps &rawProps)
+ : ViewProps(sourceProps, rawProps),
+ alwaysBounceHorizontal(convertRawProp(
+ rawProps,
+ "alwaysBounceHorizontal",
+ sourceProps.alwaysBounceHorizontal)),
+ alwaysBounceVertical(convertRawProp(
+ rawProps,
+ "alwaysBounceVertical",
+ sourceProps.alwaysBounceVertical)),
bounces(convertRawProp(rawProps, "bounces", sourceProps.bounces, true)),
- bouncesZoom(convertRawProp(rawProps, "bouncesZoom", sourceProps.bouncesZoom, true)),
- canCancelContentTouches(convertRawProp(rawProps, "canCancelContentTouches", sourceProps.canCancelContentTouches)),
- centerContent(convertRawProp(rawProps, "centerContent", sourceProps.centerContent)),
- automaticallyAdjustContentInsets(convertRawProp(rawProps, "automaticallyAdjustContentInsets", sourceProps.automaticallyAdjustContentInsets)),
- decelerationRate(convertRawProp(rawProps, "decelerationRate", sourceProps.decelerationRate, (Float)0.998)),
- directionalLockEnabled(convertRawProp(rawProps, "directionalLockEnabled", sourceProps.directionalLockEnabled)),
- indicatorStyle(convertRawProp(rawProps, "indicatorStyle", sourceProps.indicatorStyle)),
- keyboardDismissMode(convertRawProp(rawProps, "keyboardDismissMode", sourceProps.keyboardDismissMode)),
- maximumZoomScale(convertRawProp(rawProps, "maximumZoomScale", sourceProps.maximumZoomScale, (Float)1.0)),
- minimumZoomScale(convertRawProp(rawProps, "minimumZoomScale", sourceProps.minimumZoomScale, (Float)1.0)),
- scrollEnabled(convertRawProp(rawProps, "scrollEnabled", sourceProps.scrollEnabled, true)),
- pagingEnabled(convertRawProp(rawProps, "pagingEnabled", sourceProps.pagingEnabled)),
- pinchGestureEnabled(convertRawProp(rawProps, "pinchGestureEnabled", sourceProps.pinchGestureEnabled, true)),
- scrollsToTop(convertRawProp(rawProps, "scrollsToTop", sourceProps.scrollsToTop, true)),
- showsHorizontalScrollIndicator(convertRawProp(rawProps, "showsHorizontalScrollIndicator", sourceProps.showsHorizontalScrollIndicator, true)),
- showsVerticalScrollIndicator(convertRawProp(rawProps, "showsVerticalScrollIndicator", sourceProps.showsVerticalScrollIndicator, true)),
- scrollEventThrottle(convertRawProp(rawProps, "scrollEventThrottle", sourceProps.scrollEventThrottle)),
- zoomScale(convertRawProp(rawProps, "zoomScale", sourceProps.zoomScale, (Float)1.0)),
- contentInset(convertRawProp(rawProps, "contentInset", sourceProps.contentInset)),
- scrollIndicatorInsets(convertRawProp(rawProps, "scrollIndicatorInsets", sourceProps.scrollIndicatorInsets)),
- snapToInterval(convertRawProp(rawProps, "snapToInterval", sourceProps.snapToInterval)),
- snapToAlignment(convertRawProp(rawProps, "snapToAlignment", sourceProps.snapToAlignment)) {}
+ bouncesZoom(convertRawProp(
+ rawProps,
+ "bouncesZoom",
+ sourceProps.bouncesZoom,
+ true)),
+ canCancelContentTouches(convertRawProp(
+ rawProps,
+ "canCancelContentTouches",
+ sourceProps.canCancelContentTouches)),
+ centerContent(
+ convertRawProp(rawProps, "centerContent", sourceProps.centerContent)),
+ automaticallyAdjustContentInsets(convertRawProp(
+ rawProps,
+ "automaticallyAdjustContentInsets",
+ sourceProps.automaticallyAdjustContentInsets)),
+ decelerationRate(convertRawProp(
+ rawProps,
+ "decelerationRate",
+ sourceProps.decelerationRate,
+ (Float)0.998)),
+ directionalLockEnabled(convertRawProp(
+ rawProps,
+ "directionalLockEnabled",
+ sourceProps.directionalLockEnabled)),
+ indicatorStyle(convertRawProp(
+ rawProps,
+ "indicatorStyle",
+ sourceProps.indicatorStyle)),
+ keyboardDismissMode(convertRawProp(
+ rawProps,
+ "keyboardDismissMode",
+ sourceProps.keyboardDismissMode)),
+ maximumZoomScale(convertRawProp(
+ rawProps,
+ "maximumZoomScale",
+ sourceProps.maximumZoomScale,
+ (Float)1.0)),
+ minimumZoomScale(convertRawProp(
+ rawProps,
+ "minimumZoomScale",
+ sourceProps.minimumZoomScale,
+ (Float)1.0)),
+ scrollEnabled(convertRawProp(
+ rawProps,
+ "scrollEnabled",
+ sourceProps.scrollEnabled,
+ true)),
+ pagingEnabled(
+ convertRawProp(rawProps, "pagingEnabled", sourceProps.pagingEnabled)),
+ pinchGestureEnabled(convertRawProp(
+ rawProps,
+ "pinchGestureEnabled",
+ sourceProps.pinchGestureEnabled,
+ true)),
+ scrollsToTop(convertRawProp(
+ rawProps,
+ "scrollsToTop",
+ sourceProps.scrollsToTop,
+ true)),
+ showsHorizontalScrollIndicator(convertRawProp(
+ rawProps,
+ "showsHorizontalScrollIndicator",
+ sourceProps.showsHorizontalScrollIndicator,
+ true)),
+ showsVerticalScrollIndicator(convertRawProp(
+ rawProps,
+ "showsVerticalScrollIndicator",
+ sourceProps.showsVerticalScrollIndicator,
+ true)),
+ scrollEventThrottle(convertRawProp(
+ rawProps,
+ "scrollEventThrottle",
+ sourceProps.scrollEventThrottle)),
+ zoomScale(convertRawProp(
+ rawProps,
+ "zoomScale",
+ sourceProps.zoomScale,
+ (Float)1.0)),
+ contentInset(
+ convertRawProp(rawProps, "contentInset", sourceProps.contentInset)),
+ scrollIndicatorInsets(convertRawProp(
+ rawProps,
+ "scrollIndicatorInsets",
+ sourceProps.scrollIndicatorInsets)),
+ snapToInterval(convertRawProp(
+ rawProps,
+ "snapToInterval",
+ sourceProps.snapToInterval)),
+ snapToAlignment(convertRawProp(
+ rawProps,
+ "snapToAlignment",
+ sourceProps.snapToAlignment)) {}
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList ScrollViewProps::getDebugProps() const {
- ScrollViewProps defaultScrollViewProps;
+ auto defaultScrollViewProps = ScrollViewProps{};
- return
- ViewProps::getDebugProps() +
- SharedDebugStringConvertibleList {
- debugStringConvertibleItem("alwaysBounceHorizontal", alwaysBounceHorizontal, defaultScrollViewProps.alwaysBounceHorizontal),
- debugStringConvertibleItem("alwaysBounceVertical", alwaysBounceVertical, defaultScrollViewProps.alwaysBounceVertical),
- debugStringConvertibleItem("bounces", bounces, defaultScrollViewProps.bounces),
- debugStringConvertibleItem("bouncesZoom", bouncesZoom, defaultScrollViewProps.bouncesZoom),
- debugStringConvertibleItem("canCancelContentTouches", canCancelContentTouches, defaultScrollViewProps.canCancelContentTouches),
- debugStringConvertibleItem("centerContent", centerContent, defaultScrollViewProps.centerContent),
- debugStringConvertibleItem("automaticallyAdjustContentInsets", automaticallyAdjustContentInsets, defaultScrollViewProps.automaticallyAdjustContentInsets),
- debugStringConvertibleItem("decelerationRate", decelerationRate, defaultScrollViewProps.decelerationRate),
- debugStringConvertibleItem("directionalLockEnabled", directionalLockEnabled, defaultScrollViewProps.directionalLockEnabled),
- debugStringConvertibleItem("indicatorStyle", indicatorStyle, defaultScrollViewProps.indicatorStyle),
- debugStringConvertibleItem("keyboardDismissMode", keyboardDismissMode, defaultScrollViewProps.keyboardDismissMode),
- debugStringConvertibleItem("maximumZoomScale", maximumZoomScale, defaultScrollViewProps.maximumZoomScale),
- debugStringConvertibleItem("minimumZoomScale", minimumZoomScale, defaultScrollViewProps.minimumZoomScale),
- debugStringConvertibleItem("scrollEnabled", scrollEnabled, defaultScrollViewProps.scrollEnabled),
- debugStringConvertibleItem("pagingEnabled", pagingEnabled, defaultScrollViewProps.pagingEnabled),
- debugStringConvertibleItem("pinchGestureEnabled", pinchGestureEnabled, defaultScrollViewProps.pinchGestureEnabled),
- debugStringConvertibleItem("scrollsToTop", scrollsToTop, defaultScrollViewProps.scrollsToTop),
- debugStringConvertibleItem("showsHorizontalScrollIndicator", showsHorizontalScrollIndicator, defaultScrollViewProps.showsHorizontalScrollIndicator),
- debugStringConvertibleItem("showsVerticalScrollIndicator", showsVerticalScrollIndicator, defaultScrollViewProps.showsVerticalScrollIndicator),
- debugStringConvertibleItem("scrollEventThrottle", scrollEventThrottle, defaultScrollViewProps.scrollEventThrottle),
- debugStringConvertibleItem("zoomScale", zoomScale, defaultScrollViewProps.zoomScale),
- debugStringConvertibleItem("contentInset", contentInset, defaultScrollViewProps.contentInset),
- debugStringConvertibleItem("scrollIndicatorInsets", scrollIndicatorInsets, defaultScrollViewProps.scrollIndicatorInsets),
- debugStringConvertibleItem("snapToInterval", snapToInterval, defaultScrollViewProps.snapToInterval),
- debugStringConvertibleItem("snapToAlignment", snapToAlignment, defaultScrollViewProps.snapToAlignment),
+ return ViewProps::getDebugProps() +
+ SharedDebugStringConvertibleList{
+ debugStringConvertibleItem(
+ "alwaysBounceHorizontal",
+ alwaysBounceHorizontal,
+ defaultScrollViewProps.alwaysBounceHorizontal),
+ debugStringConvertibleItem(
+ "alwaysBounceVertical",
+ alwaysBounceVertical,
+ defaultScrollViewProps.alwaysBounceVertical),
+ debugStringConvertibleItem(
+ "bounces", bounces, defaultScrollViewProps.bounces),
+ debugStringConvertibleItem(
+ "bouncesZoom", bouncesZoom, defaultScrollViewProps.bouncesZoom),
+ debugStringConvertibleItem(
+ "canCancelContentTouches",
+ canCancelContentTouches,
+ defaultScrollViewProps.canCancelContentTouches),
+ debugStringConvertibleItem(
+ "centerContent",
+ centerContent,
+ defaultScrollViewProps.centerContent),
+ debugStringConvertibleItem(
+ "automaticallyAdjustContentInsets",
+ automaticallyAdjustContentInsets,
+ defaultScrollViewProps.automaticallyAdjustContentInsets),
+ debugStringConvertibleItem(
+ "decelerationRate",
+ decelerationRate,
+ defaultScrollViewProps.decelerationRate),
+ debugStringConvertibleItem(
+ "directionalLockEnabled",
+ directionalLockEnabled,
+ defaultScrollViewProps.directionalLockEnabled),
+ debugStringConvertibleItem(
+ "indicatorStyle",
+ indicatorStyle,
+ defaultScrollViewProps.indicatorStyle),
+ debugStringConvertibleItem(
+ "keyboardDismissMode",
+ keyboardDismissMode,
+ defaultScrollViewProps.keyboardDismissMode),
+ debugStringConvertibleItem(
+ "maximumZoomScale",
+ maximumZoomScale,
+ defaultScrollViewProps.maximumZoomScale),
+ debugStringConvertibleItem(
+ "minimumZoomScale",
+ minimumZoomScale,
+ defaultScrollViewProps.minimumZoomScale),
+ debugStringConvertibleItem(
+ "scrollEnabled",
+ scrollEnabled,
+ defaultScrollViewProps.scrollEnabled),
+ debugStringConvertibleItem(
+ "pagingEnabled",
+ pagingEnabled,
+ defaultScrollViewProps.pagingEnabled),
+ debugStringConvertibleItem(
+ "pinchGestureEnabled",
+ pinchGestureEnabled,
+ defaultScrollViewProps.pinchGestureEnabled),
+ debugStringConvertibleItem(
+ "scrollsToTop",
+ scrollsToTop,
+ defaultScrollViewProps.scrollsToTop),
+ debugStringConvertibleItem(
+ "showsHorizontalScrollIndicator",
+ showsHorizontalScrollIndicator,
+ defaultScrollViewProps.showsHorizontalScrollIndicator),
+ debugStringConvertibleItem(
+ "showsVerticalScrollIndicator",
+ showsVerticalScrollIndicator,
+ defaultScrollViewProps.showsVerticalScrollIndicator),
+ debugStringConvertibleItem(
+ "scrollEventThrottle",
+ scrollEventThrottle,
+ defaultScrollViewProps.scrollEventThrottle),
+ debugStringConvertibleItem(
+ "zoomScale", zoomScale, defaultScrollViewProps.zoomScale),
+ debugStringConvertibleItem(
+ "contentInset",
+ contentInset,
+ defaultScrollViewProps.contentInset),
+ debugStringConvertibleItem(
+ "scrollIndicatorInsets",
+ scrollIndicatorInsets,
+ defaultScrollViewProps.scrollIndicatorInsets),
+ debugStringConvertibleItem(
+ "snapToInterval",
+ snapToInterval,
+ defaultScrollViewProps.snapToInterval),
+ debugStringConvertibleItem(
+ "snapToAlignment",
+ snapToAlignment,
+ defaultScrollViewProps.snapToAlignment),
};
}
+#endif
} // namespace react
} // namespace facebook

ReactCommon/fabric/components/scrollview/ScrollViewProps.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,51 +7,51 @@
#pragma once
-#include <fabric/components/scrollview/primitives.h>
-#include <fabric/components/view/ViewProps.h>
+#include <react/components/scrollview/primitives.h>
+#include <react/components/view/ViewProps.h>
namespace facebook {
namespace react {
// TODO (T28334063): Consider for codegen.
-class ScrollViewProps final:
- public ViewProps {
-
-public:
+class ScrollViewProps final : public ViewProps {
+ public:
ScrollViewProps() = default;
ScrollViewProps(const ScrollViewProps &sourceProps, const RawProps &rawProps);
#pragma mark - Props
- const bool alwaysBounceHorizontal {true};
- const bool alwaysBounceVertical {true};
- const bool bounces {true};
- const bool bouncesZoom {true};
- const bool canCancelContentTouches {true};
- const bool centerContent {};
- const bool automaticallyAdjustContentInsets {};
- const Float decelerationRate {0.998};
- const bool directionalLockEnabled {};
- const ScrollViewIndicatorStyle indicatorStyle {};
- const ScrollViewKeyboardDismissMode keyboardDismissMode {};
- const Float maximumZoomScale {1.0};
- const Float minimumZoomScale {1.0};
- const bool scrollEnabled {true};
- const bool pagingEnabled {};
- const bool pinchGestureEnabled {true};
- const bool scrollsToTop {true};
- const bool showsHorizontalScrollIndicator {true};
- const bool showsVerticalScrollIndicator {true};
- const Float scrollEventThrottle {};
- const Float zoomScale {1.0};
- const EdgeInsets contentInset {};
- const EdgeInsets scrollIndicatorInsets {};
- const int snapToInterval {};
- const ScrollViewSnapToAlignment snapToAlignment {};
+ const bool alwaysBounceHorizontal{};
+ const bool alwaysBounceVertical{};
+ const bool bounces{true};
+ const bool bouncesZoom{true};
+ const bool canCancelContentTouches{true};
+ const bool centerContent{};
+ const bool automaticallyAdjustContentInsets{};
+ const Float decelerationRate{0.998};
+ const bool directionalLockEnabled{};
+ const ScrollViewIndicatorStyle indicatorStyle{};
+ const ScrollViewKeyboardDismissMode keyboardDismissMode{};
+ const Float maximumZoomScale{1.0};
+ const Float minimumZoomScale{1.0};
+ const bool scrollEnabled{true};
+ const bool pagingEnabled{};
+ const bool pinchGestureEnabled{true};
+ const bool scrollsToTop{true};
+ const bool showsHorizontalScrollIndicator{true};
+ const bool showsVerticalScrollIndicator{true};
+ const Float scrollEventThrottle{};
+ const Float zoomScale{1.0};
+ const EdgeInsets contentInset{};
+ const EdgeInsets scrollIndicatorInsets{};
+ const int snapToInterval{};
+ const ScrollViewSnapToAlignment snapToAlignment{};
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList getDebugProps() const override;
+#endif
};
} // namespace react

ReactCommon/fabric/components/scrollview/ScrollViewShadowNode.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,7 +7,7 @@
#include "ScrollViewShadowNode.h"
-#include <fabric/core/LayoutMetrics.h>
+#include <react/core/LayoutMetrics.h>
#include "ScrollViewLocalData.h"
@@ -19,12 +19,13 @@
void ScrollViewShadowNode::updateLocalData() {
ensureUnsealed();
- Rect contentBoundingRect;
+ auto contentBoundingRect = Rect{};
for (const auto &childNode : getLayoutableChildNodes()) {
contentBoundingRect.unionInPlace(childNode->getLayoutMetrics().frame);
}
- const auto &localData = std::make_shared<const ScrollViewLocalData>(contentBoundingRect);
+ const auto &localData =
+ std::make_shared<const ScrollViewLocalData>(contentBoundingRect);
setLocalData(localData);
}

ReactCommon/fabric/components/scrollview/ScrollViewShadowNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,10 +7,10 @@
#pragma once
-#include <fabric/components/scrollview/ScrollViewEventEmitter.h>
-#include <fabric/components/scrollview/ScrollViewProps.h>
-#include <fabric/components/view/ConcreteViewShadowNode.h>
-#include <fabric/core/LayoutContext.h>
+#include <react/components/scrollview/ScrollViewEventEmitter.h>
+#include <react/components/scrollview/ScrollViewProps.h>
+#include <react/components/view/ConcreteViewShadowNode.h>
+#include <react/core/LayoutContext.h>
namespace facebook {
namespace react {
@@ -20,23 +20,18 @@
/*
* `ShadowNode` for <ScrollView> component.
*/
-class ScrollViewShadowNode final:
- public ConcreteViewShadowNode<
+class ScrollViewShadowNode final : public ConcreteViewShadowNode<
ScrollViewComponentName,
ScrollViewProps,
- ScrollViewEventEmitter
- > {
-
-public:
-
+ ScrollViewEventEmitter> {
+ public:
using ConcreteViewShadowNode::ConcreteViewShadowNode;
#pragma mark - LayoutableShadowNode
void layout(LayoutContext layoutContext) override;
-private:
-
+ private:
void updateLocalData();
};

ReactCommon/fabric/components/scrollview/tests/ScrollViewTest.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactCommon/fabric/components/slider/BUCK

@@ -0,0 +1,79 @@
+load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags")
+load(
+ "//tools/build_defs/oss:rn_defs.bzl",
+ "ANDROID",
+ "APPLE",
+ "fb_xplat_cxx_test",
+ "get_apple_compiler_flags",
+ "get_apple_inspector_flags",
+ "react_native_xplat_target",
+ "rn_xplat_cxx_library",
+ "subdir_glob",
+)
+
+APPLE_COMPILER_FLAGS = get_apple_compiler_flags()
+
+rn_xplat_cxx_library(
+ name = "slider",
+ srcs = glob(
+ ["**/*.cpp"],
+ exclude = glob(["tests/**/*.cpp"]),
+ ),
+ headers = [],
+ header_namespace = "",
+ exported_headers = subdir_glob(
+ [
+ ("", "*.h"),
+ ],
+ prefix = "react/components/slider",
+ ),
+ compiler_flags = [
+ "-fexceptions",
+ "-frtti",
+ "-std=c++14",
+ "-Wall",
+ ],
+ fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
+ fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
+ macosx_tests_override = [],
+ platforms = (ANDROID, APPLE),
+ preprocessor_flags = [
+ "-DLOG_TAG=\"ReactNative\"",
+ "-DWITH_FBSYSTRACE=1",
+ ],
+ tests = [":tests"],
+ visibility = ["PUBLIC"],
+ deps = [
+ "xplat//fbsystrace:fbsystrace",
+ "xplat//folly:headers_only",
+ "xplat//folly:memory",
+ "xplat//folly:molly",
+ "xplat//third-party/glog:glog",
+ "xplat//yoga:yoga",
+ react_native_xplat_target("fabric/debug:debug"),
+ react_native_xplat_target("fabric/core:core"),
+ react_native_xplat_target("fabric/components/image:image"),
+ react_native_xplat_target("fabric/components/view:view"),
+ react_native_xplat_target("fabric/graphics:graphics"),
+ react_native_xplat_target("fabric/imagemanager:imagemanager"),
+ ],
+)
+
+fb_xplat_cxx_test(
+ name = "tests",
+ srcs = glob(["tests/**/*.cpp"]),
+ headers = glob(["tests/**/*.h"]),
+ compiler_flags = [
+ "-fexceptions",
+ "-frtti",
+ "-std=c++14",
+ "-Wall",
+ ],
+ contacts = ["oncall+react_native@xmail.facebook.com"],
+ platforms = (ANDROID, APPLE),
+ deps = [
+ "xplat//folly:molly",
+ "xplat//third-party/gmock:gtest",
+ ":slider",
+ ],
+)

ReactCommon/fabric/components/slider/SliderComponentDescriptor.h

@@ -0,0 +1,49 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <react/components/slider/SliderShadowNode.h>
+#include <react/core/ConcreteComponentDescriptor.h>
+
+namespace facebook {
+namespace react {
+
+/*
+ * Descriptor for <Slider> component.
+ */
+class SliderComponentDescriptor final
+ : public ConcreteComponentDescriptor<SliderShadowNode> {
+ public:
+ SliderComponentDescriptor(
+ SharedEventDispatcher eventDispatcher,
+ const SharedContextContainer &contextContainer)
+ : ConcreteComponentDescriptor(eventDispatcher),
+ imageManager_(
+ contextContainer
+ ? contextContainer->getInstance<SharedImageManager>(
+ "ImageManager")
+ : nullptr) {}
+
+ void adopt(UnsharedShadowNode shadowNode) const override {
+ ConcreteComponentDescriptor::adopt(shadowNode);
+
+ assert(std::dynamic_pointer_cast<SliderShadowNode>(shadowNode));
+ auto sliderShadowNode =
+ std::static_pointer_cast<SliderShadowNode>(shadowNode);
+
+ // `SliderShadowNode` uses `ImageManager` to initiate image loading and
+ // communicate the loading state and results to mounting layer.
+ sliderShadowNode->setImageManager(imageManager_);
+ }
+
+ private:
+ const SharedImageManager imageManager_;
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/components/slider/SliderEventEmitter.cpp

@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include "SliderEventEmitter.h"
+
+namespace facebook {
+namespace react {
+
+void SliderEventEmitter::onValueChange(float value) const {
+ dispatchEvent("valueChange", [value](jsi::Runtime &runtime) {
+ auto payload = jsi::Object(runtime);
+ payload.setProperty(runtime, "value", value);
+ return payload;
+ });
+}
+
+void SliderEventEmitter::onSlidingComplete(float value) const {
+ dispatchEvent("slidingComplete", [value](jsi::Runtime &runtime) {
+ auto payload = jsi::Object(runtime);
+ payload.setProperty(runtime, "value", value);
+ return payload;
+ });
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/components/slider/SliderEventEmitter.h

@@ -0,0 +1,23 @@
+/**
+ * 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.
+ */
+#pragma once
+
+#include <react/components/view/ViewEventEmitter.h>
+
+namespace facebook {
+namespace react {
+
+class SliderEventEmitter : public ViewEventEmitter {
+ public:
+ using ViewEventEmitter::ViewEventEmitter;
+
+ void onValueChange(float value) const;
+ void onSlidingComplete(float value) const;
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/components/slider/SliderLocalData.cpp

@@ -0,0 +1,68 @@
+/**
+ * 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.
+ */
+
+#include "SliderLocalData.h"
+
+#include <react/components/image/conversions.h>
+#include <react/debug/debugStringConvertibleUtils.h>
+
+namespace facebook {
+namespace react {
+
+ImageSource SliderLocalData::getTrackImageSource() const {
+ return trackImageSource_;
+}
+
+const ImageRequest &SliderLocalData::getTrackImageRequest() const {
+ return trackImageRequest_;
+}
+
+ImageSource SliderLocalData::getMinimumTrackImageSource() const {
+ return minimumTrackImageSource_;
+}
+
+const ImageRequest &SliderLocalData::getMinimumTrackImageRequest() const {
+ return minimumTrackImageRequest_;
+}
+
+ImageSource SliderLocalData::getMaximumTrackImageSource() const {
+ return maximumTrackImageSource_;
+}
+
+const ImageRequest &SliderLocalData::getMaximumTrackImageRequest() const {
+ return maximumTrackImageRequest_;
+}
+
+ImageSource SliderLocalData::getThumbImageSource() const {
+ return thumbImageSource_;
+}
+
+const ImageRequest &SliderLocalData::getThumbImageRequest() const {
+ return thumbImageRequest_;
+}
+
+#pragma mark - DebugStringConvertible
+
+#if RN_DEBUG_STRING_CONVERTIBLE
+std::string SliderLocalData::getDebugName() const {
+ return "SliderLocalData";
+}
+
+SharedDebugStringConvertibleList SliderLocalData::getDebugProps() const {
+ return {
+ debugStringConvertibleItem("trackImageSource", trackImageSource_),
+ debugStringConvertibleItem(
+ "minimumTrackImageSource", minimumTrackImageSource_),
+ debugStringConvertibleItem(
+ "maximumTrackImageSource", maximumTrackImageSource_),
+ debugStringConvertibleItem("thumbImageSource", thumbImageSource_),
+ };
+}
+#endif
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/components/slider/SliderLocalData.h

@@ -0,0 +1,108 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <react/core/LocalData.h>
+#include <react/imagemanager/ImageRequest.h>
+#include <react/imagemanager/primitives.h>
+
+namespace facebook {
+namespace react {
+
+class SliderLocalData;
+
+using SharedSliderLocalData = std::shared_ptr<const SliderLocalData>;
+
+/*
+ * LocalData for <Slider> component.
+ * Represents the image request state and (possible) retrieved image bitmap.
+ */
+class SliderLocalData : public LocalData {
+ public:
+ SliderLocalData(
+ const ImageSource &trackImageSource,
+ ImageRequest trackImageRequest,
+ const ImageSource &minimumTrackImageSource,
+ ImageRequest minimumTrackImageRequest,
+ const ImageSource &maximumTrackImageSource,
+ ImageRequest maximumTrackImageRequest,
+ const ImageSource &thumbImageSource,
+ ImageRequest thumbImageRequest)
+ : trackImageSource_(trackImageSource),
+ trackImageRequest_(std::move(trackImageRequest)),
+ minimumTrackImageSource_(minimumTrackImageSource),
+ minimumTrackImageRequest_(std::move(minimumTrackImageRequest)),
+ maximumTrackImageSource_(maximumTrackImageSource),
+ maximumTrackImageRequest_(std::move(maximumTrackImageRequest)),
+ thumbImageSource_(thumbImageSource),
+ thumbImageRequest_(std::move(thumbImageRequest)){};
+
+ /*
+ * Returns stored ImageSource object.
+ */
+ ImageSource getTrackImageSource() const;
+
+ /*
+ * Exposes for reading stored `ImageRequest` object.
+ * `ImageRequest` object cannot be copied or moved from `ImageLocalData`.
+ */
+ const ImageRequest &getTrackImageRequest() const;
+
+ /*
+ * Returns stored ImageSource object.
+ */
+ ImageSource getMinimumTrackImageSource() const;
+
+ /*
+ * Exposes for reading stored `ImageRequest` object.
+ * `ImageRequest` object cannot be copied or moved from `ImageLocalData`.
+ */
+ const ImageRequest &getMinimumTrackImageRequest() const;
+
+ /*
+ * Returns stored ImageSource object.
+ */
+ ImageSource getMaximumTrackImageSource() const;
+
+ /*
+ * Exposes for reading stored `ImageRequest` object.
+ * `ImageRequest` object cannot be copied or moved from `ImageLocalData`.
+ */
+ const ImageRequest &getMaximumTrackImageRequest() const;
+
+ /*
+ * Returns stored ImageSource object.
+ */
+ ImageSource getThumbImageSource() const;
+
+ /*
+ * Exposes for reading stored `ImageRequest` object.
+ * `ImageRequest` object cannot be copied or moved from `ImageLocalData`.
+ */
+ const ImageRequest &getThumbImageRequest() const;
+
+#pragma mark - DebugStringConvertible
+
+#if RN_DEBUG_STRING_CONVERTIBLE
+ std::string getDebugName() const override;
+ SharedDebugStringConvertibleList getDebugProps() const override;
+#endif
+
+ private:
+ ImageSource trackImageSource_;
+ ImageRequest trackImageRequest_;
+ ImageSource minimumTrackImageSource_;
+ ImageRequest minimumTrackImageRequest_;
+ ImageSource maximumTrackImageSource_;
+ ImageRequest maximumTrackImageRequest_;
+ ImageSource thumbImageSource_;
+ ImageRequest thumbImageRequest_;
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/components/slider/SliderProps.cpp

@@ -0,0 +1,70 @@
+/**
+ * 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.
+ */
+
+#include <react/components/slider/SliderProps.h>
+#include <react/components/image/conversions.h>
+#include <react/core/propsConversions.h>
+
+namespace facebook {
+namespace react {
+
+SliderProps::SliderProps(
+ const SliderProps &sourceProps,
+ const RawProps &rawProps)
+ : ViewProps(sourceProps, rawProps),
+ value(convertRawProp(rawProps, "value", sourceProps.value, value)),
+ minimumValue(convertRawProp(
+ rawProps,
+ "minimumValue",
+ sourceProps.minimumValue,
+ minimumValue)),
+ maximumValue(convertRawProp(
+ rawProps,
+ "maximumValue",
+ sourceProps.maximumValue,
+ maximumValue)),
+ step(convertRawProp(rawProps, "step", sourceProps.step, step)),
+ disabled(
+ convertRawProp(rawProps, "disabled", sourceProps.disabled, disabled)),
+ minimumTrackTintColor(convertRawProp(
+ rawProps,
+ "minimumTrackTintColor",
+ sourceProps.minimumTrackTintColor,
+ minimumTrackTintColor)),
+ maximumTrackTintColor(convertRawProp(
+ rawProps,
+ "maximumTrackTintColor",
+ sourceProps.maximumTrackTintColor,
+ maximumTrackTintColor)),
+ thumbTintColor(convertRawProp(
+ rawProps,
+ "thumbTintColor",
+ sourceProps.thumbTintColor,
+ thumbTintColor)),
+ trackImage(convertRawProp(
+ rawProps,
+ "trackImage",
+ sourceProps.trackImage,
+ trackImage)),
+ minimumTrackImage(convertRawProp(
+ rawProps,
+ "minimumTrackImage",
+ sourceProps.minimumTrackImage,
+ minimumTrackImage)),
+ maximumTrackImage(convertRawProp(
+ rawProps,
+ "maximumTrackImage",
+ sourceProps.maximumTrackImage,
+ maximumTrackImage)),
+ thumbImage(convertRawProp(
+ rawProps,
+ "thumbImage",
+ sourceProps.thumbImage,
+ thumbImage)) {}
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/components/slider/SliderProps.h

@@ -0,0 +1,44 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <react/components/view/ViewProps.h>
+#include <react/graphics/Color.h>
+#include <react/imagemanager/primitives.h>
+
+namespace facebook {
+namespace react {
+
+// TODO (T28334063): Consider for codegen.
+class SliderProps final : public ViewProps {
+ public:
+ SliderProps() = default;
+ SliderProps(const SliderProps &sourceProps, const RawProps &rawProps);
+
+#pragma mark - Props
+
+ const float value{0};
+ const float minimumValue{0};
+ const float maximumValue{1};
+ const float step{0};
+ const bool disabled{false};
+ const SharedColor minimumTrackTintColor{};
+ const SharedColor maximumTrackTintColor{};
+
+ // Android only
+ const SharedColor thumbTintColor;
+
+ // iOS only
+ const ImageSource trackImage{};
+ const ImageSource minimumTrackImage{};
+ const ImageSource maximumTrackImage{};
+ const ImageSource thumbImage{};
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/components/slider/SliderShadowNode.cpp

@@ -0,0 +1,95 @@
+/**
+ * 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.
+ */
+
+#include "SliderShadowNode.h"
+
+#include <react/components/slider/SliderLocalData.h>
+#include <react/components/slider/SliderShadowNode.h>
+#include <react/core/LayoutContext.h>
+
+namespace facebook {
+namespace react {
+
+extern const char SliderComponentName[] = "Slider";
+
+void SliderShadowNode::setImageManager(const SharedImageManager &imageManager) {
+ ensureUnsealed();
+ imageManager_ = imageManager;
+}
+
+void SliderShadowNode::updateLocalData() {
+ const auto &newTrackImageSource = getTrackImageSource();
+ const auto &newMinimumTrackImageSource = getMinimumTrackImageSource();
+ const auto &newMaximumTrackImageSource = getMaximumTrackImageSource();
+ const auto &newThumbImageSource = getThumbImageSource();
+
+ const auto &localData = getLocalData();
+ if (localData) {
+ assert(std::dynamic_pointer_cast<const SliderLocalData>(localData));
+ auto currentLocalData =
+ std::static_pointer_cast<const SliderLocalData>(localData);
+
+ auto trackImageSource = currentLocalData->getTrackImageSource();
+ auto minimumTrackImageSource =
+ currentLocalData->getMinimumTrackImageSource();
+ auto maximumTrackImageSource =
+ currentLocalData->getMaximumTrackImageSource();
+ auto thumbImageSource = currentLocalData->getThumbImageSource();
+
+ bool anyChanged = newTrackImageSource != trackImageSource ||
+ newMinimumTrackImageSource != minimumTrackImageSource ||
+ newMaximumTrackImageSource != maximumTrackImageSource ||
+ newThumbImageSource != thumbImageSource;
+
+ if (!anyChanged) {
+ return;
+ }
+ }
+
+ // Now we are about to mutate the Shadow Node.
+ ensureUnsealed();
+
+ // It is not possible to copy or move image requests from SliderLocalData,
+ // so instead we recreate any image requests (that may already be in-flight?)
+ // TODO: check if multiple requests are cached or if it's a net loss
+ const auto &newLocalData = std::make_shared<SliderLocalData>(
+ newTrackImageSource,
+ imageManager_->requestImage(newTrackImageSource),
+ newMinimumTrackImageSource,
+ imageManager_->requestImage(newMinimumTrackImageSource),
+ newMaximumTrackImageSource,
+ imageManager_->requestImage(newMaximumTrackImageSource),
+ newThumbImageSource,
+ imageManager_->requestImage(newThumbImageSource));
+ setLocalData(newLocalData);
+}
+
+ImageSource SliderShadowNode::getTrackImageSource() const {
+ return getProps()->trackImage;
+}
+
+ImageSource SliderShadowNode::getMinimumTrackImageSource() const {
+ return getProps()->minimumTrackImage;
+}
+
+ImageSource SliderShadowNode::getMaximumTrackImageSource() const {
+ return getProps()->maximumTrackImage;
+}
+
+ImageSource SliderShadowNode::getThumbImageSource() const {
+ return getProps()->thumbImage;
+}
+
+#pragma mark - LayoutableShadowNode
+
+void SliderShadowNode::layout(LayoutContext layoutContext) {
+ updateLocalData();
+ ConcreteViewShadowNode::layout(layoutContext);
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/components/slider/SliderShadowNode.h

@@ -0,0 +1,51 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <react/components/slider/SliderEventEmitter.h>
+#include <react/components/slider/SliderProps.h>
+#include <react/components/view/ConcreteViewShadowNode.h>
+#include <react/imagemanager/ImageManager.h>
+#include <react/imagemanager/primitives.h>
+
+namespace facebook {
+namespace react {
+
+extern const char SliderComponentName[];
+
+/*
+ * `ShadowNode` for <Slider> component.
+ */
+class SliderShadowNode final : public ConcreteViewShadowNode<
+ SliderComponentName,
+ SliderProps,
+ SliderEventEmitter> {
+ public:
+ using ConcreteViewShadowNode::ConcreteViewShadowNode;
+
+ // Associates a shared `ImageManager` with the node.
+ void setImageManager(const SharedImageManager &imageManager);
+
+#pragma mark - LayoutableShadowNode
+
+ void layout(LayoutContext layoutContext) override;
+
+ private:
+ // (Re)Creates a `LocalData` object (with `ImageRequest`) if needed.
+ void updateLocalData();
+
+ ImageSource getTrackImageSource() const;
+ ImageSource getMinimumTrackImageSource() const;
+ ImageSource getMaximumTrackImageSource() const;
+ ImageSource getThumbImageSource() const;
+
+ SharedImageManager imageManager_;
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/components/slider/tests/SliderTest.cpp

@@ -0,0 +1,14 @@
+/**
+ * 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.
+ */
+
+#include <memory>
+
+#include <gtest/gtest.h>
+
+TEST(SliderTest, testSomething) {
+ // TODO
+}

ReactCommon/fabric/components/switch/BUCK

@@ -1,80 +0,0 @@
-load("//configurations/buck/apple:flag_defs.bzl", "OBJC_ARC_PREPROCESSOR_FLAGS", "get_application_ios_flags", "get_debug_preprocessor_flags")
-load(
- "//tools/build_defs/oss:rn_defs.bzl",
- "ANDROID",
- "APPLE",
- "get_apple_compiler_flags",
- "subdir_glob",
- "get_apple_inspector_flags",
- "react_native_xplat_target",
- "fb_xplat_cxx_test",
- "rn_xplat_cxx_library",
-)
-
-APPLE_COMPILER_FLAGS = get_apple_compiler_flags()
-
-rn_xplat_cxx_library(
- name = "switch",
- srcs = glob(
- ["**/*.cpp"],
- exclude = glob(["tests/**/*.cpp"]),
- ),
- headers = [],
- header_namespace = "",
- exported_headers = subdir_glob(
- [
- ("", "*.h"),
- ],
- prefix = "fabric/components/switch",
- ),
- compiler_flags = [
- "-fexceptions",
- "-frtti",
- "-std=c++14",
- "-Wall",
- ],
- fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
- fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
- fbobjc_tests = [
- ":tests",
- ],
- macosx_tests_override = [],
- platforms = (ANDROID, APPLE),
- preprocessor_flags = [
- "-DLOG_TAG=\"ReactNative\"",
- "-DWITH_FBSYSTRACE=1",
- ],
- tests = [],
- visibility = ["PUBLIC"],
- deps = [
- "xplat//fbsystrace:fbsystrace",
- "xplat//folly:headers_only",
- "xplat//folly:memory",
- "xplat//folly:molly",
- "xplat//third-party/glog:glog",
- "xplat//yoga:yoga",
- react_native_xplat_target("fabric/debug:debug"),
- react_native_xplat_target("fabric/core:core"),
- react_native_xplat_target("fabric/graphics:graphics"),
- react_native_xplat_target("fabric/components/view:view"),
- ],
-)
-
-fb_xplat_cxx_test(
- name = "tests",
- srcs = glob(["tests/**/*.cpp"]),
- headers = glob(["tests/**/*.h"]),
- compiler_flags = [
- "-fexceptions",
- "-frtti",
- "-std=c++14",
- "-Wall",
- ],
- contacts = ["oncall+react_native@xmail.facebook.com"],
- platforms = APPLE,
- deps = [
- "xplat//folly:molly",
- "xplat//third-party/gmock:gtest",
- ":switch",
- ],
-)

ReactCommon/fabric/components/switch/SwitchComponentDescriptor.h

@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#pragma once
-
-#include <fabric/components/switch/SwitchShadowNode.h>
-#include <fabric/core/ConcreteComponentDescriptor.h>
-
-namespace facebook {
-namespace react {
-
-using SwitchComponentDescriptor = ConcreteComponentDescriptor<SwitchShadowNode>;
-
-} // namespace react
-} // namespace facebook

ReactCommon/fabric/components/switch/SwitchEventEmitter.cpp

@@ -1,18 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#include "SwitchEventEmitter.h"
-
-namespace facebook {
-namespace react {
-
-void SwitchEventEmitter::onChange(const bool &value) const {
- dispatchEvent("change", folly::dynamic::object("value", value));
-}
-
-} // namespace react
-} // namespace facebook

ReactCommon/fabric/components/switch/SwitchEventEmitter.h

@@ -1,25 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-#pragma once
-
-#include <fabric/components/view/ViewEventEmitter.h>
-
-namespace facebook {
-namespace react {
-
-class SwitchEventEmitter:
- public ViewEventEmitter {
-
-public:
-
- using ViewEventEmitter::ViewEventEmitter;
-
- void onChange(const bool &value) const;
-};
-
-} // namespace react
-} // namespace facebook

ReactCommon/fabric/components/switch/SwitchProps.cpp

@@ -1,23 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#include <fabric/components/switch/SwitchProps.h>
-#include <fabric/core/propsConversions.h>
-
-namespace facebook {
-namespace react {
-
-SwitchProps::SwitchProps(const SwitchProps &sourceProps, const RawProps &rawProps):
- ViewProps(sourceProps, rawProps),
- value(convertRawProp(rawProps, "value", sourceProps.value, value)),
- disabled(convertRawProp(rawProps, "disabled", sourceProps.disabled, disabled)),
- tintColor(convertRawProp(rawProps, "tintColor", sourceProps.tintColor, tintColor)),
- onTintColor(convertRawProp(rawProps, "onTintColor", sourceProps.onTintColor, onTintColor)),
- thumbTintColor(convertRawProp(rawProps, "thumbTintColor", sourceProps.thumbTintColor, thumbTintColor)) {}
-
-} // namespace react
-} // namespace facebook

ReactCommon/fabric/components/switch/SwitchProps.h

@@ -1,32 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#include <fabric/components/view/ViewProps.h>
-#include <fabric/graphics/Color.h>
-
-namespace facebook {
-namespace react {
-
-// TODO (T28334063): Consider for codegen.
-class SwitchProps final:
- public ViewProps {
-
-public:
- SwitchProps() = default;
- SwitchProps(const SwitchProps &sourceProps, const RawProps &rawProps);
-
-#pragma mark - Props
-
- const bool value {false};
- const bool disabled {false};
- const SharedColor tintColor {};
- const SharedColor onTintColor {};
- const SharedColor thumbTintColor {};
-};
-
-} // namespace react
-} // namespace facebook

ReactCommon/fabric/components/switch/SwitchShadowNode.cpp

@@ -1,16 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#include "SwitchShadowNode.h"
-
-namespace facebook {
-namespace react {
-
-extern const char SwitchComponentName[] = "Switch";
-
-} // namespace react
-} // namespace facebook

ReactCommon/fabric/components/switch/SwitchShadowNode.h

@@ -1,30 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#pragma once
-
-#include <fabric/components/switch/SwitchEventEmitter.h>
-#include <fabric/components/switch/SwitchProps.h>
-#include <fabric/components/view/ConcreteViewShadowNode.h>
-
-namespace facebook {
-namespace react {
-
-extern const char SwitchComponentName[];
-
-/*
- * `ShadowNode` for <Switch> component.
- */
-using SwitchShadowNode =
- ConcreteViewShadowNode<
- SwitchComponentName,
- SwitchProps,
- SwitchEventEmitter
- >;
-
-} // namespace react
-} // namespace facebook

ReactCommon/fabric/components/switch/tests/SwitchTest.cpp

@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#include <memory>
-
-#include <gtest/gtest.h>
-
-TEST(SwitchTest, testSomething) {
- // TODO
-}

ReactCommon/fabric/components/text/basetext/BaseTextProps.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,62 +7,100 @@
#include "BaseTextProps.h"
-#include <fabric/attributedstring/conversions.h>
-#include <fabric/core/propsConversions.h>
-#include <fabric/debug/DebugStringConvertibleItem.h>
-#include <fabric/graphics/conversions.h>
+#include <react/attributedstring/conversions.h>
+#include <react/core/propsConversions.h>
+#include <react/debug/DebugStringConvertibleItem.h>
+#include <react/graphics/conversions.h>
namespace facebook {
namespace react {
-static TextAttributes convertRawProp(const RawProps &rawProps, const TextAttributes defaultTextAttributes) {
- TextAttributes textAttributes;
+static TextAttributes convertRawProp(
+ const RawProps &rawProps,
+ const TextAttributes defaultTextAttributes) {
+ auto textAttributes = TextAttributes{};
// Color
- textAttributes.foregroundColor = convertRawProp(rawProps, "color", defaultTextAttributes.foregroundColor);
- textAttributes.backgroundColor = convertRawProp(rawProps, "backgroundColor", defaultTextAttributes.backgroundColor);
- textAttributes.opacity = convertRawProp(rawProps, "opacity", defaultTextAttributes.opacity);
+ textAttributes.foregroundColor =
+ convertRawProp(rawProps, "color", defaultTextAttributes.foregroundColor);
+ textAttributes.backgroundColor = convertRawProp(
+ rawProps, "backgroundColor", defaultTextAttributes.backgroundColor);
+ textAttributes.opacity =
+ convertRawProp(rawProps, "opacity", defaultTextAttributes.opacity);
// Font
- textAttributes.fontFamily = convertRawProp(rawProps, "fontFamily", defaultTextAttributes.fontFamily);
- textAttributes.fontSize = convertRawProp(rawProps, "fontSize", defaultTextAttributes.fontSize);
- textAttributes.fontSizeMultiplier = convertRawProp(rawProps, "fontSizeMultiplier", defaultTextAttributes.fontSizeMultiplier);
- textAttributes.fontWeight = convertRawProp(rawProps, "fontWeight", defaultTextAttributes.fontWeight);
- textAttributes.fontStyle = convertRawProp(rawProps, "fontStyle", defaultTextAttributes.fontStyle);
- textAttributes.fontVariant = convertRawProp(rawProps, "fontVariant", defaultTextAttributes.fontVariant);
- textAttributes.allowFontScaling = convertRawProp(rawProps, "allowFontScaling", defaultTextAttributes.allowFontScaling);
- textAttributes.letterSpacing = convertRawProp(rawProps, "letterSpacing", defaultTextAttributes.letterSpacing);
+ textAttributes.fontFamily =
+ convertRawProp(rawProps, "fontFamily", defaultTextAttributes.fontFamily);
+ textAttributes.fontSize =
+ convertRawProp(rawProps, "fontSize", defaultTextAttributes.fontSize);
+ textAttributes.fontSizeMultiplier = convertRawProp(
+ rawProps, "fontSizeMultiplier", defaultTextAttributes.fontSizeMultiplier);
+ textAttributes.fontWeight =
+ convertRawProp(rawProps, "fontWeight", defaultTextAttributes.fontWeight);
+ textAttributes.fontStyle =
+ convertRawProp(rawProps, "fontStyle", defaultTextAttributes.fontStyle);
+ textAttributes.fontVariant = convertRawProp(
+ rawProps, "fontVariant", defaultTextAttributes.fontVariant);
+ textAttributes.allowFontScaling = convertRawProp(
+ rawProps, "allowFontScaling", defaultTextAttributes.allowFontScaling);
+ textAttributes.letterSpacing = convertRawProp(
+ rawProps, "letterSpacing", defaultTextAttributes.letterSpacing);
// Paragraph
- textAttributes.lineHeight = convertRawProp(rawProps, "lineHeight", defaultTextAttributes.lineHeight);
- textAttributes.alignment = convertRawProp(rawProps, "alignment", defaultTextAttributes.alignment);
- textAttributes.baseWritingDirection = convertRawProp(rawProps, "baseWritingDirection", defaultTextAttributes.baseWritingDirection);
+ textAttributes.lineHeight =
+ convertRawProp(rawProps, "lineHeight", defaultTextAttributes.lineHeight);
+ textAttributes.alignment =
+ convertRawProp(rawProps, "alignment", defaultTextAttributes.alignment);
+ textAttributes.baseWritingDirection = convertRawProp(
+ rawProps,
+ "baseWritingDirection",
+ defaultTextAttributes.baseWritingDirection);
// Decoration
- textAttributes.textDecorationColor = convertRawProp(rawProps, "textDecorationColor", defaultTextAttributes.textDecorationColor);
- textAttributes.textDecorationLineType = convertRawProp(rawProps, "textDecorationLineType", defaultTextAttributes.textDecorationLineType);
- textAttributes.textDecorationLineStyle = convertRawProp(rawProps, "textDecorationLineStyle", defaultTextAttributes.textDecorationLineStyle);
- textAttributes.textDecorationLinePattern = convertRawProp(rawProps, "textDecorationLinePattern", defaultTextAttributes.textDecorationLinePattern);
+ textAttributes.textDecorationColor = convertRawProp(
+ rawProps,
+ "textDecorationColor",
+ defaultTextAttributes.textDecorationColor);
+ textAttributes.textDecorationLineType = convertRawProp(
+ rawProps,
+ "textDecorationLine",
+ defaultTextAttributes.textDecorationLineType);
+ textAttributes.textDecorationLineStyle = convertRawProp(
+ rawProps,
+ "textDecorationLineStyle",
+ defaultTextAttributes.textDecorationLineStyle);
+ textAttributes.textDecorationLinePattern = convertRawProp(
+ rawProps,
+ "textDecorationLinePattern",
+ defaultTextAttributes.textDecorationLinePattern);
// Shadow
- textAttributes.textShadowOffset = convertRawProp(rawProps, "textShadowOffset", defaultTextAttributes.textShadowOffset);
- textAttributes.textShadowRadius = convertRawProp(rawProps, "textShadowRadius", defaultTextAttributes.textShadowRadius);
- textAttributes.textShadowColor = convertRawProp(rawProps, "textShadowColor", defaultTextAttributes.textShadowColor);
+ textAttributes.textShadowOffset = convertRawProp(
+ rawProps, "textShadowOffset", defaultTextAttributes.textShadowOffset);
+ textAttributes.textShadowRadius = convertRawProp(
+ rawProps, "textShadowRadius", defaultTextAttributes.textShadowRadius);
+ textAttributes.textShadowColor = convertRawProp(
+ rawProps, "textShadowColor", defaultTextAttributes.textShadowColor);
// Special
- textAttributes.isHighlighted = convertRawProp(rawProps, "isHighlighted", defaultTextAttributes.isHighlighted);
+ textAttributes.isHighlighted = convertRawProp(
+ rawProps, "isHighlighted", defaultTextAttributes.isHighlighted);
return textAttributes;
}
-BaseTextProps::BaseTextProps(const BaseTextProps &sourceProps, const RawProps &rawProps):
- textAttributes(convertRawProp(rawProps, sourceProps.textAttributes)) {};
+BaseTextProps::BaseTextProps(
+ const BaseTextProps &sourceProps,
+ const RawProps &rawProps)
+ : textAttributes(convertRawProp(rawProps, sourceProps.textAttributes)){};
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList BaseTextProps::getDebugProps() const {
return textAttributes.getDebugProps();
}
+#endif
} // namespace react
} // namespace facebook

ReactCommon/fabric/components/text/basetext/BaseTextProps.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,10 +7,10 @@
#pragma once
-#include <fabric/attributedstring/TextAttributes.h>
-#include <fabric/core/Props.h>
-#include <fabric/graphics/Color.h>
-#include <fabric/graphics/Geometry.h>
+#include <react/attributedstring/TextAttributes.h>
+#include <react/core/Props.h>
+#include <react/graphics/Color.h>
+#include <react/graphics/Geometry.h>
namespace facebook {
namespace react {
@@ -20,18 +20,19 @@
* that can have text attributes (such as Text and Paragraph).
*/
class BaseTextProps {
-public:
-
+ public:
BaseTextProps() = default;
BaseTextProps(const BaseTextProps &sourceProps, const RawProps &rawProps);
#pragma mark - Props
- const TextAttributes textAttributes {};
+ const TextAttributes textAttributes{};
#pragma mark - DebugStringConvertible (partially)
+#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList getDebugProps() const;
+#endif
};
} // namespace react

ReactCommon/fabric/components/text/basetext/BaseTextShadowNode.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,44 +7,54 @@
#include "BaseTextShadowNode.h"
-#include <fabric/components/text/RawTextShadowNode.h>
-#include <fabric/components/text/RawTextProps.h>
-#include <fabric/components/text/TextShadowNode.h>
-#include <fabric/components/text/TextProps.h>
-#include <fabric/debug/DebugStringConvertibleItem.h>
+#include <react/components/text/RawTextProps.h>
+#include <react/components/text/RawTextShadowNode.h>
+#include <react/components/text/TextProps.h>
+#include <react/components/text/TextShadowNode.h>
+#include <react/debug/DebugStringConvertibleItem.h>
+#include <react/mounting/ShadowView.h>
namespace facebook {
namespace react {
AttributedString BaseTextShadowNode::getAttributedString(
const TextAttributes &textAttributes,
- const SharedShadowNodeList &childNodes
-) const {
- AttributedString attributedString;
+ const SharedShadowNode &parentNode) const {
+ auto attributedString = AttributedString{};
- for (const auto &childNode : childNodes) {
+ for (const auto &childNode : parentNode->getChildren()) {
// RawShadowNode
- auto rawTextShadowNode = std::dynamic_pointer_cast<const RawTextShadowNode>(childNode);
+ auto rawTextShadowNode =
+ std::dynamic_pointer_cast<const RawTextShadowNode>(childNode);
if (rawTextShadowNode) {
- AttributedString::Fragment fragment;
+ auto fragment = AttributedString::Fragment{};
fragment.string = rawTextShadowNode->getProps()->text;
fragment.textAttributes = textAttributes;
+
+ // Storing a retaining pointer to `ParagraphShadowNode` inside
+ // `attributedString` causes a retain cycle (besides that fact that we
+ // don't need it at all). Storing a `ShadowView` instance instead of
+ // `ShadowNode` should properly fix this problem.
+ fragment.parentShadowView = ShadowView(*parentNode);
attributedString.appendFragment(fragment);
continue;
}
// TextShadowNode
- auto textShadowNode = std::dynamic_pointer_cast<const TextShadowNode>(childNode);
+ auto textShadowNode =
+ std::dynamic_pointer_cast<const TextShadowNode>(childNode);
if (textShadowNode) {
- TextAttributes localTextAttributes = textAttributes;
+ auto localTextAttributes = textAttributes;
localTextAttributes.apply(textShadowNode->getProps()->textAttributes);
- attributedString.appendAttributedString(textShadowNode->getAttributedString(localTextAttributes, textShadowNode->getChildren()));
+ attributedString.appendAttributedString(
+ textShadowNode->getAttributedString(
+ localTextAttributes, textShadowNode));
continue;
}
// Any other kind of ShadowNode
- AttributedString::Fragment fragment;
- fragment.shadowNode = childNode;
+ auto fragment = AttributedString::Fragment{};
+ fragment.shadowView = ShadowView(*childNode);
fragment.textAttributes = textAttributes;
attributedString.appendFragment(fragment);
}

ReactCommon/fabric/components/text/basetext/BaseTextShadowNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,8 +7,8 @@
#pragma once
-#include <fabric/attributedstring/AttributedString.h>
-#include <fabric/attributedstring/TextAttributes.h>
+#include <react/attributedstring/AttributedString.h>
+#include <react/attributedstring/TextAttributes.h>
namespace facebook {
namespace react {
@@ -18,15 +18,13 @@
* such as Text and Paragraph (but not RawText).
*/
class BaseTextShadowNode {
-public:
-
+ public:
/*
* Returns a `AttributedString` which represents text content of the node.
*/
AttributedString getAttributedString(
const TextAttributes &baseTextAttributes,
- const SharedShadowNodeList &childNodes
- ) const;
+ const SharedShadowNode &parentNode) const;
};
} // namespace react

ReactCommon/fabric/components/text/BUCK

@@ -1,4 +1,4 @@
-load("//configurations/buck/apple:flag_defs.bzl", "OBJC_ARC_PREPROCESSOR_FLAGS", "get_application_ios_flags", "get_debug_preprocessor_flags")
+load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags")
load(
"//tools/build_defs/oss:rn_defs.bzl",
"ANDROID",
@@ -32,7 +32,7 @@
("text", "*.h"),
("rawtext", "*.h"),
],
- prefix = "fabric/components/text",
+ prefix = "react/components/text",
),
compiler_flags = [
"-fexceptions",
@@ -42,9 +42,6 @@
],
fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
- fbobjc_tests = [
- ":tests",
- ],
force_static = True,
macosx_tests_override = [],
platforms = (ANDROID, APPLE),
@@ -52,21 +49,24 @@
"-DLOG_TAG=\"ReactNative\"",
"-DWITH_FBSYSTRACE=1",
],
- tests = [],
+ tests = [":tests"],
visibility = ["PUBLIC"],
deps = [
"xplat//fbsystrace:fbsystrace",
+ "xplat//folly:evicting_cache_map",
"xplat//folly:headers_only",
"xplat//folly:memory",
"xplat//folly:molly",
"xplat//third-party/glog:glog",
"xplat//yoga:yoga",
+ react_native_xplat_target("utils:utils"),
react_native_xplat_target("fabric/attributedstring:attributedstring"),
react_native_xplat_target("fabric/core:core"),
react_native_xplat_target("fabric/debug:debug"),
react_native_xplat_target("fabric/graphics:graphics"),
react_native_xplat_target("fabric/textlayoutmanager:textlayoutmanager"),
react_native_xplat_target("fabric/components/view:view"),
+ react_native_xplat_target("fabric/uimanager:uimanager"),
],
)
@@ -81,7 +81,7 @@
"-Wall",
],
contacts = ["oncall+react_native@xmail.facebook.com"],
- platforms = APPLE,
+ platforms = (ANDROID, APPLE),
deps = [
"xplat//folly:molly",
"xplat//third-party/gmock:gtest",

ReactCommon/fabric/components/text/paragraph/conversions.h

@@ -0,0 +1,26 @@
+// 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.
+
+#include <folly/dynamic.h>
+#include <react/attributedstring/conversions.h>
+#include <react/components/text/ParagraphLocalData.h>
+
+namespace facebook {
+namespace react {
+
+#ifdef ANDROID
+
+inline folly::dynamic toDynamic(const ParagraphLocalData &paragraphLocalData) {
+ folly::dynamic newLocalData = folly::dynamic::object();
+ newLocalData["attributedString"] =
+ toDynamic(paragraphLocalData.getAttributedString());
+ newLocalData["hash"] = newLocalData["attributedString"]["hash"];
+ return newLocalData;
+}
+
+#endif
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/components/text/paragraph/ParagraphComponentDescriptor.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,9 +7,13 @@
#pragma once
-#include <fabric/components/text/ParagraphShadowNode.h>
-#include <fabric/core/ConcreteComponentDescriptor.h>
-#include <fabric/textlayoutmanager/TextLayoutManager.h>
+#include "ParagraphMeasurementCache.h"
+#include "ParagraphShadowNode.h"
+
+#include <folly/container/EvictingCacheMap.h>
+#include <react/core/ConcreteComponentDescriptor.h>
+#include <react/textlayoutmanager/TextLayoutManager.h>
+#include <react/uimanager/ContextContainer.h>
namespace facebook {
namespace react {
@@ -17,36 +21,63 @@
/*
* Descriptor for <Paragraph> component.
*/
-class ParagraphComponentDescriptor final:
- public ConcreteComponentDescriptor<ParagraphShadowNode> {
-
-public:
-
- ParagraphComponentDescriptor(SharedEventDispatcher eventDispatcher):
- ConcreteComponentDescriptor<ParagraphShadowNode>(eventDispatcher) {
+class ParagraphComponentDescriptor final
+ : public ConcreteComponentDescriptor<ParagraphShadowNode> {
+ public:
+ ParagraphComponentDescriptor(
+ SharedEventDispatcher eventDispatcher,
+ const SharedContextContainer &contextContainer)
+ : ConcreteComponentDescriptor<ParagraphShadowNode>(eventDispatcher) {
// Every single `ParagraphShadowNode` will have a reference to
// a shared `TextLayoutManager`.
- textLayoutManager_ = std::make_shared<TextLayoutManager>();
+ textLayoutManager_ = std::make_shared<TextLayoutManager>(contextContainer);
+ // Every single `ParagraphShadowNode` will have a reference to
+ // a shared `EvictingCacheMap`, a simple LRU cache for Paragraph
+ // measurements.
+#ifdef ANDROID
+ auto paramName = "react_fabric:enabled_paragraph_measure_cache_android";
+#else
+ auto paramName = "react_fabric:enabled_paragraph_measure_cache_ios";
+#endif
+ // TODO: T39927960 - get rid of this if statement
+ bool enableCache =
+ (contextContainer != nullptr
+ ? contextContainer
+ ->getInstance<std::shared_ptr<const ReactNativeConfig>>(
+ "ReactNativeConfig")
+ ->getBool(paramName)
+ : false);
+ if (enableCache) {
+ measureCache_ = std::make_unique<ParagraphMeasurementCache>();
+ } else {
+ measureCache_ = nullptr;
+ }
}
void adopt(UnsharedShadowNode shadowNode) const override {
ConcreteComponentDescriptor::adopt(shadowNode);
assert(std::dynamic_pointer_cast<ParagraphShadowNode>(shadowNode));
- auto paragraphShadowNode = std::static_pointer_cast<ParagraphShadowNode>(shadowNode);
+ auto paragraphShadowNode =
+ std::static_pointer_cast<ParagraphShadowNode>(shadowNode);
// `ParagraphShadowNode` uses `TextLayoutManager` to measure text content
// and communicate text rendering metrics to mounting layer.
paragraphShadowNode->setTextLayoutManager(textLayoutManager_);
+ // `ParagraphShadowNode` uses this to cache the results of text rendering
+ // measurements.
+ paragraphShadowNode->setMeasureCache(
+ measureCache_ ? measureCache_.get() : nullptr);
+
// All `ParagraphShadowNode`s must have leaf Yoga nodes with properly
// setup measure function.
paragraphShadowNode->enableMeasurement();
}
-private:
-
+ private:
SharedTextLayoutManager textLayoutManager_;
+ std::unique_ptr<const ParagraphMeasurementCache> measureCache_;
};
} // namespace react

ReactCommon/fabric/components/text/paragraph/ParagraphLocalData.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,7 +7,8 @@
#include "ParagraphLocalData.h"
-#include <fabric/debug/debugStringConvertibleUtils.h>
+#include <react/components/text/conversions.h>
+#include <react/debug/debugStringConvertibleUtils.h>
namespace facebook {
namespace react {
@@ -16,7 +17,8 @@
return attributedString_;
}
-void ParagraphLocalData::setAttributedString(AttributedString attributedString) {
+void ParagraphLocalData::setAttributedString(
+ AttributedString attributedString) {
ensureUnsealed();
attributedString_ = attributedString;
}
@@ -25,22 +27,32 @@
return textLayoutManager_;
}
-void ParagraphLocalData::setTextLayoutManager(SharedTextLayoutManager textLayoutManager) {
+void ParagraphLocalData::setTextLayoutManager(
+ SharedTextLayoutManager textLayoutManager) {
ensureUnsealed();
textLayoutManager_ = textLayoutManager;
}
+#ifdef ANDROID
+
+folly::dynamic ParagraphLocalData::getDynamic() const {
+ return toDynamic(*this);
+}
+
+#endif
+
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
std::string ParagraphLocalData::getDebugName() const {
return "ParagraphLocalData";
}
SharedDebugStringConvertibleList ParagraphLocalData::getDebugProps() const {
return {
- debugStringConvertibleItem("attributedString", attributedString_, "")
- };
+ debugStringConvertibleItem("attributedString", attributedString_, "")};
}
+#endif
} // namespace react
} // namespace facebook

ReactCommon/fabric/components/text/paragraph/ParagraphLocalData.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,9 +7,9 @@
#pragma once
-#include <fabric/attributedstring/AttributedString.h>
-#include <fabric/core/LocalData.h>
-#include <fabric/textlayoutmanager/TextLayoutManager.h>
+#include <react/attributedstring/AttributedString.h>
+#include <react/core/LocalData.h>
+#include <react/textlayoutmanager/TextLayoutManager.h>
namespace facebook {
namespace react {
@@ -22,11 +22,8 @@
* LocalData for <Paragraph> component.
* Represents what to render and how to render.
*/
-class ParagraphLocalData:
- public LocalData {
-
-public:
-
+class ParagraphLocalData : public LocalData {
+ public:
/*
* All content of <Paragraph> component represented as an `AttributedString`.
*/
@@ -41,13 +38,18 @@
SharedTextLayoutManager getTextLayoutManager() const;
void setTextLayoutManager(SharedTextLayoutManager textLayoutManager);
+#ifdef ANDROID
+ folly::dynamic getDynamic() const override;
+#endif
+
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
std::string getDebugName() const override;
SharedDebugStringConvertibleList getDebugProps() const override;
+#endif
-private:
-
+ private:
AttributedString attributedString_;
SharedTextLayoutManager textLayoutManager_;
};

ReactCommon/fabric/components/text/paragraph/ParagraphMeasurementCache.h

@@ -0,0 +1,53 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <folly/container/EvictingCacheMap.h>
+
+#include <react/attributedstring/AttributedString.h>
+#include <react/attributedstring/ParagraphAttributes.h>
+#include <react/core/LayoutConstraints.h>
+
+namespace facebook {
+namespace react {
+using ParagraphMeasurementCacheKey =
+ std::tuple<AttributedString, ParagraphAttributes, LayoutConstraints>;
+using ParagraphMeasurementCacheValue = Size;
+
+class ParagraphMeasurementCache {
+ public:
+ ParagraphMeasurementCache() : cache_{256} {}
+
+ bool exists(const ParagraphMeasurementCacheKey &key) const {
+ std::lock_guard<std::mutex> lock(mutex_);
+ return cache_.exists(key);
+ }
+
+ ParagraphMeasurementCacheValue get(
+ const ParagraphMeasurementCacheKey &key) const {
+ std::lock_guard<std::mutex> lock(mutex_);
+ return cache_.get(key);
+ }
+
+ void set(
+ const ParagraphMeasurementCacheKey &key,
+ const ParagraphMeasurementCacheValue &value) const {
+ std::lock_guard<std::mutex> lock(mutex_);
+ cache_.set(key, value);
+ }
+
+ private:
+ mutable folly::EvictingCacheMap<
+ ParagraphMeasurementCacheKey,
+ ParagraphMeasurementCacheValue>
+ cache_;
+ mutable std::mutex mutex_;
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/components/text/paragraph/ParagraphProps.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,42 +7,62 @@
#include "ParagraphProps.h"
-#include <fabric/attributedstring/conversions.h>
-#include <fabric/core/propsConversions.h>
-#include <fabric/debug/debugStringConvertibleUtils.h>
+#include <react/attributedstring/conversions.h>
+#include <react/core/propsConversions.h>
+#include <react/debug/debugStringConvertibleUtils.h>
namespace facebook {
namespace react {
-static ParagraphAttributes convertRawProp(const RawProps &rawProps, const ParagraphAttributes &defaultParagraphAttributes) {
- ParagraphAttributes paragraphAttributes;
-
- paragraphAttributes.maximumNumberOfLines = convertRawProp(rawProps, "numberOfLines", defaultParagraphAttributes.maximumNumberOfLines);
- paragraphAttributes.ellipsizeMode = convertRawProp(rawProps, "ellipsizeMode", defaultParagraphAttributes.ellipsizeMode);
- paragraphAttributes.adjustsFontSizeToFit = convertRawProp(rawProps, "adjustsFontSizeToFit", defaultParagraphAttributes.adjustsFontSizeToFit);
- paragraphAttributes.minimumFontSize = convertRawProp(rawProps, "minimumFontSize", defaultParagraphAttributes.minimumFontSize, std::numeric_limits<Float>::quiet_NaN());
- paragraphAttributes.maximumFontSize = convertRawProp(rawProps, "maximumFontSize", defaultParagraphAttributes.maximumFontSize, std::numeric_limits<Float>::quiet_NaN());
+static ParagraphAttributes convertRawProp(
+ const RawProps &rawProps,
+ const ParagraphAttributes &defaultParagraphAttributes) {
+ auto paragraphAttributes = ParagraphAttributes{};
+
+ paragraphAttributes.maximumNumberOfLines = convertRawProp(
+ rawProps,
+ "numberOfLines",
+ defaultParagraphAttributes.maximumNumberOfLines);
+ paragraphAttributes.ellipsizeMode = convertRawProp(
+ rawProps, "ellipsizeMode", defaultParagraphAttributes.ellipsizeMode);
+ paragraphAttributes.adjustsFontSizeToFit = convertRawProp(
+ rawProps,
+ "adjustsFontSizeToFit",
+ defaultParagraphAttributes.adjustsFontSizeToFit);
+ paragraphAttributes.minimumFontSize = convertRawProp(
+ rawProps,
+ "minimumFontSize",
+ defaultParagraphAttributes.minimumFontSize,
+ std::numeric_limits<Float>::quiet_NaN());
+ paragraphAttributes.maximumFontSize = convertRawProp(
+ rawProps,
+ "maximumFontSize",
+ defaultParagraphAttributes.maximumFontSize,
+ std::numeric_limits<Float>::quiet_NaN());
return paragraphAttributes;
}
-ParagraphProps::ParagraphProps(const ParagraphProps &sourceProps, const RawProps &rawProps):
- ViewProps(sourceProps, rawProps),
+ParagraphProps::ParagraphProps(
+ const ParagraphProps &sourceProps,
+ const RawProps &rawProps)
+ : ViewProps(sourceProps, rawProps),
BaseTextProps(sourceProps, rawProps),
- paragraphAttributes(convertRawProp(rawProps, sourceProps.paragraphAttributes)),
- isSelectable(convertRawProp(rawProps, "selectable", sourceProps.isSelectable)) {};
+ paragraphAttributes(
+ convertRawProp(rawProps, sourceProps.paragraphAttributes)),
+ isSelectable(
+ convertRawProp(rawProps, "selectable", sourceProps.isSelectable)){};
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList ParagraphProps::getDebugProps() const {
- return
- ViewProps::getDebugProps() +
- BaseTextProps::getDebugProps() +
+ return ViewProps::getDebugProps() + BaseTextProps::getDebugProps() +
paragraphAttributes.getDebugProps() +
- SharedDebugStringConvertibleList {
- debugStringConvertibleItem("isSelectable", isSelectable)
- };
+ SharedDebugStringConvertibleList{
+ debugStringConvertibleItem("isSelectable", isSelectable)};
}
+#endif
} // namespace react
} // namespace facebook

ReactCommon/fabric/components/text/paragraph/ParagraphProps.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,10 +10,10 @@
#include <limits>
#include <memory>
-#include <fabric/attributedstring/ParagraphAttributes.h>
-#include <fabric/components/text/BaseTextProps.h>
-#include <fabric/components/view/ViewProps.h>
-#include <fabric/core/Props.h>
+#include <react/attributedstring/ParagraphAttributes.h>
+#include <react/components/text/BaseTextProps.h>
+#include <react/components/view/ViewProps.h>
+#include <react/core/Props.h>
namespace facebook {
namespace react {
@@ -23,30 +23,29 @@
* Most of the props are directly stored in composed `ParagraphAttributes`
* object.
*/
-class ParagraphProps:
- public ViewProps,
- public BaseTextProps {
-
-public:
+class ParagraphProps : public ViewProps, public BaseTextProps {
+ public:
ParagraphProps() = default;
ParagraphProps(const ParagraphProps &sourceProps, const RawProps &rawProps);
#pragma mark - Props
/*
- * Contains all prop values that affect visual representation of the paragraph.
+ * Contains all prop values that affect visual representation of the
+ * paragraph.
*/
- const ParagraphAttributes paragraphAttributes {};
+ const ParagraphAttributes paragraphAttributes{};
/*
* Defines can the text be selected (and copied) or not.
*/
- const bool isSelectable {};
+ const bool isSelectable{};
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList getDebugProps() const override;
-
+#endif
};
} // namespace react

ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -6,8 +6,8 @@
*/
#include "ParagraphShadowNode.h"
-
#include "ParagraphLocalData.h"
+#include "ParagraphMeasurementCache.h"
namespace facebook {
namespace react {
@@ -16,23 +16,41 @@
AttributedString ParagraphShadowNode::getAttributedString() const {
if (!cachedAttributedString_.has_value()) {
- cachedAttributedString_ =
- BaseTextShadowNode::getAttributedString(getProps()->textAttributes, getChildren());
+ auto textAttributes = TextAttributes::defaultTextAttributes();
+ textAttributes.apply(getProps()->textAttributes);
+
+ cachedAttributedString_ = BaseTextShadowNode::getAttributedString(
+ textAttributes, shared_from_this());
}
return cachedAttributedString_.value();
}
-void ParagraphShadowNode::setTextLayoutManager(SharedTextLayoutManager textLayoutManager) {
+void ParagraphShadowNode::setTextLayoutManager(
+ SharedTextLayoutManager textLayoutManager) {
ensureUnsealed();
textLayoutManager_ = textLayoutManager;
}
-void ParagraphShadowNode::updateLocalData() {
+void ParagraphShadowNode::setMeasureCache(
+ const ParagraphMeasurementCache *cache) {
ensureUnsealed();
+ measureCache_ = cache;
+}
+
+void ParagraphShadowNode::updateLocalDataIfNeeded() {
+ ensureUnsealed();
+
+ auto attributedString = getAttributedString();
+ auto currentLocalData =
+ std::static_pointer_cast<const ParagraphLocalData>(getLocalData());
+ if (currentLocalData &&
+ currentLocalData->getAttributedString() == attributedString) {
+ return;
+ }
auto localData = std::make_shared<ParagraphLocalData>();
- localData->setAttributedString(getAttributedString());
+ localData->setAttributedString(std::move(attributedString));
localData->setTextLayoutManager(textLayoutManager_);
setLocalData(localData);
}
@@ -40,15 +58,34 @@
#pragma mark - LayoutableShadowNode
Size ParagraphShadowNode::measure(LayoutConstraints layoutConstraints) const {
+ AttributedString attributedString = getAttributedString();
+ const ParagraphAttributes attributes = getProps()->paragraphAttributes;
+
+ auto makeMeasurements = [&] {
return textLayoutManager_->measure(
- getAttributedString(),
- getProps()->paragraphAttributes,
- layoutConstraints
- );
+ attributedString, getProps()->paragraphAttributes, layoutConstraints);
+ };
+
+ // Cache results of this function so we don't need to call measure()
+ // repeatedly
+ if (measureCache_ != nullptr) {
+ ParagraphMeasurementCacheKey cacheKey =
+ std::make_tuple(attributedString, attributes, layoutConstraints);
+ if (measureCache_->exists(cacheKey)) {
+ return measureCache_->get(cacheKey);
+ }
+
+ auto measuredSize = makeMeasurements();
+ measureCache_->set(cacheKey, measuredSize);
+
+ return measuredSize;
+ }
+
+ return makeMeasurements();
}
void ParagraphShadowNode::layout(LayoutContext layoutContext) {
- updateLocalData();
+ updateLocalDataIfNeeded();
ConcreteViewShadowNode::layout(layoutContext);
}

ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,34 +7,34 @@
#pragma once
-#include <fabric/components/text/ParagraphProps.h>
-#include <fabric/components/text/TextShadowNode.h>
-#include <fabric/components/view/ConcreteViewShadowNode.h>
-#include <fabric/core/ConcreteShadowNode.h>
-#include <fabric/core/ShadowNode.h>
-#include <fabric/core/LayoutContext.h>
-#include <fabric/textlayoutmanager/TextLayoutManager.h>
#include <folly/Optional.h>
+#include <react/components/text/ParagraphMeasurementCache.h>
+#include <react/components/text/ParagraphProps.h>
+#include <react/components/text/TextShadowNode.h>
+#include <react/components/view/ConcreteViewShadowNode.h>
+#include <react/core/ConcreteShadowNode.h>
+#include <react/core/LayoutContext.h>
+#include <react/core/ShadowNode.h>
+#include <react/textlayoutmanager/TextLayoutManager.h>
namespace facebook {
namespace react {
extern const char ParagraphComponentName[];
+using ParagraphEventEmitter = ViewEventEmitter;
+
/*
* `ShadowNode` for <Paragraph> component, represents <View>-like component
* containing and displaying text. Text content is represented as nested <Text>
* and <RawText> components.
*/
-class ParagraphShadowNode:
- public ConcreteViewShadowNode<
+class ParagraphShadowNode : public ConcreteViewShadowNode<
ParagraphComponentName,
- ParagraphProps
- >,
+ ParagraphProps,
+ ParagraphEventEmitter>,
public BaseTextShadowNode {
-
-public:
-
+ public:
using ConcreteViewShadowNode::ConcreteViewShadowNode;
/*
@@ -49,26 +49,35 @@
*/
void setTextLayoutManager(SharedTextLayoutManager textLayoutManager);
+ /*
+ * Associates a shared LRU cache with the node.
+ * `ParagraphShadowNode` uses this to cache the results of
+ * text rendering measurements.
+ * By design, the ParagraphComponentDescriptor outlives all
+ * shadow nodes, so it's safe for this to be a raw pointer.
+ */
+ void setMeasureCache(const ParagraphMeasurementCache *cache);
+
#pragma mark - LayoutableShadowNode
void layout(LayoutContext layoutContext) override;
Size measure(LayoutConstraints layoutConstraints) const override;
-private:
-
+ private:
/*
* Creates a `LocalData` object (with `AttributedText` and
* `TextLayoutManager`) if needed.
*/
- void updateLocalData();
+ void updateLocalDataIfNeeded();
SharedTextLayoutManager textLayoutManager_;
+ const ParagraphMeasurementCache *measureCache_;
/*
* Cached attributed string that represents the content of the subtree started
* from the node.
*/
- mutable folly::Optional<AttributedString> cachedAttributedString_ {};
+ mutable folly::Optional<AttributedString> cachedAttributedString_{};
};
} // namespace react

ReactCommon/fabric/components/text/rawtext/RawTextComponentDescriptor.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,13 +7,14 @@
#pragma once
-#include <fabric/components/text/RawTextShadowNode.h>
-#include <fabric/core/ConcreteComponentDescriptor.h>
+#include <react/components/text/RawTextShadowNode.h>
+#include <react/core/ConcreteComponentDescriptor.h>
namespace facebook {
namespace react {
-using RawTextComponentDescriptor = ConcreteComponentDescriptor<RawTextShadowNode>;
+using RawTextComponentDescriptor =
+ ConcreteComponentDescriptor<RawTextShadowNode>;
} // namespace react
} // namespace facebook

ReactCommon/fabric/components/text/rawtext/RawTextProps.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,23 +7,25 @@
#include "RawTextProps.h"
-#include <fabric/core/propsConversions.h>
-#include <fabric/debug/debugStringConvertibleUtils.h>
+#include <react/core/propsConversions.h>
+#include <react/debug/debugStringConvertibleUtils.h>
namespace facebook {
namespace react {
-RawTextProps::RawTextProps(const RawTextProps &sourceProps, const RawProps &rawProps):
- Props(sourceProps, rawProps),
- text(convertRawProp(rawProps, "text", sourceProps.text)) {};
+RawTextProps::RawTextProps(
+ const RawTextProps &sourceProps,
+ const RawProps &rawProps)
+ : Props(sourceProps, rawProps),
+ text(convertRawProp(rawProps, "text", sourceProps.text)){};
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList RawTextProps::getDebugProps() const {
- return {
- debugStringConvertibleItem("text", text)
- };
+ return {debugStringConvertibleItem("text", text)};
}
+#endif
} // namespace react
} // namespace facebook

ReactCommon/fabric/components/text/rawtext/RawTextProps.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,8 +9,8 @@
#include <memory>
-#include <fabric/core/Props.h>
-#include <fabric/debug/DebugStringConvertible.h>
+#include <react/core/Props.h>
+#include <react/debug/DebugStringConvertible.h>
namespace facebook {
namespace react {
@@ -19,20 +19,20 @@
using SharedRawTextProps = std::shared_ptr<const RawTextProps>;
-class RawTextProps:
- public Props {
-
-public:
+class RawTextProps : public Props {
+ public:
RawTextProps() = default;
RawTextProps(const RawTextProps &sourceProps, const RawProps &rawProps);
#pragma mark - Props
- const std::string text {};
+ const std::string text{};
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList getDebugProps() const override;
+#endif
};
} // namespace react

ReactCommon/fabric/components/text/rawtext/RawTextShadowNode.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactCommon/fabric/components/text/rawtext/RawTextShadowNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,8 +7,8 @@
#pragma once
-#include <fabric/components/text/RawTextProps.h>
-#include <fabric/core/ConcreteShadowNode.h>
+#include <react/components/text/RawTextProps.h>
+#include <react/core/ConcreteShadowNode.h>
namespace facebook {
namespace react {
@@ -22,10 +22,7 @@
* <RawText> component must not have any children.
*/
using RawTextShadowNode =
- ConcreteShadowNode<
- RawTextComponentName,
- RawTextProps
- >;
+ ConcreteShadowNode<RawTextComponentName, RawTextProps>;
} // namespace react
} // namespace facebook

ReactCommon/fabric/components/text/tests/ParagraphLocalDataTest.cpp

@@ -0,0 +1,54 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <memory>
+
+#include <assert.h>
+#include <gtest/gtest.h>
+#include <react/attributedstring/AttributedString.h>
+#include <react/attributedstring/TextAttributes.h>
+#include <react/attributedstring/primitives.h>
+#include <react/components/text/ParagraphLocalData.h>
+#include <react/components/text/conversions.h>
+
+namespace facebook {
+namespace react {
+
+#ifdef ANDROID
+
+TEST(ParagraphLocalDataTest, testSomething) {
+ auto attString = AttributedString();
+ auto fragment = AttributedString::Fragment();
+ fragment.string = "test";
+
+ auto text = TextAttributes();
+ text.foregroundColor = {
+ colorFromComponents({100 / 255.0, 153 / 255.0, 253 / 255.0, 1.0})};
+ text.opacity = 0.5;
+ text.fontStyle = FontStyle::Italic;
+ text.fontWeight = FontWeight::Thin;
+ text.fontVariant = FontVariant::TabularNums;
+ fragment.textAttributes = text;
+ attString.prependFragment(fragment);
+
+ auto paragraphLocalData = ParagraphLocalData();
+ paragraphLocalData.setAttributedString(attString);
+
+ auto result = toDynamic(paragraphLocalData)["attributedString"];
+
+ assert(result["string"] == fragment.string);
+ auto textAttribute = result["fragments"][0]["textAttributes"];
+ assert(textAttribute["foregroundColor"] == toDynamic(text.foregroundColor));
+ assert(textAttribute["opacity"] == text.opacity);
+ assert(textAttribute["fontStyle"] == toString(*text.fontStyle));
+ assert(textAttribute["fontWeight"] == toString(*text.fontWeight));
+}
+
+#endif
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/components/text/tests/TextTest.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactCommon/fabric/components/text/text/TextComponentDescriptor.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,8 +7,8 @@
#pragma once
-#include <fabric/components/text/TextShadowNode.h>
-#include <fabric/core/ConcreteComponentDescriptor.h>
+#include <react/components/text/TextShadowNode.h>
+#include <react/core/ConcreteComponentDescriptor.h>
namespace facebook {
namespace react {

ReactCommon/fabric/components/text/text/TextProps.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,14 +10,16 @@
namespace facebook {
namespace react {
-TextProps::TextProps(const TextProps &sourceProps, const RawProps &rawProps):
- BaseTextProps::BaseTextProps(sourceProps, rawProps) {};
+TextProps::TextProps(const TextProps &sourceProps, const RawProps &rawProps)
+ : BaseTextProps::BaseTextProps(sourceProps, rawProps){};
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList TextProps::getDebugProps() const {
return BaseTextProps::getDebugProps();
}
+#endif
} // namespace react
} // namespace facebook

ReactCommon/fabric/components/text/text/TextProps.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,26 +7,25 @@
#pragma once
-#include <fabric/attributedstring/TextAttributes.h>
-#include <fabric/components/text/BaseTextProps.h>
-#include <fabric/core/Props.h>
-#include <fabric/graphics/Color.h>
-#include <fabric/graphics/Geometry.h>
+#include <react/attributedstring/TextAttributes.h>
+#include <react/components/text/BaseTextProps.h>
+#include <react/core/Props.h>
+#include <react/graphics/Color.h>
+#include <react/graphics/Geometry.h>
namespace facebook {
namespace react {
-class TextProps:
- public Props,
- public BaseTextProps {
-
-public:
+class TextProps : public Props, public BaseTextProps {
+ public:
TextProps() = default;
TextProps(const TextProps &sourceProps, const RawProps &rawProps);
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList getDebugProps() const override;
+#endif
};
} // namespace react

ReactCommon/fabric/components/text/text/TextShadowNode.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactCommon/fabric/components/text/text/TextShadowNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,24 +7,22 @@
#pragma once
-#include <fabric/components/text/BaseTextShadowNode.h>
-#include <fabric/components/text/TextProps.h>
-#include <fabric/core/ConcreteShadowNode.h>
+#include <react/components/text/BaseTextShadowNode.h>
+#include <react/components/text/TextProps.h>
+#include <react/components/view/ViewEventEmitter.h>
+#include <react/core/ConcreteShadowNode.h>
namespace facebook {
namespace react {
extern const char TextComponentName[];
-class TextShadowNode:
- public ConcreteShadowNode<
- TextComponentName,
- TextProps
- >,
- public BaseTextShadowNode {
-
-public:
+using TextEventEmitter = TouchEventEmitter;
+class TextShadowNode
+ : public ConcreteShadowNode<TextComponentName, TextProps, TextEventEmitter>,
+ public BaseTextShadowNode {
+ public:
using ConcreteShadowNode::ConcreteShadowNode;
};

ReactCommon/fabric/components/view/accessibility/AccessibilityPrimitives.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -12,7 +12,7 @@
namespace facebook {
namespace react {
-enum class AccessibilityTraits: uint32_t {
+enum class AccessibilityTraits : uint32_t {
None = 0,
Button = (1 << 0),
Link = (1 << 1),
@@ -27,14 +27,22 @@
SearchField = (1 << 10),
StartsMediaSession = (1 << 11),
Adjustable = (1 << 12),
- DirectInteraction = (1 << 13),
+ AllowsDirectInteraction = (1 << 13),
CausesPageTurn = (1 << 14),
Header = (1 << 15),
};
-constexpr enum AccessibilityTraits operator |(const enum AccessibilityTraits lhs, const enum AccessibilityTraits rhs) {
+constexpr enum AccessibilityTraits operator|(
+ const enum AccessibilityTraits lhs,
+ const enum AccessibilityTraits rhs) {
return (enum AccessibilityTraits)((uint32_t)lhs | (uint32_t)rhs);
}
+constexpr enum AccessibilityTraits operator&(
+ const enum AccessibilityTraits lhs,
+ const enum AccessibilityTraits rhs) {
+ return (enum AccessibilityTraits)((uint32_t)lhs & (uint32_t)rhs);
+}
+
} // namespace react
} // namespace facebook

ReactCommon/fabric/components/view/accessibility/accessibilityPropsConversions.h

@@ -0,0 +1,104 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <folly/dynamic.h>
+#include <react/components/view/AccessibilityPrimitives.h>
+
+namespace facebook {
+namespace react {
+
+inline void fromString(const std::string &string, AccessibilityTraits &result) {
+ if (string == "none") {
+ result = AccessibilityTraits::None;
+ return;
+ }
+ if (string == "button") {
+ result = AccessibilityTraits::Button;
+ return;
+ }
+ if (string == "link") {
+ result = AccessibilityTraits::Link;
+ return;
+ }
+ if (string == "image") {
+ result = AccessibilityTraits::Image;
+ return;
+ }
+ if (string == "selected") {
+ result = AccessibilityTraits::Selected;
+ return;
+ }
+ if (string == "plays") {
+ result = AccessibilityTraits::PlaysSound;
+ return;
+ }
+ if (string == "keyboardkey") {
+ result = AccessibilityTraits::KeyboardKey;
+ return;
+ }
+ if (string == "text") {
+ result = AccessibilityTraits::StaticText;
+ return;
+ }
+ if (string == "disabled") {
+ result = AccessibilityTraits::NotEnabled;
+ return;
+ }
+ if (string == "frequentUpdates") {
+ result = AccessibilityTraits::UpdatesFrequently;
+ return;
+ }
+ if (string == "search") {
+ result = AccessibilityTraits::SearchField;
+ return;
+ }
+ if (string == "startsMedia") {
+ result = AccessibilityTraits::StartsMediaSession;
+ return;
+ }
+ if (string == "adjustable") {
+ result = AccessibilityTraits::Adjustable;
+ return;
+ }
+ if (string == "allowsDirectInteraction") {
+ result = AccessibilityTraits::AllowsDirectInteraction;
+ return;
+ }
+ if (string == "pageTurn") {
+ result = AccessibilityTraits::CausesPageTurn;
+ return;
+ }
+ if (string == "header") {
+ result = AccessibilityTraits::Header;
+ return;
+ }
+ abort();
+}
+
+inline void fromRawValue(const RawValue &value, AccessibilityTraits &result) {
+ if (value.hasType<std::string>()) {
+ fromString((std::string)value, result);
+ return;
+ }
+
+ if (value.hasType<std::vector<std::string>>()) {
+ result = {};
+ auto items = (std::vector<std::string>)value;
+ for (auto &item : items) {
+ AccessibilityTraits itemAccessibilityTraits;
+ fromString(item, itemAccessibilityTraits);
+ result = result | itemAccessibilityTraits;
+ }
+ }
+
+ abort();
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/components/view/accessibility/AccessibilityProps.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,12 +7,60 @@
#include "AccessibilityProps.h"
-#include "accessibilityValuesConversions.h"
+#include <react/components/view/accessibilityPropsConversions.h>
+#include <react/components/view/propsConversions.h>
+#include <react/core/propsConversions.h>
+#include <react/debug/debugStringConvertibleUtils.h>
namespace facebook {
namespace react {
-AccessibilityProps::AccessibilityProps(const AccessibilityProps &sourceProps, const RawProps &rawProps) {}
+AccessibilityProps::AccessibilityProps(
+ const AccessibilityProps &sourceProps,
+ const RawProps &rawProps)
+ : accessible(
+ convertRawProp(rawProps, "accessible", sourceProps.accessible)),
+ accessibilityTraits(convertRawProp(
+ rawProps,
+ "accessibilityTraits",
+ sourceProps.accessibilityTraits)),
+ accessibilityLabel(convertRawProp(
+ rawProps,
+ "accessibilityLabel",
+ sourceProps.accessibilityLabel)),
+ accessibilityHint(convertRawProp(
+ rawProps,
+ "accessibilityHint",
+ sourceProps.accessibilityHint)),
+ accessibilityActions(convertRawProp(
+ rawProps,
+ "accessibilityActions",
+ sourceProps.accessibilityActions)),
+ accessibilityViewIsModal(convertRawProp(
+ rawProps,
+ "accessibilityViewIsModal",
+ sourceProps.accessibilityViewIsModal)),
+ accessibilityElementsHidden(convertRawProp(
+ rawProps,
+ "accessibilityElementsHidden",
+ sourceProps.accessibilityElementsHidden)),
+ accessibilityIgnoresInvertColors(convertRawProp(
+ rawProps,
+ "accessibilityIgnoresInvertColors",
+ sourceProps.accessibilityIgnoresInvertColors)),
+ testId(convertRawProp(rawProps, "testId", sourceProps.testId)) {}
+
+#pragma mark - DebugStringConvertible
+
+#if RN_DEBUG_STRING_CONVERTIBLE
+SharedDebugStringConvertibleList AccessibilityProps::getDebugProps() const {
+ const auto &defaultProps = AccessibilityProps();
+ LOG(INFO) << "Call AccessibilityProps::getDebugProps with testId " << testId;
+ return SharedDebugStringConvertibleList{
+ debugStringConvertibleItem("testId", testId, defaultProps.testId),
+ };
+}
+#endif // RN_DEBUG_STRING_CONVERTIBLE
} // namespace react
} // namespace facebook

ReactCommon/fabric/components/view/accessibility/AccessibilityProps.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,10 +7,10 @@
#pragma once
-#include <fabric/components/view/AccessibilityPrimitives.h>
-#include <fabric/core/Props.h>
-#include <fabric/core/ReactPrimitives.h>
-#include <fabric/debug/DebugStringConvertible.h>
+#include <react/components/view/AccessibilityPrimitives.h>
+#include <react/core/Props.h>
+#include <react/core/ReactPrimitives.h>
+#include <react/debug/DebugStringConvertible.h>
namespace facebook {
namespace react {
@@ -19,22 +19,30 @@
typedef std::shared_ptr<const AccessibilityProps> SharedAccessibilityProps;
-class AccessibilityProps:
- public virtual DebugStringConvertible {
-
-public:
-
+class AccessibilityProps : public virtual DebugStringConvertible {
+ public:
AccessibilityProps() = default;
- AccessibilityProps(const AccessibilityProps &sourceProps, const RawProps &rawProps);
+ AccessibilityProps(
+ const AccessibilityProps &sourceProps,
+ const RawProps &rawProps);
#pragma mark - Props
- const bool accessible {true};
- const std::vector<std::string> accessibilityActions {};
- const std::string accessibilityLabel {""};
- const AccessibilityTraits accessibilityTraits {AccessibilityTraits::None};
- const bool accessibilityViewIsModal {false};
- const bool accessibilityElementsHidden {false};
+ const bool accessible{false};
+ const AccessibilityTraits accessibilityTraits{AccessibilityTraits::None};
+ const std::string accessibilityLabel{""};
+ const std::string accessibilityHint{""};
+ const std::vector<std::string> accessibilityActions{};
+ const bool accessibilityViewIsModal{false};
+ const bool accessibilityElementsHidden{false};
+ const bool accessibilityIgnoresInvertColors{false};
+ const std::string testId{""};
+
+#pragma mark - DebugStringConvertible
+
+#if RN_DEBUG_STRING_CONVERTIBLE
+ SharedDebugStringConvertibleList getDebugProps() const override;
+#endif
};
} // namespace react

ReactCommon/fabric/components/view/accessibility/accessibilityValuesConversions.cpp

@@ -1,23 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#include "accessibilityValuesConversions.h"
-
-#include <folly/Conv.h>
-
-namespace facebook {
-namespace react {
-
-AccessibilityTraits accessibilityTraitsFromDynamic(const folly::dynamic &value) {
- assert(value.isString());
-
- // FIXME: Not clear yet.
- abort();
-}
-
-} // namespace react
-} // namespace facebook

ReactCommon/fabric/components/view/accessibility/accessibilityValuesConversions.h

@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#pragma once
-
-#include <fabric/components/view/AccessibilityPrimitives.h>
-#include <folly/dynamic.h>
-
-namespace facebook {
-namespace react {
-
-AccessibilityTraits accessibilityTraitsFromDynamic(const folly::dynamic &value);
-
-} // namespace react
-} // namespace facebook

ReactCommon/fabric/components/view/accessibility/AccessibleShadowNode.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -13,16 +13,13 @@
namespace react {
AccessibleShadowNode::AccessibleShadowNode(
- const SharedAccessibilityProps &props
-) {
+ const SharedAccessibilityProps &props) {
assert(props);
}
AccessibleShadowNode::AccessibleShadowNode(
const AccessibleShadowNode &shadowNode,
- const SharedAccessibilityProps &props
-) {
-}
+ const SharedAccessibilityProps &props) {}
} // namespace react
} // namespace facebook

ReactCommon/fabric/components/view/accessibility/AccessibleShadowNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,8 +9,8 @@
#include <memory>
-#include <fabric/components/view/AccessibilityProps.h>
-#include <fabric/core/ShadowNode.h>
+#include <react/components/view/AccessibilityProps.h>
+#include <react/core/ShadowNode.h>
namespace facebook {
namespace react {
@@ -20,21 +20,16 @@
using SharedAccessibleShadowNode = std::shared_ptr<const AccessibleShadowNode>;
class AccessibleShadowNode {
-
-public:
-
+ public:
#pragma mark - Constructors
AccessibleShadowNode() = default;
- AccessibleShadowNode(
- const SharedAccessibilityProps &props
- );
+ AccessibleShadowNode(const SharedAccessibilityProps &props);
AccessibleShadowNode(
const AccessibleShadowNode &shadowNode,
- const SharedAccessibilityProps &props = nullptr
- );
+ const SharedAccessibilityProps &props = nullptr);
};
} // namespace react

ReactCommon/fabric/components/view/BUCK

@@ -1,4 +1,4 @@
-load("//configurations/buck/apple:flag_defs.bzl", "OBJC_ARC_PREPROCESSOR_FLAGS", "get_application_ios_flags", "get_debug_preprocessor_flags")
+load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags")
load(
"//tools/build_defs/oss:rn_defs.bzl",
"ANDROID",
@@ -31,7 +31,7 @@
("root", "*.h"),
("yoga", "*.h"),
],
- prefix = "fabric/components/view",
+ prefix = "react/components/view",
),
compiler_flags = [
"-fexceptions",
@@ -41,17 +41,15 @@
],
fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
- fbobjc_tests = [
- ":tests",
- ],
force_static = True,
macosx_tests_override = [],
platforms = (ANDROID, APPLE),
preprocessor_flags = [
"-DLOG_TAG=\"ReactNative\"",
- "-DWITH_FBSYSTRACE=1",
+ # Systraces are temporary disabled.
+ # "-DWITH_FBSYSTRACE=1",
],
- tests = [],
+ tests = [":tests"],
visibility = ["PUBLIC"],
deps = [
"xplat//fbsystrace:fbsystrace",
@@ -77,7 +75,7 @@
"-Wall",
],
contacts = ["oncall+react_native@xmail.facebook.com"],
- platforms = APPLE,
+ platforms = (ANDROID, APPLE),
deps = [
"xplat//folly:molly",
"xplat//third-party/gmock:gtest",

ReactCommon/fabric/components/view/ConcreteViewShadowNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,15 +7,15 @@
#pragma once
-#include <fabric/components/view/AccessibleShadowNode.h>
-#include <fabric/components/view/ViewEventEmitter.h>
-#include <fabric/components/view/ViewProps.h>
-#include <fabric/components/view/YogaLayoutableShadowNode.h>
-#include <fabric/core/ConcreteShadowNode.h>
-#include <fabric/core/LayoutableShadowNode.h>
-#include <fabric/core/ShadowNode.h>
-#include <fabric/core/ShadowNodeFragment.h>
-#include <fabric/debug/DebugStringConvertibleItem.h>
+#include <react/components/view/AccessibleShadowNode.h>
+#include <react/components/view/ViewEventEmitter.h>
+#include <react/components/view/ViewProps.h>
+#include <react/components/view/YogaLayoutableShadowNode.h>
+#include <react/core/ConcreteShadowNode.h>
+#include <react/core/LayoutableShadowNode.h>
+#include <react/core/ShadowNode.h>
+#include <react/core/ShadowNodeFragment.h>
+#include <react/debug/DebugStringConvertibleItem.h>
namespace facebook {
namespace react {
@@ -28,68 +28,59 @@
template <
const char *concreteComponentName,
typename ViewPropsT = ViewProps,
- typename ViewEventEmitterT = ViewEventEmitter
->
-class ConcreteViewShadowNode:
- public ConcreteShadowNode<
+ typename ViewEventEmitterT = ViewEventEmitter>
+class ConcreteViewShadowNode : public ConcreteShadowNode<
concreteComponentName,
ViewPropsT,
- ViewEventEmitterT
- >,
+ ViewEventEmitterT>,
public AccessibleShadowNode,
public YogaLayoutableShadowNode {
-
- static_assert(std::is_base_of<ViewProps, ViewPropsT>::value, "ViewPropsT must be a descendant of ViewProps");
- static_assert(std::is_base_of<YogaStylableProps, ViewPropsT>::value, "ViewPropsT must be a descendant of YogaStylableProps");
- static_assert(std::is_base_of<AccessibilityProps, ViewPropsT>::value, "ViewPropsT must be a descendant of AccessibilityProps");
-
-public:
- using BaseShadowNode = ConcreteShadowNode<
- concreteComponentName,
- ViewPropsT,
- ViewEventEmitterT
- >;
+ static_assert(
+ std::is_base_of<ViewProps, ViewPropsT>::value,
+ "ViewPropsT must be a descendant of ViewProps");
+ static_assert(
+ std::is_base_of<YogaStylableProps, ViewPropsT>::value,
+ "ViewPropsT must be a descendant of YogaStylableProps");
+ static_assert(
+ std::is_base_of<AccessibilityProps, ViewPropsT>::value,
+ "ViewPropsT must be a descendant of AccessibilityProps");
+
+ public:
+ using BaseShadowNode =
+ ConcreteShadowNode<concreteComponentName, ViewPropsT, ViewEventEmitterT>;
using ConcreteViewProps = ViewPropsT;
ConcreteViewShadowNode(
const ShadowNodeFragment &fragment,
- const ShadowNodeCloneFunction &cloneFunction
- ):
- BaseShadowNode(
- fragment,
- cloneFunction
- ),
+ const ShadowNodeCloneFunction &cloneFunction)
+ : BaseShadowNode(fragment, cloneFunction),
AccessibleShadowNode(
- std::static_pointer_cast<const ConcreteViewProps>(fragment.props)
- ),
+ std::static_pointer_cast<const ConcreteViewProps>(fragment.props)),
YogaLayoutableShadowNode() {
-
- YogaLayoutableShadowNode::setProps(*std::static_pointer_cast<const ConcreteViewProps>(fragment.props));
- YogaLayoutableShadowNode::setChildren(BaseShadowNode::template getChildrenSlice<YogaLayoutableShadowNode>());
+ YogaLayoutableShadowNode::setProps(
+ *std::static_pointer_cast<const ConcreteViewProps>(fragment.props));
+ YogaLayoutableShadowNode::setChildren(
+ BaseShadowNode::template getChildrenSlice<YogaLayoutableShadowNode>());
};
ConcreteViewShadowNode(
const ShadowNode &sourceShadowNode,
- const ShadowNodeFragment &fragment
- ):
- BaseShadowNode(
- sourceShadowNode,
- fragment
- ),
+ const ShadowNodeFragment &fragment)
+ : BaseShadowNode(sourceShadowNode, fragment),
AccessibleShadowNode(
static_cast<const ConcreteViewShadowNode &>(sourceShadowNode),
- std::static_pointer_cast<const ConcreteViewProps>(fragment.props)
- ),
+ std::static_pointer_cast<const ConcreteViewProps>(fragment.props)),
YogaLayoutableShadowNode(
- static_cast<const ConcreteViewShadowNode &>(sourceShadowNode)
- ) {
-
+ static_cast<const ConcreteViewShadowNode &>(sourceShadowNode)) {
if (fragment.props) {
- YogaLayoutableShadowNode::setProps(*std::static_pointer_cast<const ConcreteViewProps>(fragment.props));
+ YogaLayoutableShadowNode::setProps(
+ *std::static_pointer_cast<const ConcreteViewProps>(fragment.props));
}
if (fragment.children) {
- YogaLayoutableShadowNode::setChildren(BaseShadowNode::template getChildrenSlice<YogaLayoutableShadowNode>());
+ YogaLayoutableShadowNode::setChildren(
+ BaseShadowNode::template getChildrenSlice<
+ YogaLayoutableShadowNode>());
}
};
@@ -99,44 +90,44 @@
ShadowNode::appendChild(child);
auto nonConstChild = const_cast<ShadowNode *>(child.get());
- auto yogaLayoutableChild = dynamic_cast<YogaLayoutableShadowNode *>(nonConstChild);
+ auto yogaLayoutableChild =
+ dynamic_cast<YogaLayoutableShadowNode *>(nonConstChild);
if (yogaLayoutableChild) {
YogaLayoutableShadowNode::appendChild(yogaLayoutableChild);
}
}
- LayoutableShadowNode *cloneAndReplaceChild(LayoutableShadowNode *child, int suggestedIndex = -1) override {
+ LayoutableShadowNode *cloneAndReplaceChild(
+ LayoutableShadowNode *child,
+ int suggestedIndex = -1) override {
ensureUnsealed();
auto childShadowNode = static_cast<const ConcreteViewShadowNode *>(child);
- auto clonedChildShadowNode = std::static_pointer_cast<ConcreteViewShadowNode>(childShadowNode->clone({}));
- ShadowNode::replaceChild(childShadowNode->shared_from_this(), clonedChildShadowNode, suggestedIndex);
+ auto clonedChildShadowNode =
+ std::static_pointer_cast<ConcreteViewShadowNode>(
+ childShadowNode->clone({}));
+ ShadowNode::replaceChild(
+ childShadowNode->shared_from_this(),
+ clonedChildShadowNode,
+ suggestedIndex);
return clonedChildShadowNode.get();
}
-#pragma mark - Equality
-
- bool operator==(const ShadowNode& rhs) const override {
- if (!ShadowNode::operator==(rhs)) {
- return false;
- }
-
- const auto &other = static_cast<const ConcreteViewShadowNode&>(rhs);
- return getLayoutMetrics() == other.getLayoutMetrics();
- }
-
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList getDebugProps() const override {
- SharedDebugStringConvertibleList list = {};
+ auto list = SharedDebugStringConvertibleList{};
auto basePropsList = ShadowNode::getDebugProps();
- std::move(basePropsList.begin(), basePropsList.end(), std::back_inserter(list));
+ std::move(
+ basePropsList.begin(), basePropsList.end(), std::back_inserter(list));
- list.push_back(std::make_shared<DebugStringConvertibleItem>("layout", "", LayoutableShadowNode::getDebugProps()));
+ list.push_back(std::make_shared<DebugStringConvertibleItem>(
+ "layout", "", LayoutableShadowNode::getDebugProps()));
return list;
}
-
+#endif
};
} // namespace react

ReactCommon/fabric/components/view/conversions.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,18 +7,20 @@
#pragma once
-#include <fabric/components/view/primitives.h>
-#include <fabric/core/LayoutMetrics.h>
-#include <fabric/graphics/Geometry.h>
-#include <folly/dynamic.h>
#include <folly/Conv.h>
-#include <yoga/Yoga.h>
+#include <folly/dynamic.h>
+#include <react/components/view/primitives.h>
+#include <react/core/LayoutMetrics.h>
+#include <react/graphics/Geometry.h>
+#include <yoga/YGEnums.h>
#include <yoga/YGNode.h>
+#include <yoga/Yoga.h>
+#include <cmath>
namespace facebook {
namespace react {
-inline Float fabricFloatFromYogaFloat(float value) {
+inline Float floatFromYogaFloat(float value) {
if (value == YGUndefined) {
return kFloatUndefined;
}
@@ -26,7 +28,7 @@
return (Float)value;
}
-inline float yogaFloatFromFabricFloat(Float value) {
+inline float yogaFloatFromFloat(Float value) {
if (value == kFloatUndefined) {
return YGUndefined;
}
@@ -34,163 +36,287 @@
return (float)value;
}
-inline Float fabricFloatFromYogaOptionalFloat(YGFloatOptional value) {
+inline Float floatFromYogaOptionalFloat(YGFloatOptional value) {
if (value.isUndefined()) {
return kFloatUndefined;
}
- return fabricFloatFromYogaFloat(value.getValue());
+ return floatFromYogaFloat(value.unwrap());
}
-inline YGFloatOptional yogaOptionalFloatFromFabricFloat(Float value) {
+inline YGFloatOptional yogaOptionalFloatFromFloat(Float value) {
if (value == kFloatUndefined) {
return YGFloatOptional();
}
- return YGFloatOptional(yogaFloatFromFabricFloat(value));
+ return YGFloatOptional(yogaFloatFromFloat(value));
}
inline YGValue yogaStyleValueFromFloat(const Float &value) {
- if (isnan(value) || value == kFloatUndefined) {
+ if (std::isnan(value) || value == kFloatUndefined) {
return YGValueUndefined;
}
return {(float)value, YGUnitPoint};
}
-inline LayoutMetrics layoutMetricsFromYogaNode(YGNode &yogaNode) {
- LayoutMetrics layoutMetrics;
-
- YGLayout layout = yogaNode.getLayout();
+inline folly::Optional<Float> optionalFloatFromYogaValue(
+ const YGValue value,
+ folly::Optional<Float> base = {}) {
+ switch (value.unit) {
+ case YGUnitUndefined:
+ return {};
+ case YGUnitPoint:
+ return floatFromYogaFloat(value.value);
+ case YGUnitPercent:
+ return base.has_value()
+ ? folly::Optional<Float>(
+ base.value() * floatFromYogaFloat(value.value))
+ : folly::Optional<Float>();
+ case YGUnitAuto:
+ return {};
+ }
+}
- layoutMetrics.frame = Rect {
- Point {
- fabricFloatFromYogaFloat(layout.position[YGEdgeLeft]),
- fabricFloatFromYogaFloat(layout.position[YGEdgeTop])
- },
- Size {
- fabricFloatFromYogaFloat(layout.dimensions[YGDimensionWidth]),
- fabricFloatFromYogaFloat(layout.dimensions[YGDimensionHeight])
- }
- };
-
- layoutMetrics.borderWidth = EdgeInsets {
- fabricFloatFromYogaFloat(layout.border[YGEdgeLeft]),
- fabricFloatFromYogaFloat(layout.border[YGEdgeTop]),
- fabricFloatFromYogaFloat(layout.border[YGEdgeRight]),
- fabricFloatFromYogaFloat(layout.border[YGEdgeBottom])
- };
-
- layoutMetrics.contentInsets = EdgeInsets {
- fabricFloatFromYogaFloat(layout.border[YGEdgeLeft] + layout.padding[YGEdgeLeft]),
- fabricFloatFromYogaFloat(layout.border[YGEdgeTop] + layout.padding[YGEdgeTop]),
- fabricFloatFromYogaFloat(layout.border[YGEdgeRight] + layout.padding[YGEdgeRight]),
- fabricFloatFromYogaFloat(layout.border[YGEdgeBottom] + layout.padding[YGEdgeBottom])
- };
+inline LayoutMetrics layoutMetricsFromYogaNode(YGNode &yogaNode) {
+ auto layoutMetrics = LayoutMetrics{};
- layoutMetrics.displayType =
- yogaNode.getStyle().display == YGDisplayNone ? DisplayType::None : DisplayType::Flex;
+ layoutMetrics.frame =
+ Rect{Point{floatFromYogaFloat(YGNodeLayoutGetLeft(&yogaNode)),
+ floatFromYogaFloat(YGNodeLayoutGetTop(&yogaNode))},
+ Size{floatFromYogaFloat(YGNodeLayoutGetWidth(&yogaNode)),
+ floatFromYogaFloat(YGNodeLayoutGetHeight(&yogaNode))}};
+
+ layoutMetrics.borderWidth = EdgeInsets{
+ floatFromYogaFloat(YGNodeLayoutGetBorder(&yogaNode, YGEdgeLeft)),
+ floatFromYogaFloat(YGNodeLayoutGetBorder(&yogaNode, YGEdgeTop)),
+ floatFromYogaFloat(YGNodeLayoutGetBorder(&yogaNode, YGEdgeRight)),
+ floatFromYogaFloat(YGNodeLayoutGetBorder(&yogaNode, YGEdgeBottom))};
+
+ layoutMetrics.contentInsets = EdgeInsets{
+ layoutMetrics.borderWidth.left +
+ floatFromYogaFloat(YGNodeLayoutGetPadding(&yogaNode, YGEdgeLeft)),
+ layoutMetrics.borderWidth.top +
+ floatFromYogaFloat(YGNodeLayoutGetPadding(&yogaNode, YGEdgeTop)),
+ layoutMetrics.borderWidth.right +
+ floatFromYogaFloat(YGNodeLayoutGetPadding(&yogaNode, YGEdgeRight)),
+ layoutMetrics.borderWidth.bottom +
+ floatFromYogaFloat(YGNodeLayoutGetPadding(&yogaNode, YGEdgeBottom))};
+
+ layoutMetrics.displayType = yogaNode.getStyle().display == YGDisplayNone
+ ? DisplayType::None
+ : DisplayType::Flex;
layoutMetrics.layoutDirection =
- layout.direction == YGDirectionRTL ? LayoutDirection::RightToLeft : LayoutDirection::LeftToRight;
+ YGNodeLayoutGetDirection(&yogaNode) == YGDirectionRTL
+ ? LayoutDirection::RightToLeft
+ : LayoutDirection::LeftToRight;
return layoutMetrics;
}
-inline void fromDynamic(const folly::dynamic &value, YGDirection &result) {
- assert(value.isString());
- auto stringValue = value.asString();
- if (stringValue == "inherit") { result = YGDirectionInherit; return; }
- if (stringValue == "ltr") { result = YGDirectionLTR; return; }
- if (stringValue == "rtl") { result = YGDirectionRTL; return; }
+inline YGDirection yogaDirectionFromLayoutDirection(LayoutDirection direction) {
+ switch (direction) {
+ case LayoutDirection::Undefined:
+ return YGDirectionInherit;
+ case LayoutDirection::LeftToRight:
+ return YGDirectionLTR;
+ case LayoutDirection::RightToLeft:
+ return YGDirectionRTL;
+ }
+}
+
+inline void fromRawValue(const RawValue &value, YGDirection &result) {
+ assert(value.hasType<std::string>());
+ auto stringValue = (std::string)value;
+ if (stringValue == "inherit") {
+ result = YGDirectionInherit;
+ return;
+ }
+ if (stringValue == "ltr") {
+ result = YGDirectionLTR;
+ return;
+ }
+ if (stringValue == "rtl") {
+ result = YGDirectionRTL;
+ return;
+ }
abort();
}
-inline void fromDynamic(const folly::dynamic &value, YGFlexDirection &result) {
- assert(value.isString());
- auto stringValue = value.asString();
- if (stringValue == "column") { result = YGFlexDirectionColumn; return; }
- if (stringValue == "column-reverse") { result = YGFlexDirectionColumnReverse; return; }
- if (stringValue == "row") { result = YGFlexDirectionRow; return; }
- if (stringValue == "row-reverse") { result = YGFlexDirectionRowReverse; return; }
+inline void fromRawValue(const RawValue &value, YGFlexDirection &result) {
+ assert(value.hasType<std::string>());
+ auto stringValue = (std::string)value;
+ if (stringValue == "column") {
+ result = YGFlexDirectionColumn;
+ return;
+ }
+ if (stringValue == "column-reverse") {
+ result = YGFlexDirectionColumnReverse;
+ return;
+ }
+ if (stringValue == "row") {
+ result = YGFlexDirectionRow;
+ return;
+ }
+ if (stringValue == "row-reverse") {
+ result = YGFlexDirectionRowReverse;
+ return;
+ }
abort();
}
-inline void fromDynamic(const folly::dynamic &value, YGJustify &result) {
- assert(value.isString());
- auto stringValue = value.asString();
- if (stringValue == "flex-start") { result = YGJustifyFlexStart; return; }
- if (stringValue == "center") { result = YGJustifyCenter; return; }
- if (stringValue == "flex-end") { result = YGJustifyFlexEnd; return; }
- if (stringValue == "space-between") { result = YGJustifySpaceBetween; return; }
- if (stringValue == "space-around") { result = YGJustifySpaceAround; return; }
- if (stringValue == "space-evenly") { result = YGJustifySpaceEvenly; return; }
+inline void fromRawValue(const RawValue &value, YGJustify &result) {
+ assert(value.hasType<std::string>());
+ auto stringValue = (std::string)value;
+ if (stringValue == "flex-start") {
+ result = YGJustifyFlexStart;
+ return;
+ }
+ if (stringValue == "center") {
+ result = YGJustifyCenter;
+ return;
+ }
+ if (stringValue == "flex-end") {
+ result = YGJustifyFlexEnd;
+ return;
+ }
+ if (stringValue == "space-between") {
+ result = YGJustifySpaceBetween;
+ return;
+ }
+ if (stringValue == "space-around") {
+ result = YGJustifySpaceAround;
+ return;
+ }
+ if (stringValue == "space-evenly") {
+ result = YGJustifySpaceEvenly;
+ return;
+ }
abort();
}
-inline void fromDynamic(const folly::dynamic &value, YGAlign &result) {
- assert(value.isString());
- auto stringValue = value.asString();
- if (stringValue == "auto") { result = YGAlignAuto; return; }
- if (stringValue == "flex-start") { result = YGAlignFlexStart; return; }
- if (stringValue == "center") { result = YGAlignCenter; return; }
- if (stringValue == "flex-end") { result = YGAlignFlexEnd; return; }
- if (stringValue == "stretch") { result = YGAlignStretch; return; }
- if (stringValue == "baseline") { result = YGAlignBaseline; return; }
- if (stringValue == "between") { result = YGAlignSpaceBetween; return; }
- if (stringValue == "space-around") { result = YGAlignSpaceAround; return; }
+inline void fromRawValue(const RawValue &value, YGAlign &result) {
+ assert(value.hasType<std::string>());
+ auto stringValue = (std::string)value;
+ if (stringValue == "auto") {
+ result = YGAlignAuto;
+ return;
+ }
+ if (stringValue == "flex-start") {
+ result = YGAlignFlexStart;
+ return;
+ }
+ if (stringValue == "center") {
+ result = YGAlignCenter;
+ return;
+ }
+ if (stringValue == "flex-end") {
+ result = YGAlignFlexEnd;
+ return;
+ }
+ if (stringValue == "stretch") {
+ result = YGAlignStretch;
+ return;
+ }
+ if (stringValue == "baseline") {
+ result = YGAlignBaseline;
+ return;
+ }
+ if (stringValue == "between") {
+ result = YGAlignSpaceBetween;
+ return;
+ }
+ if (stringValue == "space-around") {
+ result = YGAlignSpaceAround;
+ return;
+ }
abort();
}
-inline void fromDynamic(const folly::dynamic &value, YGPositionType &result) {
- assert(value.isString());
- auto stringValue = value.asString();
- if (stringValue == "relative") { result = YGPositionTypeRelative; return; }
- if (stringValue == "absolute") { result = YGPositionTypeAbsolute; return; }
+inline void fromRawValue(const RawValue &value, YGPositionType &result) {
+ assert(value.hasType<std::string>());
+ auto stringValue = (std::string)value;
+ if (stringValue == "relative") {
+ result = YGPositionTypeRelative;
+ return;
+ }
+ if (stringValue == "absolute") {
+ result = YGPositionTypeAbsolute;
+ return;
+ }
abort();
}
-inline void fromDynamic(const folly::dynamic &value, YGWrap &result) {
- assert(value.isString());
- auto stringValue = value.asString();
- if (stringValue == "no-wrap") { result = YGWrapNoWrap; return; }
- if (stringValue == "wrap") { result = YGWrapWrap; return; }
- if (stringValue == "wrap-reverse") { result = YGWrapWrapReverse; return; }
+inline void fromRawValue(const RawValue &value, YGWrap &result) {
+ assert(value.hasType<std::string>());
+ auto stringValue = (std::string)value;
+ if (stringValue == "no-wrap") {
+ result = YGWrapNoWrap;
+ return;
+ }
+ if (stringValue == "wrap") {
+ result = YGWrapWrap;
+ return;
+ }
+ if (stringValue == "wrap-reverse") {
+ result = YGWrapWrapReverse;
+ return;
+ }
abort();
}
-inline void fromDynamic(const folly::dynamic &value, YGOverflow &result) {
- assert(value.isString());
- auto stringValue = value.asString();
- if (stringValue == "visible") { result = YGOverflowVisible; return; }
- if (stringValue == "hidden") { result = YGOverflowHidden; return; }
- if (stringValue == "scroll") { result = YGOverflowScroll; return; }
+inline void fromRawValue(const RawValue &value, YGOverflow &result) {
+ assert(value.hasType<std::string>());
+ auto stringValue = (std::string)value;
+ if (stringValue == "visible") {
+ result = YGOverflowVisible;
+ return;
+ }
+ if (stringValue == "hidden") {
+ result = YGOverflowHidden;
+ return;
+ }
+ if (stringValue == "scroll") {
+ result = YGOverflowScroll;
+ return;
+ }
abort();
}
-inline void fromDynamic(const folly::dynamic &value, YGDisplay &result) {
- assert(value.isString());
- auto stringValue = value.asString();
- if (stringValue == "flex") { result = YGDisplayFlex; return; }
- if (stringValue == "none") { result = YGDisplayNone; return; }
+inline void fromRawValue(const RawValue &value, YGDisplay &result) {
+ assert(value.hasType<std::string>());
+ auto stringValue = (std::string)value;
+ if (stringValue == "flex") {
+ result = YGDisplayFlex;
+ return;
+ }
+ if (stringValue == "none") {
+ result = YGDisplayNone;
+ return;
+ }
abort();
}
-inline void fromDynamic(const folly::dynamic &value, YGValue &result) {
- if (value.isNumber()) {
- result = yogaStyleValueFromFloat(value.asDouble());
+inline void fromRawValue(
+ const RawValue &value,
+ decltype(YGStyle{}.margin[0]) /* type is subject to change */ &result) {
+ if (value.hasType<Float>()) {
+ result = yogaStyleValueFromFloat((Float)value);
return;
- } else if (value.isString()) {
- const auto stringValue = value.asString();
+ } else if (value.hasType<std::string>()) {
+ const auto stringValue = (std::string)value;
if (stringValue == "auto") {
result = YGValueUndefined;
return;
} else {
if (stringValue.back() == '%') {
- result = { folly::to<float>(stringValue.substr(0, stringValue.length() - 1)), YGUnitPercent };
+ result = YGValue{
+ folly::to<float>(stringValue.substr(0, stringValue.length() - 1)),
+ YGUnitPercent};
return;
} else {
- result = { folly::to<float>(stringValue), YGUnitPoint };
+ result = YGValue{folly::to<float>(stringValue), YGUnitPoint};
return;
}
}
@@ -198,12 +324,12 @@
result = YGValueUndefined;
}
-inline void fromDynamic(const folly::dynamic &value, YGFloatOptional &result) {
- if (value.isNumber()) {
- result = YGFloatOptional(value.asDouble());
+inline void fromRawValue(const RawValue &value, YGFloatOptional &result) {
+ if (value.hasType<float>()) {
+ result = YGFloatOptional((float)value);
return;
- } else if (value.isString()) {
- const auto stringValue = value.asString();
+ } else if (value.hasType<std::string>()) {
+ const auto stringValue = (std::string)value;
if (stringValue == "auto") {
result = YGFloatOptional();
return;
@@ -212,84 +338,125 @@
abort();
}
-inline void fromDynamic(const folly::dynamic &value, Transform &result) {
- assert(value.isArray());
- Transform transformMatrix;
- for (const auto &tranformConfiguration : value) {
- assert(tranformConfiguration.isObject());
- auto pair = *tranformConfiguration.items().begin();
- const auto &operation = pair.first.asString();
- const auto &parameters = pair.second;
+inline void fromRawValue(const RawValue &value, Transform &result) {
+ assert(value.hasType<std::vector<RawValue>>());
+ auto transformMatrix = Transform{};
+ auto configurations = (std::vector<RawValue>)value;
+
+ for (const auto &configuration : configurations) {
+ auto configurationPair =
+ (std::unordered_map<std::string, RawValue>)configuration;
+ auto pair = configurationPair.begin();
+ auto operation = pair->first;
+ auto &parameters = pair->second;
if (operation == "matrix") {
- assert(parameters.isArray());
- assert(parameters.size() == transformMatrix.matrix.size());
- int i = 0;
- for (auto item : parameters) {
- transformMatrix.matrix[i++] = (Float)item.asDouble();
+ assert(parameters.hasType<std::vector<Float>>());
+ auto numbers = (std::vector<Float>)parameters;
+ assert(numbers.size() == transformMatrix.matrix.size());
+ auto i = 0;
+ for (auto number : numbers) {
+ transformMatrix.matrix[i++] = number;
}
} else if (operation == "perspective") {
- transformMatrix = transformMatrix * Transform::Perspective((Float)parameters.asDouble());
+ transformMatrix =
+ transformMatrix * Transform::Perspective((Float)parameters);
} else if (operation == "rotateX") {
- transformMatrix = transformMatrix * Transform::Rotate((Float)parameters.asDouble(), 0, 0);
+ transformMatrix =
+ transformMatrix * Transform::Rotate((Float)parameters, 0, 0);
} else if (operation == "rotateY") {
- transformMatrix = transformMatrix * Transform::Rotate(0, (Float)parameters.asDouble(), 0);
+ transformMatrix =
+ transformMatrix * Transform::Rotate(0, (Float)parameters, 0);
} else if (operation == "rotateZ") {
- transformMatrix = transformMatrix * Transform::Rotate(0, 0, (Float)parameters.asDouble());
+ transformMatrix =
+ transformMatrix * Transform::Rotate(0, 0, (Float)parameters);
} else if (operation == "scale") {
- transformMatrix = transformMatrix * Transform::Scale((Float)parameters.asDouble(), (Float)parameters.asDouble(), (Float)parameters.asDouble());
+ auto number = (Float)parameters;
+ transformMatrix =
+ transformMatrix * Transform::Scale(number, number, number);
} else if (operation == "scaleX") {
- transformMatrix = transformMatrix * Transform::Scale((Float)parameters.asDouble(), 0, 0);
+ transformMatrix =
+ transformMatrix * Transform::Scale((Float)parameters, 0, 0);
} else if (operation == "scaleY") {
- transformMatrix = transformMatrix * Transform::Scale(0, (Float)parameters.asDouble(), 0);
+ transformMatrix =
+ transformMatrix * Transform::Scale(0, (Float)parameters, 0);
} else if (operation == "scaleZ") {
- transformMatrix = transformMatrix * Transform::Scale(0, 0, (Float)parameters.asDouble());
+ transformMatrix =
+ transformMatrix * Transform::Scale(0, 0, (Float)parameters);
} else if (operation == "translate") {
- transformMatrix = transformMatrix * Transform::Translate(parameters[0].asDouble(), parameters[1].asDouble(), 0);
+ auto numbers = (std::vector<Float>)parameters;
+ transformMatrix = transformMatrix *
+ Transform::Translate(numbers.at(0), numbers.at(1), 0);
} else if (operation == "translateX") {
- transformMatrix = transformMatrix * Transform::Translate(parameters.asDouble(), 0, 0);
+ transformMatrix =
+ transformMatrix * Transform::Translate((Float)parameters, 0, 0);
} else if (operation == "translateY") {
- transformMatrix = transformMatrix * Transform::Translate(0, parameters.asDouble(), 0);
+ transformMatrix =
+ transformMatrix * Transform::Translate(0, (Float)parameters, 0);
} else if (operation == "skewX") {
- transformMatrix = transformMatrix * Transform::Skew(parameters.asDouble(), 0);
+ transformMatrix = transformMatrix * Transform::Skew((Float)parameters, 0);
} else if (operation == "skewY") {
- transformMatrix = transformMatrix * Transform::Skew(0, parameters.asDouble());
+ transformMatrix = transformMatrix * Transform::Skew(0, (Float)parameters);
}
}
result = transformMatrix;
}
-inline void fromDynamic(const folly::dynamic &value, PointerEventsMode &result) {
- assert(value.isString());
- auto stringValue = value.asString();
- if (stringValue == "auto") { result = PointerEventsMode::Auto; return; }
- if (stringValue == "none") { result = PointerEventsMode::None; return; }
- if (stringValue == "box-none") { result = PointerEventsMode::BoxNone; return; }
- if (stringValue == "box-only") { result = PointerEventsMode::BoxOnly; return; }
+inline void fromRawValue(const RawValue &value, PointerEventsMode &result) {
+ assert(value.hasType<std::string>());
+ auto stringValue = (std::string)value;
+ if (stringValue == "auto") {
+ result = PointerEventsMode::Auto;
+ return;
+ }
+ if (stringValue == "none") {
+ result = PointerEventsMode::None;
+ return;
+ }
+ if (stringValue == "box-none") {
+ result = PointerEventsMode::BoxNone;
+ return;
+ }
+ if (stringValue == "box-only") {
+ result = PointerEventsMode::BoxOnly;
+ return;
+ }
abort();
}
-inline void fromDynamic(const folly::dynamic &value, BorderStyle &result) {
- assert(value.isString());
- auto stringValue = value.asString();
- if (stringValue == "solid") { result = BorderStyle::Solid; return; }
- if (stringValue == "dotted") { result = BorderStyle::Dotted; return; }
- if (stringValue == "dashed") { result = BorderStyle::Dashed; return; }
+inline void fromRawValue(const RawValue &value, BorderStyle &result) {
+ assert(value.hasType<std::string>());
+ auto stringValue = (std::string)value;
+ if (stringValue == "solid") {
+ result = BorderStyle::Solid;
+ return;
+ }
+ if (stringValue == "dotted") {
+ result = BorderStyle::Dotted;
+ return;
+ }
+ if (stringValue == "dashed") {
+ result = BorderStyle::Dashed;
+ return;
+ }
abort();
}
-inline std::string toString(const std::array<float, YGDimensionCount> &dimensions) {
- return "{" + folly::to<std::string>(dimensions[0]) + ", " + folly::to<std::string>(dimensions[1]) + "}";
+inline std::string toString(
+ const std::array<float, yoga::enums::count<YGDimension>()> &dimensions) {
+ return "{" + folly::to<std::string>(dimensions[0]) + ", " +
+ folly::to<std::string>(dimensions[1]) + "}";
}
inline std::string toString(const std::array<float, 4> &position) {
- return "{" + folly::to<std::string>(position[0]) + ", " + folly::to<std::string>(position[1]) + "}";
+ return "{" + folly::to<std::string>(position[0]) + ", " +
+ folly::to<std::string>(position[1]) + "}";
}
-inline std::string toString(const std::array<float, YGEdgeCount> &edges) {
- return "{" +
- folly::to<std::string>(edges[0]) + ", " +
+inline std::string toString(
+ const std::array<float, yoga::enums::count<YGEdge>()> &edges) {
+ return "{" + folly::to<std::string>(edges[0]) + ", " +
folly::to<std::string>(edges[1]) + ", " +
folly::to<std::string>(edges[2]) + ", " +
folly::to<std::string>(edges[3]) + "}";
@@ -297,81 +464,116 @@
inline std::string toString(const YGDirection &value) {
switch (value) {
- case YGDirectionInherit: return "inherit";
- case YGDirectionLTR: return "ltr";
- case YGDirectionRTL: return "rtl";
+ case YGDirectionInherit:
+ return "inherit";
+ case YGDirectionLTR:
+ return "ltr";
+ case YGDirectionRTL:
+ return "rtl";
}
}
inline std::string toString(const YGFlexDirection &value) {
switch (value) {
- case YGFlexDirectionColumn: return "column";
- case YGFlexDirectionColumnReverse: return "column-reverse";
- case YGFlexDirectionRow: return "row";
- case YGFlexDirectionRowReverse: return "row-reverse";
+ case YGFlexDirectionColumn:
+ return "column";
+ case YGFlexDirectionColumnReverse:
+ return "column-reverse";
+ case YGFlexDirectionRow:
+ return "row";
+ case YGFlexDirectionRowReverse:
+ return "row-reverse";
}
}
inline std::string toString(const YGJustify &value) {
switch (value) {
- case YGJustifyFlexStart: return "flex-start";
- case YGJustifyCenter: return "center";
- case YGJustifyFlexEnd: return "flex-end";
- case YGJustifySpaceBetween: return "space-between";
- case YGJustifySpaceAround: return "space-around";
- case YGJustifySpaceEvenly: return "space-evenly";
+ case YGJustifyFlexStart:
+ return "flex-start";
+ case YGJustifyCenter:
+ return "center";
+ case YGJustifyFlexEnd:
+ return "flex-end";
+ case YGJustifySpaceBetween:
+ return "space-between";
+ case YGJustifySpaceAround:
+ return "space-around";
+ case YGJustifySpaceEvenly:
+ return "space-evenly";
}
}
inline std::string toString(const YGAlign &value) {
switch (value) {
- case YGAlignAuto: return "auto";
- case YGAlignFlexStart: return "flex-start";
- case YGAlignCenter: return "center";
- case YGAlignFlexEnd: return "flex-end";
- case YGAlignStretch: return "stretch";
- case YGAlignBaseline: return "baseline";
- case YGAlignSpaceBetween: return "space-between";
- case YGAlignSpaceAround: return "space-around";
+ case YGAlignAuto:
+ return "auto";
+ case YGAlignFlexStart:
+ return "flex-start";
+ case YGAlignCenter:
+ return "center";
+ case YGAlignFlexEnd:
+ return "flex-end";
+ case YGAlignStretch:
+ return "stretch";
+ case YGAlignBaseline:
+ return "baseline";
+ case YGAlignSpaceBetween:
+ return "space-between";
+ case YGAlignSpaceAround:
+ return "space-around";
}
}
inline std::string toString(const YGPositionType &value) {
switch (value) {
- case YGPositionTypeRelative: return "relative";
- case YGPositionTypeAbsolute: return "absolute";
+ case YGPositionTypeRelative:
+ return "relative";
+ case YGPositionTypeAbsolute:
+ return "absolute";
}
}
inline std::string toString(const YGWrap &value) {
switch (value) {
- case YGWrapNoWrap: return "no-wrap";
- case YGWrapWrap: return "wrap";
- case YGWrapWrapReverse: return "wrap-reverse";
+ case YGWrapNoWrap:
+ return "no-wrap";
+ case YGWrapWrap:
+ return "wrap";
+ case YGWrapWrapReverse:
+ return "wrap-reverse";
}
}
inline std::string toString(const YGOverflow &value) {
switch (value) {
- case YGOverflowVisible: return "visible";
- case YGOverflowScroll: return "scroll";
- case YGOverflowHidden: return "hidden";
+ case YGOverflowVisible:
+ return "visible";
+ case YGOverflowScroll:
+ return "scroll";
+ case YGOverflowHidden:
+ return "hidden";
}
}
inline std::string toString(const YGDisplay &value) {
switch (value) {
- case YGDisplayFlex: return "flex";
- case YGDisplayNone: return "none";
+ case YGDisplayFlex:
+ return "flex";
+ case YGDisplayNone:
+ return "none";
}
}
inline std::string toString(const YGValue &value) {
switch (value.unit) {
- case YGUnitUndefined: return "undefined";
- case YGUnitPoint: return folly::to<std::string>(value.value);
- case YGUnitPercent: return folly::to<std::string>(value.value) + "%";
- case YGUnitAuto: return "auto";
+ case YGUnitUndefined:
+ return "undefined";
+ case YGUnitPoint:
+ return folly::to<std::string>(value.value);
+ case YGUnitPercent:
+ return folly::to<std::string>(value.value) + "%";
+ case YGUnitAuto:
+ return "auto";
}
}
@@ -380,28 +582,34 @@
return "undefined";
}
- return folly::to<std::string>(fabricFloatFromYogaFloat(value.getValue()));
+ return folly::to<std::string>(floatFromYogaFloat(value.unwrap()));
}
-inline std::string toString(const std::array<YGValue, YGDimensionCount> &value) {
- return "{" +
- toString(value[0]) + ", " +
- toString(value[1]) + "}";
+inline std::string toString(const YGStyle::Dimensions &value) {
+ return "{" + toString(value[0]) + ", " + toString(value[1]) + "}";
}
-inline std::string toString(const std::array<YGValue, YGEdgeCount> &value) {
- static std::array<std::string, YGEdgeCount> names = {
- {"left", "top", "right", "bottom", "start", "end", "horizontal", "vertical", "all"}
- };
-
- std::string result;
- std::string separator = ", ";
-
- for (int i = 0; i < YGEdgeCount; i++) {
- if (value[i].unit == YGUnitUndefined) {
+inline std::string toString(const YGStyle::Edges &value) {
+ static std::array<std::string, yoga::enums::count<YGEdge>()> names = {
+ {"left",
+ "top",
+ "right",
+ "bottom",
+ "start",
+ "end",
+ "horizontal",
+ "vertical",
+ "all"}};
+
+ auto result = std::string{};
+ auto separator = std::string{", "};
+
+ for (auto i = 0; i < yoga::enums::count<YGEdge>(); i++) {
+ YGValue v = value[i];
+ if (v.unit == YGUnitUndefined) {
continue;
}
- result += names[i] + ": " + toString(value[i]) + separator;
+ result += names[i] + ": " + toString(v) + separator;
}
if (!result.empty()) {

ReactCommon/fabric/components/view/primitives.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,33 +7,32 @@
#pragma once
+#include <folly/Optional.h>
+#include <react/graphics/Color.h>
+#include <react/graphics/Geometry.h>
+#include <array>
#include <cmath>
-#include <fabric/graphics/Geometry.h>
namespace facebook {
namespace react {
struct Transform {
- std::array<Float, 16> matrix {{
- 1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- 0, 0, 0, 1
- }};
+ std::array<Float, 16> matrix{
+ {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}};
static Transform Identity() {
- Transform transform;
- return transform;
+ return {};
}
static Transform Perspective(const Float &perspective) {
- Transform transform;
+ auto transform = Transform{};
transform.matrix[11] = -1.0 / perspective;
return transform;
}
- static Transform Scale(const Float &factorX, const Float &factorY, const Float &factorZ) {
- Transform transform;
+ static Transform
+ Scale(const Float &factorX, const Float &factorY, const Float &factorZ) {
+ auto transform = Transform{};
transform.matrix[0] = factorX;
transform.matrix[5] = factorY;
transform.matrix[10] = factorZ;
@@ -41,7 +40,7 @@
}
static Transform Translate(const Float &x, const Float &y, const Float &z) {
- Transform transform;
+ auto transform = Transform{};
transform.matrix[12] = x;
transform.matrix[13] = y;
transform.matrix[14] = z;
@@ -49,14 +48,14 @@
}
static Transform Skew(const Float &x, const Float &y) {
- Transform transform;
+ auto transform = Transform{};
transform.matrix[4] = std::tan(x);
transform.matrix[1] = std::tan(y);
return transform;
}
static Transform RotateX(const Float &radians) {
- Transform transform;
+ auto transform = Transform{};
transform.matrix[5] = std::cos(radians);
transform.matrix[6] = std::sin(radians);
transform.matrix[9] = -std::sin(radians);
@@ -65,7 +64,7 @@
}
static Transform RotateY(const Float &radians) {
- Transform transform;
+ auto transform = Transform{};
transform.matrix[0] = std::cos(radians);
transform.matrix[2] = -std::sin(radians);
transform.matrix[8] = std::sin(radians);
@@ -74,7 +73,7 @@
}
static Transform RotateZ(const Float &radians) {
- Transform transform;
+ auto transform = Transform{};
transform.matrix[0] = std::cos(radians);
transform.matrix[1] = std::sin(radians);
transform.matrix[4] = -std::sin(radians);
@@ -83,15 +82,21 @@
}
static Transform Rotate(const Float &x, const Float &y, const Float &z) {
- Transform transform;
- if (x != 0) { transform = transform * Transform::RotateX(x); }
- if (y != 0) { transform = transform * Transform::RotateY(y); }
- if (z != 0) { transform = transform * Transform::RotateZ(z); }
+ auto transform = Transform{};
+ if (x != 0) {
+ transform = transform * Transform::RotateX(x);
+ }
+ if (y != 0) {
+ transform = transform * Transform::RotateY(y);
+ }
+ if (z != 0) {
+ transform = transform * Transform::RotateZ(z);
+ }
return transform;
}
- bool operator ==(const Transform& rhs) const {
- for (int i = 0; i < 16; i++) {
+ bool operator==(const Transform &rhs) const {
+ for (auto i = 0; i < 16; i++) {
if (matrix[i] != rhs.matrix[i]) {
return false;
}
@@ -99,62 +104,233 @@
return true;
}
- bool operator !=(const Transform& rhs) const {
+ bool operator!=(const Transform &rhs) const {
return !(*this == rhs);
}
- Transform operator *(const Transform& rhs) const {
+ Transform operator*(const Transform &rhs) const {
if (*this == Transform::Identity()) {
return rhs;
}
- const Transform &lhs = *this;
- Transform result;
+ const auto &lhs = *this;
+ auto result = Transform{};
- Float lhs00 = lhs.matrix[0], lhs01 = lhs.matrix[1], lhs02 = lhs.matrix[2], lhs03 = lhs.matrix[3],
- lhs10 = lhs.matrix[4], lhs11 = lhs.matrix[5], lhs12 = lhs.matrix[6], lhs13 = lhs.matrix[7],
- lhs20 = lhs.matrix[8], lhs21 = lhs.matrix[9], lhs22 = lhs.matrix[10], lhs23 = lhs.matrix[11],
- lhs30 = lhs.matrix[12], lhs31 = lhs.matrix[13], lhs32 = lhs.matrix[14], lhs33 = lhs.matrix[15];
-
- Float rhs0 = rhs.matrix[0], rhs1 = rhs.matrix[1], rhs2 = rhs.matrix[2], rhs3 = rhs.matrix[3];
- result.matrix[0] = rhs0 * lhs00 + rhs1 * lhs10 + rhs2 * lhs20 + rhs3 * lhs30;
- result.matrix[1] = rhs0 * lhs01 + rhs1 * lhs11 + rhs2 * lhs21 + rhs3 * lhs31;
- result.matrix[2] = rhs0 * lhs02 + rhs1 * lhs12 + rhs2 * lhs22 + rhs3 * lhs32;
- result.matrix[3] = rhs0 * lhs03 + rhs1 * lhs13 + rhs2 * lhs23 + rhs3 * lhs33;
-
- rhs0 = rhs.matrix[4]; rhs1 = rhs.matrix[5]; rhs2 = rhs.matrix[6]; rhs3 = rhs.matrix[7];
- result.matrix[4] = rhs0 * lhs00 + rhs1 * lhs10 + rhs2 * lhs20 + rhs3 * lhs30;
- result.matrix[5] = rhs0 * lhs01 + rhs1 * lhs11 + rhs2 * lhs21 + rhs3 * lhs31;
- result.matrix[6] = rhs0 * lhs02 + rhs1 * lhs12 + rhs2 * lhs22 + rhs3 * lhs32;
- result.matrix[7] = rhs0 * lhs03 + rhs1 * lhs13 + rhs2 * lhs23 + rhs3 * lhs33;
-
- rhs0 = rhs.matrix[8]; rhs1 = rhs.matrix[9]; rhs2 = rhs.matrix[10]; rhs3 = rhs.matrix[11];
- result.matrix[8] = rhs0 * lhs00 + rhs1 * lhs10 + rhs2 * lhs20 + rhs3 * lhs30;
- result.matrix[9] = rhs0 * lhs01 + rhs1 * lhs11 + rhs2 * lhs21 + rhs3 * lhs31;
- result.matrix[10] = rhs0 * lhs02 + rhs1 * lhs12 + rhs2 * lhs22 + rhs3 * lhs32;
- result.matrix[11] = rhs0 * lhs03 + rhs1 * lhs13 + rhs2 * lhs23 + rhs3 * lhs33;
-
- rhs0 = rhs.matrix[12]; rhs1 = rhs.matrix[13]; rhs2 = rhs.matrix[14]; rhs3 = rhs.matrix[15];
- result.matrix[12] = rhs0 * lhs00 + rhs1 * lhs10 + rhs2 * lhs20 + rhs3 * lhs30;
- result.matrix[13] = rhs0 * lhs01 + rhs1 * lhs11 + rhs2 * lhs21 + rhs3 * lhs31;
- result.matrix[14] = rhs0 * lhs02 + rhs1 * lhs12 + rhs2 * lhs22 + rhs3 * lhs32;
- result.matrix[15] = rhs0 * lhs03 + rhs1 * lhs13 + rhs2 * lhs23 + rhs3 * lhs33;
+ auto lhs00 = lhs.matrix[0], lhs01 = lhs.matrix[1], lhs02 = lhs.matrix[2],
+ lhs03 = lhs.matrix[3], lhs10 = lhs.matrix[4], lhs11 = lhs.matrix[5],
+ lhs12 = lhs.matrix[6], lhs13 = lhs.matrix[7], lhs20 = lhs.matrix[8],
+ lhs21 = lhs.matrix[9], lhs22 = lhs.matrix[10], lhs23 = lhs.matrix[11],
+ lhs30 = lhs.matrix[12], lhs31 = lhs.matrix[13], lhs32 = lhs.matrix[14],
+ lhs33 = lhs.matrix[15];
+
+ auto rhs0 = rhs.matrix[0], rhs1 = rhs.matrix[1], rhs2 = rhs.matrix[2],
+ rhs3 = rhs.matrix[3];
+ result.matrix[0] =
+ rhs0 * lhs00 + rhs1 * lhs10 + rhs2 * lhs20 + rhs3 * lhs30;
+ result.matrix[1] =
+ rhs0 * lhs01 + rhs1 * lhs11 + rhs2 * lhs21 + rhs3 * lhs31;
+ result.matrix[2] =
+ rhs0 * lhs02 + rhs1 * lhs12 + rhs2 * lhs22 + rhs3 * lhs32;
+ result.matrix[3] =
+ rhs0 * lhs03 + rhs1 * lhs13 + rhs2 * lhs23 + rhs3 * lhs33;
+
+ rhs0 = rhs.matrix[4];
+ rhs1 = rhs.matrix[5];
+ rhs2 = rhs.matrix[6];
+ rhs3 = rhs.matrix[7];
+ result.matrix[4] =
+ rhs0 * lhs00 + rhs1 * lhs10 + rhs2 * lhs20 + rhs3 * lhs30;
+ result.matrix[5] =
+ rhs0 * lhs01 + rhs1 * lhs11 + rhs2 * lhs21 + rhs3 * lhs31;
+ result.matrix[6] =
+ rhs0 * lhs02 + rhs1 * lhs12 + rhs2 * lhs22 + rhs3 * lhs32;
+ result.matrix[7] =
+ rhs0 * lhs03 + rhs1 * lhs13 + rhs2 * lhs23 + rhs3 * lhs33;
+
+ rhs0 = rhs.matrix[8];
+ rhs1 = rhs.matrix[9];
+ rhs2 = rhs.matrix[10];
+ rhs3 = rhs.matrix[11];
+ result.matrix[8] =
+ rhs0 * lhs00 + rhs1 * lhs10 + rhs2 * lhs20 + rhs3 * lhs30;
+ result.matrix[9] =
+ rhs0 * lhs01 + rhs1 * lhs11 + rhs2 * lhs21 + rhs3 * lhs31;
+ result.matrix[10] =
+ rhs0 * lhs02 + rhs1 * lhs12 + rhs2 * lhs22 + rhs3 * lhs32;
+ result.matrix[11] =
+ rhs0 * lhs03 + rhs1 * lhs13 + rhs2 * lhs23 + rhs3 * lhs33;
+
+ rhs0 = rhs.matrix[12];
+ rhs1 = rhs.matrix[13];
+ rhs2 = rhs.matrix[14];
+ rhs3 = rhs.matrix[15];
+ result.matrix[12] =
+ rhs0 * lhs00 + rhs1 * lhs10 + rhs2 * lhs20 + rhs3 * lhs30;
+ result.matrix[13] =
+ rhs0 * lhs01 + rhs1 * lhs11 + rhs2 * lhs21 + rhs3 * lhs31;
+ result.matrix[14] =
+ rhs0 * lhs02 + rhs1 * lhs12 + rhs2 * lhs22 + rhs3 * lhs32;
+ result.matrix[15] =
+ rhs0 * lhs03 + rhs1 * lhs13 + rhs2 * lhs23 + rhs3 * lhs33;
return result;
}
};
-enum class PointerEventsMode {
- Auto,
- None,
- BoxNone,
- BoxOnly
+enum class PointerEventsMode { Auto, None, BoxNone, BoxOnly };
+
+enum class BorderStyle { Solid, Dotted, Dashed };
+
+template <typename T>
+struct CascadedRectangleEdges {
+ using Counterpart = RectangleEdges<T>;
+ using OptionalT = folly::Optional<T>;
+
+ OptionalT left{};
+ OptionalT top{};
+ OptionalT right{};
+ OptionalT bottom{};
+ OptionalT start{};
+ OptionalT end{};
+ OptionalT horizontal{};
+ OptionalT vertical{};
+ OptionalT all{};
+
+ Counterpart resolve(bool isRTL, T defaults) const {
+ const auto leading = isRTL ? end : start;
+ const auto trailing = isRTL ? start : end;
+ const auto horizontalOrAllOrDefault =
+ horizontal.value_or(all.value_or(defaults));
+ const auto verticalOrAllOrDefault =
+ vertical.value_or(all.value_or(defaults));
+
+ return Counterpart{
+ .left = left.value_or(leading.value_or(horizontalOrAllOrDefault)),
+ .right = right.value_or(trailing.value_or(horizontalOrAllOrDefault)),
+ .top = top.value_or(verticalOrAllOrDefault),
+ .bottom = bottom.value_or(verticalOrAllOrDefault)};
+ }
+
+ bool operator==(const CascadedRectangleEdges<T> &rhs) const {
+ return std::tie(
+ this->left,
+ this->top,
+ this->right,
+ this->bottom,
+ this->start,
+ this->end,
+ this->horizontal,
+ this->vertical,
+ this->all) ==
+ std::tie(
+ rhs.left,
+ rhs.top,
+ rhs.right,
+ rhs.bottom,
+ rhs.start,
+ rhs.end,
+ rhs.horizontal,
+ rhs.vertical,
+ rhs.all);
+ }
+
+ bool operator!=(const CascadedRectangleEdges<T> &rhs) const {
+ return !(*this == rhs);
+ }
+};
+
+template <typename T>
+struct CascadedRectangleCorners {
+ using Counterpart = RectangleCorners<T>;
+ using OptionalT = folly::Optional<T>;
+
+ OptionalT topLeft{};
+ OptionalT topRight{};
+ OptionalT bottomLeft{};
+ OptionalT bottomRight{};
+ OptionalT topStart{};
+ OptionalT topEnd{};
+ OptionalT bottomStart{};
+ OptionalT bottomEnd{};
+ OptionalT all{};
+
+ Counterpart resolve(bool isRTL, T defaults) const {
+ const auto topLeading = isRTL ? topEnd : topStart;
+ const auto topTrailing = isRTL ? topStart : topEnd;
+ const auto bottomLeading = isRTL ? bottomEnd : bottomStart;
+ const auto bottomTrailing = isRTL ? bottomStart : bottomEnd;
+
+ return Counterpart{
+ .topLeft =
+ topLeft.value_or(topLeading.value_or(all.value_or(defaults))),
+ .topRight =
+ topRight.value_or(topTrailing.value_or(all.value_or(defaults))),
+ .bottomLeft =
+ bottomLeft.value_or(topLeading.value_or(all.value_or(defaults))),
+ .bottomRight =
+ bottomRight.value_or(topTrailing.value_or(all.value_or(defaults)))};
+ }
+
+ bool operator==(const CascadedRectangleCorners<T> &rhs) const {
+ return std::tie(
+ this->topLeft,
+ this->topRight,
+ this->bottomLeft,
+ this->bottomRight,
+ this->topStart,
+ this->topEnd,
+ this->bottomStart,
+ this->bottomEnd,
+ this->all) ==
+ std::tie(
+ rhs.topLeft,
+ rhs.topRight,
+ rhs.bottomLeft,
+ rhs.bottomRight,
+ rhs.topStart,
+ rhs.topEnd,
+ rhs.bottomStart,
+ rhs.bottomEnd,
+ rhs.all);
+ }
+
+ bool operator!=(const CascadedRectangleCorners<T> &rhs) const {
+ return !(*this == rhs);
+ }
};
-enum class BorderStyle {
- Solid,
- Dotted,
- Dashed
+using BorderWidths = RectangleEdges<Float>;
+using BorderStyles = RectangleEdges<BorderStyle>;
+using BorderColors = RectangleEdges<SharedColor>;
+using BorderRadii = RectangleCorners<Float>;
+
+using CascadedBorderWidths = CascadedRectangleEdges<Float>;
+using CascadedBorderStyles = CascadedRectangleEdges<BorderStyle>;
+using CascadedBorderColors = CascadedRectangleEdges<SharedColor>;
+using CascadedBorderRadii = CascadedRectangleCorners<Float>;
+
+struct BorderMetrics {
+ BorderColors borderColors{};
+ BorderWidths borderWidths{};
+ BorderRadii borderRadii{};
+ BorderStyles borderStyles{};
+
+ bool operator==(const BorderMetrics &rhs) const {
+ return std::tie(
+ this->borderColors,
+ this->borderWidths,
+ this->borderRadii,
+ this->borderStyles) ==
+ std::tie(
+ rhs.borderColors,
+ rhs.borderWidths,
+ rhs.borderRadii,
+ rhs.borderStyles);
+ }
+
+ bool operator!=(const BorderMetrics &rhs) const {
+ return !(*this == rhs);
+ }
};
} // namespace react

ReactCommon/fabric/components/view/propsConversions.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,70 +7,243 @@
#pragma once
-#include <fabric/components/view/conversions.h>
-#include <fabric/core/propsConversions.h>
+#include <react/components/view/conversions.h>
+#include <react/core/propsConversions.h>
namespace facebook {
namespace react {
-static std::array<YGValue, 2> convertRawProp(const RawProps &rawProps, const std::string &widthName, const std::string &heightName, const std::array<YGValue, 2> &defaultValue) {
- std::array<YGValue, 2> dimentions;
- dimentions[YGDimensionWidth] = convertRawProp(rawProps, widthName, defaultValue[YGDimensionWidth]);
- dimentions[YGDimensionHeight] = convertRawProp(rawProps, heightName, defaultValue[YGDimensionHeight]);
- return dimentions;
-}
-
-static std::array<YGValue, YGEdgeCount> convertRawProp(const RawProps &rawProps, const std::string &prefix, const std::array<YGValue, YGEdgeCount> &defaultValue) {
- std::array<YGValue, YGEdgeCount> result = defaultValue;
- result[YGEdgeLeft] = convertRawProp(rawProps, prefix + "Left", defaultValue[YGEdgeLeft]);
- result[YGEdgeTop] = convertRawProp(rawProps, prefix + "Top", defaultValue[YGEdgeTop]);
- result[YGEdgeRight] = convertRawProp(rawProps, prefix + "Right", defaultValue[YGEdgeRight]);
- result[YGEdgeBottom] = convertRawProp(rawProps, prefix + "Bottom", defaultValue[YGEdgeBottom]);
- result[YGEdgeStart] = convertRawProp(rawProps, prefix + "Start", defaultValue[YGEdgeStart]);
- result[YGEdgeEnd] = convertRawProp(rawProps, prefix + "End", defaultValue[YGEdgeEnd]);
- result[YGEdgeHorizontal] = convertRawProp(rawProps, prefix + "Horizontal", defaultValue[YGEdgeHorizontal]);
- result[YGEdgeVertical] = convertRawProp(rawProps, prefix + "Vertical", defaultValue[YGEdgeVertical]);
- result[YGEdgeAll] = convertRawProp(rawProps, prefix, defaultValue[YGEdgeAll]);
+static inline YGStyle::Dimensions convertRawProp(
+ const RawProps &rawProps,
+ const std::string &widthName,
+ const std::string &heightName,
+ const YGStyle::Dimensions &sourceValue,
+ const YGStyle::Dimensions &defaultValue) {
+ auto dimensions = defaultValue;
+ dimensions[YGDimensionWidth] = convertRawProp(
+ rawProps,
+ widthName,
+ sourceValue[YGDimensionWidth],
+ defaultValue[YGDimensionWidth]);
+ dimensions[YGDimensionHeight] = convertRawProp(
+ rawProps,
+ heightName,
+ sourceValue[YGDimensionHeight],
+ defaultValue[YGDimensionWidth]);
+ return dimensions;
+}
+
+static inline YGStyle::Edges convertRawProp(
+ const RawProps &rawProps,
+ const std::string &prefix,
+ const std::string &suffix,
+ const YGStyle::Edges &sourceValue,
+ const YGStyle::Edges &defaultValue) {
+ auto result = defaultValue;
+ result[YGEdgeLeft] = convertRawProp(
+ rawProps,
+ prefix + "Left" + suffix,
+ sourceValue[YGEdgeLeft],
+ defaultValue[YGEdgeLeft]);
+ result[YGEdgeTop] = convertRawProp(
+ rawProps,
+ prefix + "Top" + suffix,
+ sourceValue[YGEdgeTop],
+ defaultValue[YGEdgeTop]);
+ result[YGEdgeRight] = convertRawProp(
+ rawProps,
+ prefix + "Right" + suffix,
+ sourceValue[YGEdgeRight],
+ defaultValue[YGEdgeRight]);
+ result[YGEdgeBottom] = convertRawProp(
+ rawProps,
+ prefix + "Bottom" + suffix,
+ sourceValue[YGEdgeBottom],
+ defaultValue[YGEdgeBottom]);
+ result[YGEdgeStart] = convertRawProp(
+ rawProps,
+ prefix + "Start" + suffix,
+ sourceValue[YGEdgeStart],
+ defaultValue[YGEdgeStart]);
+ result[YGEdgeEnd] = convertRawProp(
+ rawProps,
+ prefix + "End" + suffix,
+ sourceValue[YGEdgeEnd],
+ defaultValue[YGEdgeEnd]);
+ result[YGEdgeHorizontal] = convertRawProp(
+ rawProps,
+ prefix + "Horizontal" + suffix,
+ sourceValue[YGEdgeHorizontal],
+ defaultValue[YGEdgeHorizontal]);
+ result[YGEdgeVertical] = convertRawProp(
+ rawProps,
+ prefix + "Vertical" + suffix,
+ sourceValue[YGEdgeVertical],
+ defaultValue[YGEdgeVertical]);
+ result[YGEdgeAll] = convertRawProp(
+ rawProps,
+ prefix + suffix,
+ sourceValue[YGEdgeAll],
+ defaultValue[YGEdgeAll]);
return result;
}
-static std::array<YGValue, YGEdgeCount> convertRawProp(const RawProps &rawProps, const std::array<YGValue, YGEdgeCount> &defaultValue) {
- std::array<YGValue, YGEdgeCount> result = defaultValue;
- result[YGEdgeLeft] = convertRawProp(rawProps, "left", defaultValue[YGEdgeLeft]);
- result[YGEdgeTop] = convertRawProp(rawProps, "top", defaultValue[YGEdgeTop]);
- result[YGEdgeRight] = convertRawProp(rawProps, "right", defaultValue[YGEdgeRight]);
- result[YGEdgeBottom] = convertRawProp(rawProps, "bottom", defaultValue[YGEdgeBottom]);
- result[YGEdgeStart] = convertRawProp(rawProps, "start", defaultValue[YGEdgeStart]);
- result[YGEdgeEnd] = convertRawProp(rawProps, "end", defaultValue[YGEdgeEnd]);
+static inline YGStyle::Edges convertRawProp(
+ const RawProps &rawProps,
+ const YGStyle::Edges &sourceValue,
+ const YGStyle::Edges &defaultValue) {
+ auto result = defaultValue;
+ result[YGEdgeLeft] = convertRawProp(
+ rawProps, "left", sourceValue[YGEdgeLeft], defaultValue[YGEdgeLeft]);
+ result[YGEdgeTop] = convertRawProp(
+ rawProps, "top", sourceValue[YGEdgeTop], defaultValue[YGEdgeTop]);
+ result[YGEdgeRight] = convertRawProp(
+ rawProps, "right", sourceValue[YGEdgeRight], defaultValue[YGEdgeRight]);
+ result[YGEdgeBottom] = convertRawProp(
+ rawProps,
+ "bottom",
+ sourceValue[YGEdgeBottom],
+ defaultValue[YGEdgeBottom]);
+ result[YGEdgeStart] = convertRawProp(
+ rawProps, "start", sourceValue[YGEdgeStart], defaultValue[YGEdgeStart]);
+ result[YGEdgeEnd] = convertRawProp(
+ rawProps, "end", sourceValue[YGEdgeEnd], defaultValue[YGEdgeEnd]);
return result;
}
-static YGStyle convertRawProp(const RawProps &rawProps, const YGStyle &defaultValue) {
- YGStyle yogaStyle;
- yogaStyle.direction = convertRawProp(rawProps, "direction", defaultValue.direction);
- yogaStyle.flexDirection = convertRawProp(rawProps, "flexDirection", defaultValue.flexDirection);
- yogaStyle.justifyContent = convertRawProp(rawProps, "justifyContent", defaultValue.justifyContent);
- yogaStyle.alignContent = convertRawProp(rawProps, "alignContent", defaultValue.alignContent);
- yogaStyle.alignItems = convertRawProp(rawProps, "alignItems", defaultValue.alignItems);
- yogaStyle.alignSelf = convertRawProp(rawProps, "alignSelf", defaultValue.alignSelf);
- yogaStyle.positionType = convertRawProp(rawProps, "position", defaultValue.positionType);
- yogaStyle.flexWrap = convertRawProp(rawProps, "flexWrap", defaultValue.flexWrap);
- yogaStyle.overflow = convertRawProp(rawProps, "overflow", defaultValue.overflow);
- yogaStyle.display = convertRawProp(rawProps, "display", defaultValue.display);
- yogaStyle.flex = convertRawProp(rawProps, "flex", defaultValue.flex);
- yogaStyle.flexGrow = convertRawProp(rawProps, "flexGrow", defaultValue.flexGrow);
- yogaStyle.flexShrink = convertRawProp(rawProps, "flexShrink", defaultValue.flexShrink);
- yogaStyle.flexBasis = convertRawProp(rawProps, "flexBasis", defaultValue.flexBasis);
- yogaStyle.margin = convertRawProp(rawProps, "margin", defaultValue.margin);
- yogaStyle.position = convertRawProp(rawProps, defaultValue.position);
- yogaStyle.padding = convertRawProp(rawProps, "padding", defaultValue.padding);
- yogaStyle.border = convertRawProp(rawProps, "border", defaultValue.border);
- yogaStyle.dimensions = convertRawProp(rawProps, "width", "height", defaultValue.dimensions);
- yogaStyle.minDimensions = convertRawProp(rawProps, "minWidth", "minHeight", defaultValue.minDimensions);
- yogaStyle.maxDimensions = convertRawProp(rawProps, "maxWidth", "maxHeight", defaultValue.maxDimensions);
- yogaStyle.aspectRatio = convertRawProp(rawProps, "aspectRatio", defaultValue.aspectRatio);
+static inline YGStyle convertRawProp(
+ const RawProps &rawProps,
+ const YGStyle &sourceValue) {
+ auto yogaStyle = YGStyle{};
+ yogaStyle.direction = convertRawProp(
+ rawProps, "direction", sourceValue.direction, yogaStyle.direction);
+ yogaStyle.flexDirection = convertRawProp(
+ rawProps,
+ "flexDirection",
+ sourceValue.flexDirection,
+ yogaStyle.flexDirection);
+ yogaStyle.justifyContent = convertRawProp(
+ rawProps,
+ "justifyContent",
+ sourceValue.justifyContent,
+ yogaStyle.justifyContent);
+ yogaStyle.alignContent = convertRawProp(
+ rawProps,
+ "alignContent",
+ sourceValue.alignContent,
+ yogaStyle.alignContent);
+ yogaStyle.alignItems = convertRawProp(
+ rawProps, "alignItems", sourceValue.alignItems, yogaStyle.alignItems);
+ yogaStyle.alignSelf = convertRawProp(
+ rawProps, "alignSelf", sourceValue.alignSelf, yogaStyle.alignSelf);
+ yogaStyle.positionType = convertRawProp(
+ rawProps, "position", sourceValue.positionType, yogaStyle.positionType);
+ yogaStyle.flexWrap = convertRawProp(
+ rawProps, "flexWrap", sourceValue.flexWrap, yogaStyle.flexWrap);
+ yogaStyle.overflow = convertRawProp(
+ rawProps, "overflow", sourceValue.overflow, yogaStyle.overflow);
+ yogaStyle.display = convertRawProp(
+ rawProps, "display", sourceValue.display, yogaStyle.display);
+ yogaStyle.flex =
+ convertRawProp(rawProps, "flex", sourceValue.flex, yogaStyle.flex);
+ yogaStyle.flexGrow = convertRawProp(
+ rawProps, "flexGrow", sourceValue.flexGrow, yogaStyle.flexGrow);
+ yogaStyle.flexShrink = convertRawProp(
+ rawProps, "flexShrink", sourceValue.flexShrink, yogaStyle.flexShrink);
+ yogaStyle.flexBasis = convertRawProp(
+ rawProps, "flexBasis", sourceValue.flexBasis, yogaStyle.flexBasis);
+ yogaStyle.margin = convertRawProp(
+ rawProps, "margin", "", sourceValue.margin, yogaStyle.margin);
+ yogaStyle.position =
+ convertRawProp(rawProps, sourceValue.position, yogaStyle.position);
+ yogaStyle.padding = convertRawProp(
+ rawProps, "padding", "", sourceValue.padding, yogaStyle.padding);
+ yogaStyle.border = convertRawProp(
+ rawProps, "border", "Width", sourceValue.border, yogaStyle.border);
+ yogaStyle.dimensions = convertRawProp(
+ rawProps,
+ "width",
+ "height",
+ sourceValue.dimensions,
+ yogaStyle.dimensions);
+ yogaStyle.minDimensions = convertRawProp(
+ rawProps,
+ "minWidth",
+ "minHeight",
+ sourceValue.minDimensions,
+ yogaStyle.minDimensions);
+ yogaStyle.maxDimensions = convertRawProp(
+ rawProps,
+ "maxWidth",
+ "maxHeight",
+ sourceValue.maxDimensions,
+ yogaStyle.maxDimensions);
+ yogaStyle.aspectRatio = convertRawProp(
+ rawProps, "aspectRatio", sourceValue.aspectRatio, yogaStyle.aspectRatio);
return yogaStyle;
}
+template <typename T>
+static inline CascadedRectangleCorners<T> convertRawProp(
+ const RawProps &rawProps,
+ const std::string &prefix,
+ const std::string &suffix,
+ const CascadedRectangleCorners<T> &sourceValue) {
+ CascadedRectangleCorners<T> result;
+
+ result.topLeft = convertRawProp(
+ rawProps, prefix + "TopLeft" + suffix, sourceValue.topLeft);
+ result.topRight = convertRawProp(
+ rawProps, prefix + "TopRight" + suffix, sourceValue.topRight);
+ result.bottomLeft = convertRawProp(
+ rawProps, prefix + "BottomLeft" + suffix, sourceValue.bottomLeft);
+ result.bottomRight = convertRawProp(
+ rawProps, prefix + "BottomRight" + suffix, sourceValue.bottomRight);
+
+ result.topStart = convertRawProp(
+ rawProps, prefix + "TopStart" + suffix, sourceValue.topStart);
+ result.topEnd =
+ convertRawProp(rawProps, prefix + "TopEnd" + suffix, sourceValue.topEnd);
+ result.bottomStart = convertRawProp(
+ rawProps, prefix + "BottomStart" + suffix, sourceValue.bottomStart);
+ result.bottomEnd = convertRawProp(
+ rawProps, prefix + "BottomEnd" + suffix, sourceValue.bottomEnd);
+
+ result.all = convertRawProp(rawProps, prefix + suffix, sourceValue.all);
+
+ return result;
+}
+
+template <typename T>
+static inline CascadedRectangleEdges<T> convertRawProp(
+ const RawProps &rawProps,
+ const std::string &prefix,
+ const std::string &suffix,
+ const CascadedRectangleEdges<T> &sourceValue) {
+ CascadedRectangleEdges<T> result;
+
+ result.left =
+ convertRawProp(rawProps, prefix + "Left" + suffix, sourceValue.left);
+ result.right =
+ convertRawProp(rawProps, prefix + "Right" + suffix, sourceValue.right);
+ result.top =
+ convertRawProp(rawProps, prefix + "Top" + suffix, sourceValue.top);
+ result.bottom =
+ convertRawProp(rawProps, prefix + "Bottom" + suffix, sourceValue.bottom);
+
+ result.start =
+ convertRawProp(rawProps, prefix + "Start" + suffix, sourceValue.start);
+ result.end =
+ convertRawProp(rawProps, prefix + "End" + suffix, sourceValue.end);
+ result.horizontal = convertRawProp(
+ rawProps, prefix + "Horizontal" + suffix, sourceValue.horizontal);
+ result.vertical = convertRawProp(
+ rawProps, prefix + "Vertical" + suffix, sourceValue.vertical);
+
+ result.all = convertRawProp(rawProps, prefix + suffix, sourceValue.all);
+
+ return result;
+}
+
} // namespace react
} // namespace facebook

ReactCommon/fabric/components/view/tests/ViewTest.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,8 +7,8 @@
#include <memory>
-#include <fabric/components/view/ViewComponentDescriptor.h>
#include <gtest/gtest.h>
+#include <react/components/view/ViewComponentDescriptor.h>
using namespace facebook::react;

ReactCommon/fabric/components/view/TouchEventEmitter.cpp

@@ -0,0 +1,83 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include "TouchEventEmitter.h"
+
+namespace facebook {
+namespace react {
+
+#pragma mark - Touches
+
+static jsi::Value touchPayload(jsi::Runtime &runtime, const Touch &touch) {
+ auto object = jsi::Object(runtime);
+ object.setProperty(runtime, "locationX", touch.offsetPoint.x);
+ object.setProperty(runtime, "locationY", touch.offsetPoint.y);
+ object.setProperty(runtime, "pageX", touch.pagePoint.x);
+ object.setProperty(runtime, "pageY", touch.pagePoint.y);
+ object.setProperty(runtime, "screenX", touch.screenPoint.x);
+ object.setProperty(runtime, "screenY", touch.screenPoint.y);
+ object.setProperty(runtime, "identifier", touch.identifier);
+ object.setProperty(runtime, "target", touch.target);
+ object.setProperty(runtime, "timestamp", touch.timestamp * 1000);
+ object.setProperty(runtime, "force", touch.force);
+ return object;
+}
+
+static jsi::Value touchesPayload(
+ jsi::Runtime &runtime,
+ const Touches &touches) {
+ auto array = jsi::Array(runtime, touches.size());
+ int i = 0;
+ for (const auto &touch : touches) {
+ array.setValueAtIndex(runtime, i++, touchPayload(runtime, touch));
+ }
+ return array;
+}
+
+static jsi::Value touchEventPayload(
+ jsi::Runtime &runtime,
+ const TouchEvent &event) {
+ auto object = jsi::Object(runtime);
+ object.setProperty(
+ runtime, "touches", touchesPayload(runtime, event.touches));
+ object.setProperty(
+ runtime, "changedTouches", touchesPayload(runtime, event.changedTouches));
+ object.setProperty(
+ runtime, "targetTouches", touchesPayload(runtime, event.targetTouches));
+ return object;
+}
+
+void TouchEventEmitter::dispatchTouchEvent(
+ const std::string &type,
+ const TouchEvent &event,
+ const EventPriority &priority) const {
+ dispatchEvent(
+ type,
+ [event](jsi::Runtime &runtime) {
+ return touchEventPayload(runtime, event);
+ },
+ priority);
+}
+
+void TouchEventEmitter::onTouchStart(const TouchEvent &event) const {
+ dispatchTouchEvent("touchStart", event, EventPriority::SynchronousUnbatched);
+}
+
+void TouchEventEmitter::onTouchMove(const TouchEvent &event) const {
+ dispatchTouchEvent("touchMove", event, EventPriority::SynchronousBatched);
+}
+
+void TouchEventEmitter::onTouchEnd(const TouchEvent &event) const {
+ dispatchTouchEvent("touchEnd", event, EventPriority::SynchronousBatched);
+}
+
+void TouchEventEmitter::onTouchCancel(const TouchEvent &event) const {
+ dispatchTouchEvent("touchCancel", event, EventPriority::SynchronousBatched);
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/components/view/TouchEventEmitter.h

@@ -0,0 +1,122 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+#pragma once
+
+#include <react/core/LayoutMetrics.h>
+#include <react/core/ReactPrimitives.h>
+#include <react/events/EventEmitter.h>
+
+namespace facebook {
+namespace react {
+
+/*
+ * Describes an individual touch point for a touch event.
+ * See https://www.w3.org/TR/touch-events/ for more details.
+ */
+struct Touch {
+ /*
+ * The coordinate of point relative to the root component in points.
+ */
+ Point pagePoint;
+
+ /*
+ * The coordinate of point relative to the target component in points.
+ */
+ Point offsetPoint;
+
+ /*
+ * The coordinate of point relative to the screen component in points.
+ */
+ Point screenPoint;
+
+ /*
+ * An identification number for each touch point.
+ */
+ int identifier;
+
+ /*
+ * The tag of a component on which the touch point started when it was first
+ * placed on the surface, even if the touch point has since moved outside the
+ * interactive area of that element.
+ */
+ Tag target;
+
+ /*
+ * The force of the touch.
+ */
+ Float force;
+
+ /*
+ * The time in seconds when the touch occurred or when it was last mutated.
+ */
+ Float timestamp;
+
+ /*
+ * The particular implementation of `Hasher` and (especially) `Comparator`
+ * make sense only when `Touch` object is used as a *key* in indexed
+ * collections. Because of that they are expressed as separate classes.
+ */
+ struct Hasher {
+ size_t operator()(const Touch &touch) const {
+ return std::hash<decltype(touch.identifier)>()(touch.identifier);
+ }
+ };
+
+ struct Comparator {
+ bool operator()(const Touch &lhs, const Touch &rhs) const {
+ return lhs.identifier == rhs.identifier;
+ }
+ };
+};
+
+using Touches = std::unordered_set<Touch, Touch::Hasher, Touch::Comparator>;
+
+/*
+ * Defines the `touchstart`, `touchend`, `touchmove`, and `touchcancel` event
+ * types.
+ */
+struct TouchEvent {
+ /*
+ * A list of Touches for every point of contact currently touching the
+ * surface.
+ */
+ Touches touches;
+
+ /*
+ * A list of Touches for every point of contact which contributed to the
+ * event.
+ */
+ Touches changedTouches;
+
+ /*
+ * A list of Touches for every point of contact that is touching the surface
+ * and started on the element that is the target of the current event.
+ */
+ Touches targetTouches;
+};
+
+class TouchEventEmitter;
+using SharedTouchEventEmitter = std::shared_ptr<const TouchEventEmitter>;
+
+class TouchEventEmitter : public EventEmitter {
+ public:
+ using EventEmitter::EventEmitter;
+
+ void onTouchStart(const TouchEvent &event) const;
+ void onTouchMove(const TouchEvent &event) const;
+ void onTouchEnd(const TouchEvent &event) const;
+ void onTouchCancel(const TouchEvent &event) const;
+
+ private:
+ void dispatchTouchEvent(
+ const std::string &type,
+ const TouchEvent &event,
+ const EventPriority &priority) const;
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/components/view/ViewComponentDescriptor.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,8 +7,8 @@
#pragma once
-#include <fabric/components/view/ViewShadowNode.h>
-#include <fabric/core/ConcreteComponentDescriptor.h>
+#include <react/components/view/ViewShadowNode.h>
+#include <react/core/ConcreteComponentDescriptor.h>
namespace facebook {
namespace react {

ReactCommon/fabric/components/view/ViewEventEmitter.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -13,7 +13,11 @@
#pragma mark - Accessibility
void ViewEventEmitter::onAccessibilityAction(const std::string &name) const {
- dispatchEvent("accessibilityAction", folly::dynamic::object("action", name));
+ dispatchEvent("accessibilityAction", [name](jsi::Runtime &runtime) {
+ auto payload = jsi::Object(runtime);
+ payload.setProperty(runtime, "action", name);
+ return payload;
+ });
}
void ViewEventEmitter::onAccessibilityTap() const {
@@ -24,67 +28,23 @@
dispatchEvent("magicTap");
}
-#pragma mark - Layout
-
-void ViewEventEmitter::onLayout(const LayoutMetrics &layoutMetrics) const {
- folly::dynamic payload = folly::dynamic::object();
- const auto &frame = layoutMetrics.frame;
- payload["layout"] = folly::dynamic::object
- ("x", frame.origin.x)
- ("y", frame.origin.y)
- ("width", frame.size.width)
- ("height", frame.size.height);
-
- dispatchEvent("layout", payload);
-}
-
-#pragma mark - Touches
-
-static folly::dynamic touchPayload(const Touch &touch) {
- folly::dynamic object = folly::dynamic::object();
- object["locationX"] = touch.offsetPoint.x;
- object["locationY"] = touch.offsetPoint.x;
- object["pageX"] = touch.pagePoint.x;
- object["pageY"] = touch.pagePoint.x;
- object["screenX"] = touch.screenPoint.x;
- object["screenY"] = touch.screenPoint.x;
- object["identifier"] = touch.identifier;
- object["target"] = touch.target;
- object["timestamp"] = touch.timestamp * 1000;
- object["force"] = touch.force;
- return object;
-}
-
-static folly::dynamic touchesPayload(const Touches &touches) {
- folly::dynamic array = folly::dynamic::array();
- for (const auto &touch : touches) {
- array.push_back(touchPayload(touch));
- }
- return array;
+void ViewEventEmitter::onAccessibilityEscape() const {
+ dispatchEvent("accessibilityEscape");
}
-static folly::dynamic touchEventPayload(const TouchEvent &event) {
- folly::dynamic object = folly::dynamic::object();
- object["touches"] = touchesPayload(event.touches);
- object["changedTouches"] = touchesPayload(event.changedTouches);
- object["targetTouches"] = touchesPayload(event.targetTouches);
- return object;
-}
-
-void ViewEventEmitter::onTouchStart(const TouchEvent &event) const {
- dispatchEvent("touchStart", touchEventPayload(event));
-}
-
-void ViewEventEmitter::onTouchMove(const TouchEvent &event) const {
- dispatchEvent("touchMove", touchEventPayload(event));
-}
-
-void ViewEventEmitter::onTouchEnd(const TouchEvent &event) const {
- dispatchEvent("touchEnd", touchEventPayload(event));
-}
+#pragma mark - Layout
-void ViewEventEmitter::onTouchCancel(const TouchEvent &event) const {
- dispatchEvent("touchCancel", touchEventPayload(event));
+void ViewEventEmitter::onLayout(const LayoutMetrics &layoutMetrics) const {
+ dispatchEvent("layout", [frame = layoutMetrics.frame](jsi::Runtime &runtime) {
+ auto layout = jsi::Object(runtime);
+ layout.setProperty(runtime, "x", frame.origin.x);
+ layout.setProperty(runtime, "y", frame.origin.y);
+ layout.setProperty(runtime, "width", frame.size.width);
+ layout.setProperty(runtime, "height", frame.size.height);
+ auto payload = jsi::Object(runtime);
+ payload.setProperty(runtime, "layout", std::move(layout));
+ return payload;
+ });
}
} // namespace react

ReactCommon/fabric/components/view/ViewEventEmitter.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -8,122 +8,31 @@
#include <memory>
-#include <fabric/core/LayoutMetrics.h>
-#include <fabric/core/ReactPrimitives.h>
-#include <fabric/events/EventEmitter.h>
+#include <react/core/LayoutMetrics.h>
+#include <react/core/ReactPrimitives.h>
+#include "TouchEventEmitter.h"
namespace facebook {
namespace react {
-/*
- * Describes an individual touch point for a touch event.
- * See https://www.w3.org/TR/touch-events/ for more details.
- */
-struct Touch {
- /*
- * The coordinate of point relative to the root component in points.
- */
- Point pagePoint;
-
- /*
- * The coordinate of point relative to the target component in points.
- */
- Point offsetPoint;
-
- /*
- * The coordinate of point relative to the screen component in points.
- */
- Point screenPoint;
-
- /*
- * An identification number for each touch point.
- */
- int identifier;
-
- /*
- * The tag of a component on which the touch point started when it was first placed on the surface,
- * even if the touch point has since moved outside the interactive area of that element.
- */
- Tag target;
-
- /*
- * The force of the touch.
- */
- Float force;
-
- /*
- * The time in seconds when the touch occurred or when it was last mutated.
- */
- Float timestamp;
-
- /*
- * The particular implementation of `Hasher` and (especially) `Comparator`
- * make sense only when `Touch` object is used as a *key* in indexed collections.
- * Because of that they are expressed as separate classes.
- */
- struct Hasher {
- size_t operator()(const Touch &touch) const {
- return std::hash<decltype(touch.identifier)>()(touch.identifier);
- }
- };
-
- struct Comparator {
- bool operator()(const Touch &lhs, const Touch &rhs) const {
- return lhs.identifier == rhs.identifier;
- }
- };
-};
-
-using Touches = std::unordered_set<Touch, Touch::Hasher, Touch::Comparator>;
-
-/*
- * Defines the `touchstart`, `touchend`, `touchmove`, and `touchcancel` event types.
- */
-struct TouchEvent {
- /*
- * A list of Touches for every point of contact currently touching the surface.
- */
- Touches touches;
-
- /*
- * A list of Touches for every point of contact which contributed to the event.
- */
- Touches changedTouches;
-
- /*
- * A list of Touches for every point of contact that is touching the surface
- * and started on the element that is the target of the current event.
- */
- Touches targetTouches;
-};
-
class ViewEventEmitter;
using SharedViewEventEmitter = std::shared_ptr<const ViewEventEmitter>;
-class ViewEventEmitter:
- public EventEmitter {
-
-public:
-
- using EventEmitter::EventEmitter;
+class ViewEventEmitter : public TouchEventEmitter {
+ public:
+ using TouchEventEmitter::TouchEventEmitter;
#pragma mark - Accessibility
void onAccessibilityAction(const std::string &name) const;
void onAccessibilityTap() const;
void onAccessibilityMagicTap() const;
+ void onAccessibilityEscape() const;
#pragma mark - Layout
void onLayout(const LayoutMetrics &layoutMetrics) const;
-
-#pragma mark - Touches
-
- void onTouchStart(const TouchEvent &event) const;
- void onTouchMove(const TouchEvent &event) const;
- void onTouchEnd(const TouchEvent &event) const;
- void onTouchCancel(const TouchEvent &event) const;
};
} // namespace react

ReactCommon/fabric/components/view/ViewProps.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,54 +7,118 @@
#include "ViewProps.h"
-#include <fabric/components/view/conversions.h>
-#include <fabric/core/propsConversions.h>
-#include <fabric/debug/debugStringConvertibleUtils.h>
-#include <fabric/graphics/conversions.h>
+#include <react/components/view/conversions.h>
+#include <react/components/view/propsConversions.h>
+#include <react/core/propsConversions.h>
+#include <react/debug/debugStringConvertibleUtils.h>
+#include <react/graphics/conversions.h>
namespace facebook {
namespace react {
-ViewProps::ViewProps(const YGStyle &yogaStyle):
- YogaStylableProps(yogaStyle) {}
+ViewProps::ViewProps(const YGStyle &yogaStyle) : YogaStylableProps(yogaStyle) {}
-ViewProps::ViewProps(const ViewProps &sourceProps, const RawProps &rawProps):
- Props(sourceProps, rawProps),
+ViewProps::ViewProps(const ViewProps &sourceProps, const RawProps &rawProps)
+ : Props(sourceProps, rawProps),
YogaStylableProps(sourceProps, rawProps),
- opacity(convertRawProp(rawProps, "opacity", sourceProps.opacity, (Float)1.0)),
- foregroundColor(convertRawProp(rawProps, "foregroundColor", sourceProps.foregroundColor)),
- backgroundColor(convertRawProp(rawProps, "backgroundColor", sourceProps.backgroundColor)),
- borderWidth(convertRawProp(rawProps, "borderWidth", sourceProps.borderWidth)),
- borderRadius(convertRawProp(rawProps, "borderRadius", sourceProps.borderRadius)),
- borderColor(convertRawProp(rawProps, "borderColor", sourceProps.borderColor)),
- borderStyle(convertRawProp(rawProps, "borderStyle", sourceProps.borderStyle)),
- shadowColor(convertRawProp(rawProps, "shadowColor", sourceProps.shadowColor)),
- shadowOffset(convertRawProp(rawProps, "shadowOffset", sourceProps.shadowOffset)),
- shadowOpacity(convertRawProp(rawProps, "shadowOpacity", sourceProps.shadowOpacity)),
- shadowRadius(convertRawProp(rawProps, "shadowRadius", sourceProps.shadowRadius)),
+ AccessibilityProps(sourceProps, rawProps),
+ opacity(
+ convertRawProp(rawProps, "opacity", sourceProps.opacity, (Float)1.0)),
+ foregroundColor(convertRawProp(
+ rawProps,
+ "foregroundColor",
+ sourceProps.foregroundColor)),
+ backgroundColor(convertRawProp(
+ rawProps,
+ "backgroundColor",
+ sourceProps.backgroundColor)),
+ borderRadii(convertRawProp(
+ rawProps,
+ "border",
+ "Radius",
+ sourceProps.borderRadii)),
+ borderColors(convertRawProp(
+ rawProps,
+ "border",
+ "Color",
+ sourceProps.borderColors)),
+ borderStyles(convertRawProp(
+ rawProps,
+ "border",
+ "Style",
+ sourceProps.borderStyles)),
+ shadowColor(
+ convertRawProp(rawProps, "shadowColor", sourceProps.shadowColor)),
+ shadowOffset(
+ convertRawProp(rawProps, "shadowOffset", sourceProps.shadowOffset)),
+ shadowOpacity(
+ convertRawProp(rawProps, "shadowOpacity", sourceProps.shadowOpacity)),
+ shadowRadius(
+ convertRawProp(rawProps, "shadowRadius", sourceProps.shadowRadius)),
transform(convertRawProp(rawProps, "transform", sourceProps.transform)),
- backfaceVisibility(convertRawProp(rawProps, "backfaceVisibility", sourceProps.backfaceVisibility)),
- shouldRasterize(convertRawProp(rawProps, "shouldRasterize", sourceProps.shouldRasterize)),
+ backfaceVisibility(convertRawProp(
+ rawProps,
+ "backfaceVisibility",
+ sourceProps.backfaceVisibility)),
+ shouldRasterize(convertRawProp(
+ rawProps,
+ "shouldRasterize",
+ sourceProps.shouldRasterize)),
zIndex(convertRawProp(rawProps, "zIndex", sourceProps.zIndex)),
- pointerEvents(convertRawProp(rawProps, "pointerEvents", sourceProps.pointerEvents)),
+ pointerEvents(
+ convertRawProp(rawProps, "pointerEvents", sourceProps.pointerEvents)),
hitSlop(convertRawProp(rawProps, "hitSlop", sourceProps.hitSlop)),
- onLayout(convertRawProp(rawProps, "onLayout", sourceProps.onLayout)) {};
+ onLayout(convertRawProp(rawProps, "onLayout", sourceProps.onLayout)),
+ collapsable(convertRawProp(
+ rawProps,
+ "collapsable",
+ sourceProps.collapsable,
+ true)){};
+
+#pragma mark - Convenience Methods
+
+BorderMetrics ViewProps::resolveBorderMetrics(bool isRTL) const {
+ auto borderWidths = CascadedBorderWidths{
+ .left = optionalFloatFromYogaValue(yogaStyle.border[YGEdgeLeft]),
+ .top = optionalFloatFromYogaValue(yogaStyle.border[YGEdgeTop]),
+ .right = optionalFloatFromYogaValue(yogaStyle.border[YGEdgeRight]),
+ .bottom = optionalFloatFromYogaValue(yogaStyle.border[YGEdgeBottom]),
+ .start = optionalFloatFromYogaValue(yogaStyle.border[YGEdgeStart]),
+ .end = optionalFloatFromYogaValue(yogaStyle.border[YGEdgeEnd]),
+ .horizontal =
+ optionalFloatFromYogaValue(yogaStyle.border[YGEdgeHorizontal]),
+ .vertical = optionalFloatFromYogaValue(yogaStyle.border[YGEdgeVertical]),
+ .all = optionalFloatFromYogaValue(yogaStyle.border[YGEdgeAll])};
+
+ return {.borderColors = borderColors.resolve(isRTL, {}),
+ .borderWidths = borderWidths.resolve(isRTL, 0),
+ .borderRadii = borderRadii.resolve(isRTL, 0),
+ .borderStyles = borderStyles.resolve(isRTL, BorderStyle::Solid)};
+}
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList ViewProps::getDebugProps() const {
const auto &defaultViewProps = ViewProps();
- return
- AccessibilityProps::getDebugProps() +
+ return AccessibilityProps::getDebugProps() +
YogaStylableProps::getDebugProps() +
- SharedDebugStringConvertibleList {
+ SharedDebugStringConvertibleList{
debugStringConvertibleItem("zIndex", zIndex, defaultViewProps.zIndex),
- debugStringConvertibleItem("opacity", opacity, defaultViewProps.opacity),
- debugStringConvertibleItem("foregroundColor", foregroundColor, defaultViewProps.foregroundColor),
- debugStringConvertibleItem("backgroundColor", backgroundColor, defaultViewProps.backgroundColor),
+ debugStringConvertibleItem(
+ "opacity", opacity, defaultViewProps.opacity),
+ debugStringConvertibleItem(
+ "foregroundColor",
+ foregroundColor,
+ defaultViewProps.foregroundColor),
+ debugStringConvertibleItem(
+ "backgroundColor",
+ backgroundColor,
+ defaultViewProps.backgroundColor),
};
}
+#endif
} // namespace react
} // namespace facebook

ReactCommon/fabric/components/view/ViewProps.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,12 +7,12 @@
#pragma once
-#include <fabric/components/view/AccessibilityProps.h>
-#include <fabric/components/view/primitives.h>
-#include <fabric/components/view/YogaStylableProps.h>
-#include <fabric/core/Props.h>
-#include <fabric/graphics/Geometry.h>
-#include <fabric/graphics/Color.h>
+#include <react/components/view/AccessibilityProps.h>
+#include <react/components/view/YogaStylableProps.h>
+#include <react/components/view/primitives.h>
+#include <react/core/Props.h>
+#include <react/graphics/Color.h>
+#include <react/graphics/Geometry.h>
namespace facebook {
namespace react {
@@ -21,12 +21,10 @@
using SharedViewProps = std::shared_ptr<const ViewProps>;
-class ViewProps:
- public Props,
+class ViewProps : public Props,
public YogaStylableProps,
public AccessibilityProps {
-
-public:
+ public:
ViewProps() = default;
ViewProps(const YGStyle &yogaStyle);
ViewProps(const ViewProps &sourceProps, const RawProps &rawProps);
@@ -34,36 +32,43 @@
#pragma mark - Props
// Color
- const Float opacity {1.0};
- const SharedColor foregroundColor {};
- const SharedColor backgroundColor {};
+ const Float opacity{1.0};
+ const SharedColor foregroundColor{};
+ const SharedColor backgroundColor{};
// Borders
- const EdgeInsets borderWidth {};
- const CornerInsets borderRadius {};
- const SharedColor borderColor {};
- const BorderStyle borderStyle {};
+ const CascadedBorderRadii borderRadii{};
+ const CascadedBorderColors borderColors{};
+ const CascadedBorderStyles borderStyles{};
// Shadow
- const SharedColor shadowColor {};
- const Size shadowOffset {};
- const Float shadowOpacity {};
- const Float shadowRadius {};
+ const SharedColor shadowColor{};
+ const Size shadowOffset{};
+ const Float shadowOpacity{};
+ const Float shadowRadius{};
// Transform
- const Transform transform {};
- const bool backfaceVisibility {};
- const bool shouldRasterize {};
- const int zIndex {};
+ const Transform transform{};
+ const bool backfaceVisibility{};
+ const bool shouldRasterize{};
+ const int zIndex{};
// Events
- const PointerEventsMode pointerEvents {};
- const EdgeInsets hitSlop {};
- const bool onLayout {};
+ const PointerEventsMode pointerEvents{};
+ const EdgeInsets hitSlop{};
+ const bool onLayout{};
+
+ const bool collapsable{true};
+
+#pragma mark - Convenience Methods
+
+ BorderMetrics resolveBorderMetrics(bool isRTL) const;
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList getDebugProps() const override;
+#endif
};
} // namespace react

ReactCommon/fabric/components/view/ViewShadowNode.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -12,5 +12,24 @@
const char ViewComponentName[] = "View";
+bool ViewShadowNode::isLayoutOnly() const {
+ const auto &viewProps = *std::static_pointer_cast<const ViewProps>(props_);
+
+ return viewProps.collapsable &&
+ // Event listeners
+ !viewProps.onLayout &&
+ // Generic Props
+ viewProps.nativeId.empty() &&
+ // Accessibility Props
+ !viewProps.accessible &&
+ // Style Props
+ viewProps.yogaStyle.overflow == YGOverflowVisible &&
+ viewProps.opacity == 1.0 && !viewProps.backgroundColor &&
+ !viewProps.foregroundColor && !viewProps.shadowColor &&
+ viewProps.transform == Transform{} && viewProps.zIndex == 0 &&
+ // Layout Metrics
+ getLayoutMetrics().borderWidth == EdgeInsets{};
+}
+
} // namespace react
} // namespace facebook

ReactCommon/fabric/components/view/ViewShadowNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,20 +7,26 @@
#pragma once
-#include <fabric/components/view/ViewProps.h>
-#include <fabric/components/view/ConcreteViewShadowNode.h>
+#include <react/components/view/ConcreteViewShadowNode.h>
+#include <react/components/view/ViewProps.h>
namespace facebook {
namespace react {
extern const char ViewComponentName[];
-using ViewShadowNode =
- ConcreteViewShadowNode<
+/*
+ * `ShadowNode` for <View> component.
+ */
+class ViewShadowNode final : public ConcreteViewShadowNode<
ViewComponentName,
ViewProps,
- ViewEventEmitter
- >;
+ ViewEventEmitter> {
+ public:
+ using ConcreteViewShadowNode::ConcreteViewShadowNode;
+
+ bool isLayoutOnly() const;
+};
} // namespace react
} // namespace facebook

ReactCommon/fabric/components/view/yoga/YogaLayoutableShadowNode.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,19 +10,18 @@
#include <algorithm>
#include <memory>
-#include <fabric/components/view/conversions.h>
-#include <fabric/core/LayoutContext.h>
-#include <fabric/core/LayoutConstraints.h>
-#include <fabric/debug/DebugStringConvertibleItem.h>
+#include <react/components/view/conversions.h>
+#include <react/core/LayoutConstraints.h>
+#include <react/core/LayoutContext.h>
+#include <react/debug/DebugStringConvertibleItem.h>
+#include <react/debug/SystraceSection.h>
#include <yoga/Yoga.h>
namespace facebook {
namespace react {
-YogaLayoutableShadowNode::YogaLayoutableShadowNode():
- yogaNode_({}),
- yogaConfig_(nullptr) {
-
+YogaLayoutableShadowNode::YogaLayoutableShadowNode()
+ : yogaNode_({}), yogaConfig_(nullptr) {
initializeYogaConfig(yogaConfig_);
yogaNode_.setConfig(&yogaConfig_);
@@ -31,11 +30,8 @@
}
YogaLayoutableShadowNode::YogaLayoutableShadowNode(
- const YogaLayoutableShadowNode &layoutableShadowNode
-):
- yogaNode_(layoutableShadowNode.yogaNode_),
- yogaConfig_(nullptr) {
-
+ const YogaLayoutableShadowNode &layoutableShadowNode)
+ : yogaNode_(layoutableShadowNode.yogaNode_), yogaConfig_(nullptr) {
initializeYogaConfig(yogaConfig_);
yogaNode_.setConfig(&yogaConfig_);
@@ -69,7 +65,8 @@
void YogaLayoutableShadowNode::enableMeasurement() {
ensureUnsealed();
- yogaNode_.setMeasureFunc(YogaLayoutableShadowNode::yogaNodeMeasureCallbackConnector);
+ yogaNode_.setMeasureFunc(
+ YogaLayoutableShadowNode::yogaNodeMeasureCallbackConnector);
}
void YogaLayoutableShadowNode::appendChild(YogaLayoutableShadowNode *child) {
@@ -79,7 +76,8 @@
auto childYogaNodeRawPtr = &child->yogaNode_;
if (childYogaNodeRawPtr->getOwner() != nullptr) {
- child = static_cast<YogaLayoutableShadowNode *>(cloneAndReplaceChild(child, yogaNode_.getChildren().size()));
+ child = static_cast<YogaLayoutableShadowNode *>(
+ cloneAndReplaceChild(child, yogaNode_.getChildren().size()));
childYogaNodeRawPtr = &child->yogaNode_;
assert(childYogaNodeRawPtr->getOwner() == nullptr);
}
@@ -87,10 +85,12 @@
child->ensureUnsealed();
childYogaNodeRawPtr->setOwner(yogaNodeRawPtr);
- yogaNodeRawPtr->insertChild(childYogaNodeRawPtr, yogaNodeRawPtr->getChildren().size());
+ yogaNodeRawPtr->insertChild(
+ childYogaNodeRawPtr, yogaNodeRawPtr->getChildren().size());
}
-void YogaLayoutableShadowNode::setChildren(std::vector<YogaLayoutableShadowNode *> children) {
+void YogaLayoutableShadowNode::setChildren(
+ std::vector<YogaLayoutableShadowNode *> children) {
yogaNode_.setChildren({});
for (const auto &child : children) {
appendChild(child);
@@ -115,7 +115,13 @@
* (and this is by design).
*/
yogaConfig_.pointScaleFactor = layoutContext.pointScaleFactor;
- YGNodeCalculateLayout(&yogaNode_, YGUndefined, YGUndefined, YGDirectionInherit);
+
+ {
+ SystraceSection s("YogaLayoutableShadowNode::YGNodeCalculateLayout");
+
+ YGNodeCalculateLayout(
+ &yogaNode_, YGUndefined, YGUndefined, YGDirectionInherit);
+ }
}
LayoutableShadowNode::layout(layoutContext);
@@ -126,13 +132,15 @@
auto childNode =
static_cast<YogaLayoutableShadowNode *>(childYogaNode->getContext());
- LayoutMetrics childLayoutMetrics = layoutMetricsFromYogaNode(childNode->yogaNode_);
+ LayoutMetrics childLayoutMetrics =
+ layoutMetricsFromYogaNode(childNode->yogaNode_);
childLayoutMetrics.pointScaleFactor = layoutContext.pointScaleFactor;
childNode->setLayoutMetrics(childLayoutMetrics);
}
}
-std::vector<LayoutableShadowNode *> YogaLayoutableShadowNode::getLayoutableChildNodes() const {
+std::vector<LayoutableShadowNode *>
+YogaLayoutableShadowNode::getLayoutableChildNodes() const {
std::vector<LayoutableShadowNode *> yogaLayoutableChildNodes;
yogaLayoutableChildNodes.reserve(yogaNode_.getChildren().size());
@@ -147,32 +155,47 @@
#pragma mark - Yoga Connectors
-YGNode *YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector(YGNode *oldYogaNode, YGNode *parentYogaNode, int childIndex) {
- // At this point it is garanteed that all shadow nodes associated with yoga nodes are `YogaLayoutableShadowNode` subclasses.
+YGNode *YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector(
+ YGNode *oldYogaNode,
+ YGNode *parentYogaNode,
+ int childIndex) {
+ SystraceSection s("YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector");
+
+ // At this point it is garanteed that all shadow nodes associated with yoga
+ // nodes are `YogaLayoutableShadowNode` subclasses.
auto parentNode =
static_cast<YogaLayoutableShadowNode *>(parentYogaNode->getContext());
auto oldNode =
static_cast<YogaLayoutableShadowNode *>(oldYogaNode->getContext());
- auto clonedNode =
- static_cast<YogaLayoutableShadowNode *>(parentNode->cloneAndReplaceChild(oldNode, childIndex));
+ auto clonedNode = static_cast<YogaLayoutableShadowNode *>(
+ parentNode->cloneAndReplaceChild(oldNode, childIndex));
return &clonedNode->yogaNode_;
}
-YGSize YogaLayoutableShadowNode::yogaNodeMeasureCallbackConnector(YGNode *yogaNode, float width, YGMeasureMode widthMode, float height, YGMeasureMode heightMode) {
- auto shadowNodeRawPtr = static_cast<YogaLayoutableShadowNode *>(yogaNode->getContext());
+YGSize YogaLayoutableShadowNode::yogaNodeMeasureCallbackConnector(
+ YGNode *yogaNode,
+ float width,
+ YGMeasureMode widthMode,
+ float height,
+ YGMeasureMode heightMode) {
+ SystraceSection s(
+ "YogaLayoutableShadowNode::yogaNodeMeasureCallbackConnector");
+
+ auto shadowNodeRawPtr =
+ static_cast<YogaLayoutableShadowNode *>(yogaNode->getContext());
- auto minimumSize = Size {0, 0};
- auto maximumSize = Size {kFloatMax, kFloatMax};
+ auto minimumSize = Size{0, 0};
+ auto maximumSize = Size{kFloatMax, kFloatMax};
switch (widthMode) {
case YGMeasureModeUndefined:
break;
case YGMeasureModeExactly:
- minimumSize.width = fabricFloatFromYogaFloat(width);
- maximumSize.width = fabricFloatFromYogaFloat(width);
+ minimumSize.width = floatFromYogaFloat(width);
+ maximumSize.width = floatFromYogaFloat(width);
break;
case YGMeasureModeAtMost:
- maximumSize.width = fabricFloatFromYogaFloat(width);
+ maximumSize.width = floatFromYogaFloat(width);
break;
}
@@ -180,24 +203,23 @@
case YGMeasureModeUndefined:
break;
case YGMeasureModeExactly:
- minimumSize.height = fabricFloatFromYogaFloat(height);
- maximumSize.height = fabricFloatFromYogaFloat(height);
+ minimumSize.height = floatFromYogaFloat(height);
+ maximumSize.height = floatFromYogaFloat(height);
break;
case YGMeasureModeAtMost:
- maximumSize.height = fabricFloatFromYogaFloat(height);
+ maximumSize.height = floatFromYogaFloat(height);
break;
}
auto size = shadowNodeRawPtr->measure({minimumSize, maximumSize});
- return YGSize {
- yogaFloatFromFabricFloat(size.width),
- yogaFloatFromFabricFloat(size.height)
- };
+ return YGSize{yogaFloatFromFloat(size.width),
+ yogaFloatFromFloat(size.height)};
}
void YogaLayoutableShadowNode::initializeYogaConfig(YGConfig &config) {
- config.cloneNodeCallback = YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector;
+ config.cloneNodeCallback =
+ YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector;
}
} // namespace react

ReactCommon/fabric/components/view/yoga/YogaLayoutableShadowNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -12,26 +12,24 @@
#include <yoga/YGNode.h>
-#include <fabric/components/view/YogaStylableProps.h>
-#include <fabric/core/LayoutableShadowNode.h>
-#include <fabric/core/Sealable.h>
-#include <fabric/debug/DebugStringConvertible.h>
+#include <react/components/view/YogaStylableProps.h>
+#include <react/core/LayoutableShadowNode.h>
+#include <react/core/Sealable.h>
+#include <react/debug/DebugStringConvertible.h>
namespace facebook {
namespace react {
-class YogaLayoutableShadowNode:
- public LayoutableShadowNode,
+class YogaLayoutableShadowNode : public LayoutableShadowNode,
public virtual DebugStringConvertible,
public virtual Sealable {
-
-public:
-
+ public:
#pragma mark - Constructors
YogaLayoutableShadowNode();
- YogaLayoutableShadowNode(const YogaLayoutableShadowNode &layoutableShadowNode);
+ YogaLayoutableShadowNode(
+ const YogaLayoutableShadowNode &layoutableShadowNode);
#pragma mark - Mutating Methods
@@ -43,13 +41,15 @@
/*
* Appends `child`'s Yoga node to the own Yoga node.
- * Complements `ShadowNode::appendChild(...)` functionality from Yoga perspective.
+ * Complements `ShadowNode::appendChild(...)` functionality from Yoga
+ * perspective.
*/
void appendChild(YogaLayoutableShadowNode *child);
/*
- * Sets Yoga children based on collection of `YogaLayoutableShadowNode` instances.
- * Complements `ShadowNode::setChildren(...)` functionality from Yoga perspective.
+ * Sets Yoga children based on collection of `YogaLayoutableShadowNode`
+ * instances. Complements `ShadowNode::setChildren(...)` functionality from
+ * Yoga perspective.
*/
void setChildren(std::vector<YogaLayoutableShadowNode *> children);
@@ -77,7 +77,7 @@
std::vector<LayoutableShadowNode *> getLayoutableChildNodes() const override;
-protected:
+ protected:
/*
* All Yoga functions only accept non-const arguments, so we have to mark
* Yoga node as `mutable` here to avoid `static_cast`ing the pointer to this
@@ -90,10 +90,18 @@
*/
YGConfig yogaConfig_;
-private:
+ private:
static void initializeYogaConfig(YGConfig &config);
- static YGNode *yogaNodeCloneCallbackConnector(YGNode *oldYogaNode, YGNode *parentYogaNode, int childIndex);
- static YGSize yogaNodeMeasureCallbackConnector(YGNode *yogaNode, float width, YGMeasureMode widthMode, float height, YGMeasureMode heightMode);
+ static YGNode *yogaNodeCloneCallbackConnector(
+ YGNode *oldYogaNode,
+ YGNode *parentYogaNode,
+ int childIndex);
+ static YGSize yogaNodeMeasureCallbackConnector(
+ YGNode *yogaNode,
+ float width,
+ YGMeasureMode widthMode,
+ float height,
+ YGMeasureMode heightMode);
};
} // namespace react

ReactCommon/fabric/components/view/yoga/YogaStylableProps.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,10 +7,10 @@
#include "YogaStylableProps.h"
-#include <fabric/components/view/conversions.h>
-#include <fabric/core/propsConversions.h>
-#include <fabric/components/view/propsConversions.h>
-#include <fabric/debug/debugStringConvertibleUtils.h>
+#include <react/components/view/conversions.h>
+#include <react/components/view/propsConversions.h>
+#include <react/core/propsConversions.h>
+#include <react/debug/debugStringConvertibleUtils.h>
#include <yoga/YGNode.h>
#include <yoga/Yoga.h>
@@ -19,41 +19,78 @@
namespace facebook {
namespace react {
-YogaStylableProps::YogaStylableProps(const YGStyle &yogaStyle):
- yogaStyle(yogaStyle) {}
+YogaStylableProps::YogaStylableProps(const YGStyle &yogaStyle)
+ : yogaStyle(yogaStyle) {}
-YogaStylableProps::YogaStylableProps(const YogaStylableProps &sourceProps, const RawProps &rawProps):
- yogaStyle(convertRawProp(rawProps, sourceProps.yogaStyle)) {};
+YogaStylableProps::YogaStylableProps(
+ const YogaStylableProps &sourceProps,
+ const RawProps &rawProps)
+ : yogaStyle(convertRawProp(rawProps, sourceProps.yogaStyle)){};
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList YogaStylableProps::getDebugProps() const {
- YGStyle defaultYogaStyle;
+ auto defaultYogaStyle = YGStyle{};
return {
- debugStringConvertibleItem("direction", yogaStyle.direction, defaultYogaStyle.direction),
- debugStringConvertibleItem("flexDirection", yogaStyle.flexDirection, defaultYogaStyle.flexDirection),
- debugStringConvertibleItem("justifyContent", yogaStyle.justifyContent, defaultYogaStyle.justifyContent),
- debugStringConvertibleItem("alignContent", yogaStyle.alignContent, defaultYogaStyle.alignContent),
- debugStringConvertibleItem("alignItems", yogaStyle.alignItems, defaultYogaStyle.alignItems),
- debugStringConvertibleItem("alignSelf", yogaStyle.alignSelf, defaultYogaStyle.alignSelf),
- debugStringConvertibleItem("positionType", yogaStyle.positionType, defaultYogaStyle.positionType),
- debugStringConvertibleItem("flexWrap", yogaStyle.flexWrap, defaultYogaStyle.flexWrap),
- debugStringConvertibleItem("overflow", yogaStyle.overflow, defaultYogaStyle.overflow),
- debugStringConvertibleItem("display", yogaStyle.display, defaultYogaStyle.display),
+ debugStringConvertibleItem(
+ "direction", yogaStyle.direction, defaultYogaStyle.direction),
+ debugStringConvertibleItem(
+ "flexDirection",
+ yogaStyle.flexDirection,
+ defaultYogaStyle.flexDirection),
+ debugStringConvertibleItem(
+ "justifyContent",
+ yogaStyle.justifyContent,
+ defaultYogaStyle.justifyContent),
+ debugStringConvertibleItem(
+ "alignContent",
+ yogaStyle.alignContent,
+ defaultYogaStyle.alignContent),
+ debugStringConvertibleItem(
+ "alignItems", yogaStyle.alignItems, defaultYogaStyle.alignItems),
+ debugStringConvertibleItem(
+ "alignSelf", yogaStyle.alignSelf, defaultYogaStyle.alignSelf),
+ debugStringConvertibleItem(
+ "positionType",
+ yogaStyle.positionType,
+ defaultYogaStyle.positionType),
+ debugStringConvertibleItem(
+ "flexWrap", yogaStyle.flexWrap, defaultYogaStyle.flexWrap),
+ debugStringConvertibleItem(
+ "overflow", yogaStyle.overflow, defaultYogaStyle.overflow),
+ debugStringConvertibleItem(
+ "display", yogaStyle.display, defaultYogaStyle.display),
debugStringConvertibleItem("flex", yogaStyle.flex, defaultYogaStyle.flex),
- debugStringConvertibleItem("flexGrow", yogaStyle.flexGrow, defaultYogaStyle.flexGrow),
- debugStringConvertibleItem("flexShrink", yogaStyle.flexShrink, defaultYogaStyle.flexShrink),
- debugStringConvertibleItem("flexBasis", yogaStyle.flexBasis, defaultYogaStyle.flexBasis),
- debugStringConvertibleItem("margin", yogaStyle.margin, defaultYogaStyle.margin),
- debugStringConvertibleItem("position", yogaStyle.position, defaultYogaStyle.position),
- debugStringConvertibleItem("padding", yogaStyle.padding, defaultYogaStyle.padding),
- debugStringConvertibleItem("border", yogaStyle.border, defaultYogaStyle.border),
- debugStringConvertibleItem("dimensions", yogaStyle.dimensions, defaultYogaStyle.dimensions),
- debugStringConvertibleItem("minDimensions", yogaStyle.minDimensions, defaultYogaStyle.minDimensions),
- debugStringConvertibleItem("maxDimensions", yogaStyle.maxDimensions, defaultYogaStyle.maxDimensions),
- debugStringConvertibleItem("aspectRatio", yogaStyle.aspectRatio, defaultYogaStyle.aspectRatio),
+ debugStringConvertibleItem(
+ "flexGrow", yogaStyle.flexGrow, defaultYogaStyle.flexGrow),
+ debugStringConvertibleItem(
+ "flexShrink", yogaStyle.flexShrink, defaultYogaStyle.flexShrink),
+ debugStringConvertibleItem(
+ "flexBasis", yogaStyle.flexBasis, defaultYogaStyle.flexBasis),
+ debugStringConvertibleItem(
+ "margin", yogaStyle.margin, defaultYogaStyle.margin),
+ debugStringConvertibleItem(
+ "position", yogaStyle.position, defaultYogaStyle.position),
+ debugStringConvertibleItem(
+ "padding", yogaStyle.padding, defaultYogaStyle.padding),
+ debugStringConvertibleItem(
+ "border", yogaStyle.border, defaultYogaStyle.border),
+ debugStringConvertibleItem(
+ "dimensions", yogaStyle.dimensions, defaultYogaStyle.dimensions),
+ debugStringConvertibleItem(
+ "minDimensions",
+ yogaStyle.minDimensions,
+ defaultYogaStyle.minDimensions),
+ debugStringConvertibleItem(
+ "maxDimensions",
+ yogaStyle.maxDimensions,
+ defaultYogaStyle.maxDimensions),
+ debugStringConvertibleItem(
+ "aspectRatio", yogaStyle.aspectRatio, defaultYogaStyle.aspectRatio),
};
}
+#endif
} // namespace react
} // namespace facebook

ReactCommon/fabric/components/view/yoga/YogaStylableProps.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,8 +9,8 @@
#include <yoga/YGStyle.h>
-#include <fabric/core/Props.h>
-#include <fabric/debug/DebugStringConvertible.h>
+#include <react/core/Props.h>
+#include <react/debug/DebugStringConvertible.h>
namespace facebook {
namespace react {
@@ -20,20 +20,22 @@
typedef std::shared_ptr<const YogaStylableProps> SharedYogaStylableProps;
class YogaStylableProps {
-
-public:
-
+ public:
YogaStylableProps() = default;
YogaStylableProps(const YGStyle &yogaStyle);
- YogaStylableProps(const YogaStylableProps &sourceProps, const RawProps &rawProps);
+ YogaStylableProps(
+ const YogaStylableProps &sourceProps,
+ const RawProps &rawProps);
#pragma mark - Props
- const YGStyle yogaStyle {};
+ const YGStyle yogaStyle{};
#pragma mark - DebugStringConvertible (Partial)
+#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList getDebugProps() const;
+#endif
};
} // namespace react

ReactCommon/fabric/core/BUCK

@@ -1,5 +1,5 @@
-load("//configurations/buck/apple:flag_defs.bzl", "OBJC_ARC_PREPROCESSOR_FLAGS", "get_application_ios_flags", "get_debug_preprocessor_flags")
-load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", "subdir_glob", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", "react_native_xplat_target", "rn_xplat_cxx_library")
+load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags")
+load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", "react_native_xplat_target", "rn_xplat_cxx_library", "subdir_glob")
APPLE_COMPILER_FLAGS = get_apple_compiler_flags()
@@ -23,7 +23,7 @@
("layout", "*.h"),
("shadownode", "*.h"),
],
- prefix = "fabric/core",
+ prefix = "react/core",
),
compiler_flags = [
"-fexceptions",
@@ -33,9 +33,6 @@
],
fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
- fbobjc_tests = [
- ":tests",
- ],
force_static = True,
macosx_tests_override = [],
platforms = (ANDROID, APPLE),
@@ -43,7 +40,7 @@
"-DLOG_TAG=\"ReactNative\"",
"-DWITH_FBSYSTRACE=1",
],
- tests = [],
+ tests = [":tests"],
visibility = ["PUBLIC"],
deps = [
"xplat//fbsystrace:fbsystrace",
@@ -51,6 +48,7 @@
"xplat//folly:memory",
"xplat//folly:molly",
"xplat//third-party/glog:glog",
+ react_native_xplat_target("utils:utils"),
react_native_xplat_target("fabric/debug:debug"),
react_native_xplat_target("fabric/events:events"),
react_native_xplat_target("fabric/graphics:graphics"),
@@ -68,7 +66,7 @@
"-Wall",
],
contacts = ["oncall+react_native@xmail.facebook.com"],
- platforms = APPLE,
+ platforms = (ANDROID, APPLE),
deps = [
"xplat//folly:molly",
"xplat//third-party/gmock:gtest",

ReactCommon/fabric/core/componentdescriptor/ComponentDescriptor.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,8 +7,8 @@
#pragma once
-#include <fabric/core/ShadowNode.h>
-#include <fabric/core/Props.h>
+#include <react/core/Props.h>
+#include <react/core/ShadowNode.h>
namespace facebook {
namespace react {
@@ -24,8 +24,7 @@
* `ShadowNode`s (such as creating, cloning, props and children managing).
*/
class ComponentDescriptor {
-public:
-
+ public:
virtual ~ComponentDescriptor() = default;
/*
@@ -45,24 +44,21 @@
* Creates a new `ShadowNode` of a particular type.
*/
virtual SharedShadowNode createShadowNode(
- const ShadowNodeFragment &fragment
- ) const = 0;
+ const ShadowNodeFragment &fragment) const = 0;
/*
* Clones a `ShadowNode` with optionally new `props` and/or `children`.
*/
virtual UnsharedShadowNode cloneShadowNode(
const ShadowNode &sourceShadowNode,
- const ShadowNodeFragment &fragment
- ) const = 0;
+ const ShadowNodeFragment &fragment) const = 0;
/*
* Appends (by mutating) a given `childShadowNode` to `parentShadowNode`.
*/
virtual void appendChild(
const SharedShadowNode &parentShadowNode,
- const SharedShadowNode &childShadowNode
- ) const = 0;
+ const SharedShadowNode &childShadowNode) const = 0;
/*
* Creates a new `Props` of a particular type with all values copied from
@@ -72,17 +68,15 @@
*/
virtual SharedProps cloneProps(
const SharedProps &props,
- const RawProps &rawProps
- ) const = 0;
+ const RawProps &rawProps) const = 0;
/*
* Creates a new `EventEmitter` object compatible with particular type of
* shadow nodes.
*/
virtual SharedEventEmitter createEventEmitter(
- const EventTarget &eventTarget,
- const Tag &tag
- ) const = 0;
+ SharedEventTarget eventTarget,
+ const Tag &tag) const = 0;
};
} // namespace react

ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,14 +7,14 @@
#pragma once
-#include <memory>
#include <functional>
+#include <memory>
-#include <fabric/core/ComponentDescriptor.h>
-#include <fabric/core/Props.h>
-#include <fabric/core/ShadowNode.h>
-#include <fabric/core/ShadowNodeFragment.h>
-#include <fabric/events/EventDispatcher.h>
+#include <react/core/ComponentDescriptor.h>
+#include <react/core/Props.h>
+#include <react/core/ShadowNode.h>
+#include <react/core/ShadowNodeFragment.h>
+#include <react/events/EventDispatcher.h>
namespace facebook {
namespace react {
@@ -25,18 +25,21 @@
* if necessary.
*/
template <typename ShadowNodeT>
-class ConcreteComponentDescriptor: public ComponentDescriptor {
- static_assert(std::is_base_of<ShadowNode, ShadowNodeT>::value, "ShadowNodeT must be a descendant of ShadowNode");
+class ConcreteComponentDescriptor : public ComponentDescriptor {
+ static_assert(
+ std::is_base_of<ShadowNode, ShadowNodeT>::value,
+ "ShadowNodeT must be a descendant of ShadowNode");
using SharedShadowNodeT = std::shared_ptr<const ShadowNodeT>;
using ConcreteProps = typename ShadowNodeT::ConcreteProps;
using SharedConcreteProps = typename ShadowNodeT::SharedConcreteProps;
using ConcreteEventEmitter = typename ShadowNodeT::ConcreteEventEmitter;
- using SharedConcreteEventEmitter = typename ShadowNodeT::SharedConcreteEventEmitter;
+ using SharedConcreteEventEmitter =
+ typename ShadowNodeT::SharedConcreteEventEmitter;
-public:
- ConcreteComponentDescriptor(SharedEventDispatcher eventDispatcher):
- eventDispatcher_(eventDispatcher) {}
+ public:
+ ConcreteComponentDescriptor(SharedEventDispatcher eventDispatcher)
+ : eventDispatcher_(eventDispatcher) {}
ComponentHandle getComponentHandle() const override {
return ShadowNodeT::Handle();
@@ -47,15 +50,13 @@
}
SharedShadowNode createShadowNode(
- const ShadowNodeFragment &fragment
- ) const override {
+ const ShadowNodeFragment &fragment) const override {
assert(std::dynamic_pointer_cast<const ConcreteProps>(fragment.props));
- assert(std::dynamic_pointer_cast<const ConcreteEventEmitter>(fragment.eventEmitter));
+ assert(std::dynamic_pointer_cast<const ConcreteEventEmitter>(
+ fragment.eventEmitter));
- auto shadowNode = std::make_shared<ShadowNodeT>(
- fragment,
- getCloneFunction()
- );
+ auto shadowNode =
+ std::make_shared<ShadowNodeT>(fragment, getCloneFunction());
adopt(shadowNode);
@@ -64,12 +65,8 @@
UnsharedShadowNode cloneShadowNode(
const ShadowNode &sourceShadowNode,
- const ShadowNodeFragment &fragment
- ) const override {
- auto shadowNode = std::make_shared<ShadowNodeT>(
- sourceShadowNode,
- fragment
- );
+ const ShadowNodeFragment &fragment) const override {
+ auto shadowNode = std::make_shared<ShadowNodeT>(sourceShadowNode, fragment);
adopt(shadowNode);
return shadowNode;
@@ -77,43 +74,43 @@
void appendChild(
const SharedShadowNode &parentShadowNode,
- const SharedShadowNode &childShadowNode
- ) const override {
- auto concreteParentShadowNode = std::static_pointer_cast<const ShadowNodeT>(parentShadowNode);
- auto concreteNonConstParentShadowNode = std::const_pointer_cast<ShadowNodeT>(concreteParentShadowNode);
+ const SharedShadowNode &childShadowNode) const override {
+ auto concreteParentShadowNode =
+ std::static_pointer_cast<const ShadowNodeT>(parentShadowNode);
+ auto concreteNonConstParentShadowNode =
+ std::const_pointer_cast<ShadowNodeT>(concreteParentShadowNode);
concreteNonConstParentShadowNode->appendChild(childShadowNode);
}
virtual SharedProps cloneProps(
const SharedProps &props,
- const RawProps &rawProps
- ) const override {
+ const RawProps &rawProps) const override {
return ShadowNodeT::Props(rawProps, props);
};
virtual SharedEventEmitter createEventEmitter(
- const EventTarget &eventTarget,
- const Tag &tag
- ) const override {
- return std::make_shared<ConcreteEventEmitter>(eventTarget, tag, eventDispatcher_);
+ SharedEventTarget eventTarget,
+ const Tag &tag) const override {
+ return std::make_shared<ConcreteEventEmitter>(
+ std::move(eventTarget), tag, eventDispatcher_);
}
-protected:
-
+ protected:
virtual void adopt(UnsharedShadowNode shadowNode) const {
// Default implementation does nothing.
assert(shadowNode->getComponentHandle() == getComponentHandle());
}
-private:
-
- mutable SharedEventDispatcher eventDispatcher_ {nullptr};
+ private:
+ mutable SharedEventDispatcher eventDispatcher_{nullptr};
mutable ShadowNodeCloneFunction cloneFunction_;
ShadowNodeCloneFunction getCloneFunction() const {
if (!cloneFunction_) {
- cloneFunction_ = [this](const ShadowNode &shadowNode, const ShadowNodeFragment &fragment) {
+ cloneFunction_ = [this](
+ const ShadowNode &shadowNode,
+ const ShadowNodeFragment &fragment) {
return this->cloneShadowNode(shadowNode, fragment);
};
}

ReactCommon/fabric/core/conversions.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,26 +7,46 @@
#pragma once
-#include <fabric/core/LayoutPrimitives.h>
+#include <react/core/LayoutPrimitives.h>
namespace facebook {
namespace react {
inline std::string toString(const LayoutDirection &layoutDirection) {
switch (layoutDirection) {
- case LayoutDirection::Undefined: return "undefined";
- case LayoutDirection::LeftToRight: return "ltr";
- case LayoutDirection::RightToLeft: return "rtl";
+ case LayoutDirection::Undefined:
+ return "undefined";
+ case LayoutDirection::LeftToRight:
+ return "ltr";
+ case LayoutDirection::RightToLeft:
+ return "rtl";
}
}
inline std::string toString(const DisplayType &displayType) {
switch (displayType) {
- case DisplayType::None: return "none";
- case DisplayType::Flex: return "flex";
- case DisplayType::Inline: return "inline";
+ case DisplayType::None:
+ return "none";
+ case DisplayType::Flex:
+ return "flex";
+ case DisplayType::Inline:
+ return "inline";
}
}
+inline Size yogaMeassureToSize(int64_t value) {
+ static_assert(
+ sizeof(value) == 8,
+ "Expected measureResult to be 8 bytes, or two 32 bit ints");
+
+ int32_t wBits = 0xFFFFFFFF & (value >> 32);
+ int32_t hBits = 0xFFFFFFFF & value;
+
+ float *measuredWidth = reinterpret_cast<float *>(&wBits);
+ float *measuredHeight = reinterpret_cast<float *>(&hBits);
+
+ return {*measuredWidth, *measuredHeight};
+}
+
} // namespace react
} // namespace facebook

ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,11 +7,12 @@
#include "LayoutableShadowNode.h"
-#include <fabric/core/LayoutConstraints.h>
-#include <fabric/core/LayoutContext.h>
-#include <fabric/core/LayoutMetrics.h>
-#include <fabric/debug/DebugStringConvertibleItem.h>
-#include <fabric/graphics/conversions.h>
+#include <react/core/LayoutConstraints.h>
+#include <react/core/LayoutContext.h>
+#include <react/core/LayoutMetrics.h>
+#include <react/core/ShadowNode.h>
+#include <react/debug/DebugStringConvertibleItem.h>
+#include <react/graphics/conversions.h>
namespace facebook {
namespace react {
@@ -31,6 +32,39 @@
return true;
}
+bool LayoutableShadowNode::LayoutableShadowNode::isLayoutOnly() const {
+ return false;
+}
+
+LayoutMetrics LayoutableShadowNode::getRelativeLayoutMetrics(
+ const LayoutableShadowNode &ancestorLayoutableShadowNode) const {
+ std::vector<std::reference_wrapper<const ShadowNode>> ancestors;
+
+ auto &ancestorShadowNode =
+ dynamic_cast<const ShadowNode &>(ancestorLayoutableShadowNode);
+ auto &shadowNode = dynamic_cast<const ShadowNode &>(*this);
+
+ if (!shadowNode.constructAncestorPath(ancestorShadowNode, ancestors)) {
+ return EmptyLayoutMetrics;
+ }
+
+ auto layoutMetrics = getLayoutMetrics();
+
+ for (const auto &currentShadowNode : ancestors) {
+ auto layoutableCurrentShadowNode =
+ dynamic_cast<const LayoutableShadowNode *>(&currentShadowNode.get());
+
+ if (!layoutableCurrentShadowNode) {
+ return EmptyLayoutMetrics;
+ }
+
+ layoutMetrics.frame.origin +=
+ layoutableCurrentShadowNode->getLayoutMetrics().frame.origin;
+ }
+
+ return layoutMetrics;
+}
+
void LayoutableShadowNode::cleanLayout() {
isLayoutClean_ = true;
}
@@ -74,12 +108,12 @@
child->ensureUnsealed();
child->setHasNewLayout(false);
- const LayoutMetrics childLayoutMetrics = child->getLayoutMetrics();
+ const auto childLayoutMetrics = child->getLayoutMetrics();
if (childLayoutMetrics.displayType == DisplayType::None) {
continue;
}
- LayoutContext childLayoutContext = LayoutContext(layoutContext);
+ auto childLayoutContext = LayoutContext(layoutContext);
childLayoutContext.absolutePosition += childLayoutMetrics.frame.origin;
child->layout(layoutContext);
@@ -90,28 +124,33 @@
// Default implementation does nothing.
}
+#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList LayoutableShadowNode::getDebugProps() const {
- SharedDebugStringConvertibleList list = {};
+ auto list = SharedDebugStringConvertibleList{};
if (getHasNewLayout()) {
- list.push_back(std::make_shared<DebugStringConvertibleItem>("hasNewLayout"));
+ list.push_back(
+ std::make_shared<DebugStringConvertibleItem>("hasNewLayout"));
}
if (!getIsLayoutClean()) {
list.push_back(std::make_shared<DebugStringConvertibleItem>("dirty"));
}
- LayoutMetrics layoutMetrics = getLayoutMetrics();
- LayoutMetrics defaultLayoutMetrics = LayoutMetrics();
+ auto layoutMetrics = getLayoutMetrics();
+ auto defaultLayoutMetrics = LayoutMetrics();
- list.push_back(std::make_shared<DebugStringConvertibleItem>("frame", toString(layoutMetrics.frame)));
+ list.push_back(std::make_shared<DebugStringConvertibleItem>(
+ "frame", toString(layoutMetrics.frame)));
if (layoutMetrics.borderWidth != defaultLayoutMetrics.borderWidth) {
- list.push_back(std::make_shared<DebugStringConvertibleItem>("borderWidth", toString(layoutMetrics.borderWidth)));
+ list.push_back(std::make_shared<DebugStringConvertibleItem>(
+ "borderWidth", toString(layoutMetrics.borderWidth)));
}
if (layoutMetrics.contentInsets != defaultLayoutMetrics.contentInsets) {
- list.push_back(std::make_shared<DebugStringConvertibleItem>("contentInsets", toString(layoutMetrics.contentInsets)));
+ list.push_back(std::make_shared<DebugStringConvertibleItem>(
+ "contentInsets", toString(layoutMetrics.contentInsets)));
}
if (layoutMetrics.displayType == DisplayType::None) {
@@ -124,6 +163,7 @@
return list;
}
+#endif
} // namespace react
} // namespace facebook

ReactCommon/fabric/core/layout/LayoutableShadowNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,12 +9,12 @@
#include <array>
#include <cmath>
-#include <vector>
#include <memory>
+#include <vector>
-#include <fabric/core/LayoutMetrics.h>
-#include <fabric/core/Sealable.h>
-#include <fabric/debug/DebugStringConvertible.h>
+#include <react/core/LayoutMetrics.h>
+#include <react/core/Sealable.h>
+#include <react/debug/DebugStringConvertible.h>
namespace facebook {
namespace react {
@@ -26,10 +26,9 @@
* Describes all sufficient layout API (in approach-agnostic way)
* which makes a concurrent layout possible.
*/
-class LayoutableShadowNode:
- public virtual Sealable {
-
-public:
+class LayoutableShadowNode : public virtual Sealable {
+ public:
+ virtual ~LayoutableShadowNode() noexcept = default;
/*
* Measures the node (and node content, propbably recursivly) with
@@ -42,8 +41,9 @@
* Computes layout recusively.
* Additional environmental constraints might be provided via `layoutContext`
* argument.
- * Default implementation basically calls `layoutChildren()` and then `layout()`
- * (recursively), and provides some obvious performance optimization.
+ * Default implementation basically calls `layoutChildren()` and then
+ * `layout()` (recursively), and provides some obvious performance
+ * optimization.
*/
virtual void layout(LayoutContext layoutContext);
@@ -52,8 +52,20 @@
*/
virtual LayoutMetrics getLayoutMetrics() const;
-protected:
+ /*
+ * Returns `true` if the node represents only information necessary for
+ * layout computation and can be safely removed from view hierarchy.
+ * Default implementation returns `false`.
+ */
+ virtual bool isLayoutOnly() const;
+
+ /*
+ * Returns layout metrics relatively to the given ancestor node.
+ */
+ LayoutMetrics getRelativeLayoutMetrics(
+ const LayoutableShadowNode &ancestorLayoutableShadowNode) const;
+ protected:
/*
* Clean or Dirty layout state:
* Indicates whether all nodes (and possibly their subtrees) along the path
@@ -85,13 +97,16 @@
/*
* Returns layoutable children to interate on.
*/
- virtual std::vector<LayoutableShadowNode *> getLayoutableChildNodes() const = 0;
+ virtual std::vector<LayoutableShadowNode *> getLayoutableChildNodes()
+ const = 0;
/*
* In case layout algorithm needs to mutate this (probably sealed) node,
* it has to clone and replace it in the hierarchy before to do so.
*/
- virtual LayoutableShadowNode *cloneAndReplaceChild(LayoutableShadowNode *child, int suggestedIndex = -1) = 0;
+ virtual LayoutableShadowNode *cloneAndReplaceChild(
+ LayoutableShadowNode *child,
+ int suggestedIndex = -1) = 0;
/*
* Sets layout metrics for the shadow node.
@@ -101,12 +116,14 @@
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList getDebugProps() const;
+#endif
-private:
- LayoutMetrics layoutMetrics_ {};
- bool hasNewLayout_ {false};
- bool isLayoutClean_ {false};
+ private:
+ LayoutMetrics layoutMetrics_{};
+ bool hasNewLayout_{false};
+ bool isLayoutClean_{false};
};
} // namespace react

ReactCommon/fabric/core/layout/LayoutConstraints.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,8 +7,9 @@
#pragma once
-#include <fabric/core/LayoutPrimitives.h>
-#include <fabric/graphics/Geometry.h>
+#include <folly/Hash.h>
+#include <react/core/LayoutPrimitives.h>
+#include <react/graphics/Geometry.h>
namespace facebook {
namespace react {
@@ -17,10 +18,33 @@
* Unified layout constraints for measuring.
*/
struct LayoutConstraints {
- Size minimumSize {0, 0};
- Size maximumSize {kFloatUndefined, kFloatUndefined};
- LayoutDirection layoutDirection;
+ Size minimumSize{0, 0};
+ Size maximumSize{kFloatUndefined, kFloatUndefined};
+ LayoutDirection layoutDirection{LayoutDirection::Undefined};
};
+inline bool operator==(
+ const LayoutConstraints &lhs,
+ const LayoutConstraints &rhs) {
+ return std::tie(lhs.minimumSize, lhs.maximumSize, lhs.layoutDirection) ==
+ std::tie(rhs.minimumSize, rhs.maximumSize, rhs.layoutDirection);
+}
+
} // namespace react
} // namespace facebook
+
+namespace std {
+template <>
+struct hash<facebook::react::LayoutConstraints> {
+ size_t operator()(
+ const facebook::react::LayoutConstraints &constraints) const {
+ auto seed = size_t{0};
+ folly::hash::hash_combine(
+ seed,
+ constraints.minimumSize,
+ constraints.maximumSize,
+ constraints.layoutDirection);
+ return seed;
+ }
+};
+} // namespace std

ReactCommon/fabric/core/layout/LayoutContext.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,7 +7,7 @@
#pragma once
-#include <fabric/graphics/Geometry.h>
+#include <react/graphics/Geometry.h>
namespace facebook {
namespace react {
@@ -20,7 +20,7 @@
/*
* Compound absolute position of the node relative to the root node.
*/
- Point absolutePosition {0, 0};
+ Point absolutePosition{0, 0};
/*
* Reflects the scale factor needed to convert from the logical coordinate

ReactCommon/fabric/core/layout/LayoutMetrics.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,8 +7,8 @@
#pragma once
-#include <fabric/core/LayoutPrimitives.h>
-#include <fabric/graphics/Geometry.h>
+#include <react/core/LayoutPrimitives.h>
+#include <react/graphics/Geometry.h>
namespace facebook {
namespace react {
@@ -18,29 +18,46 @@
*/
struct LayoutMetrics {
Rect frame;
- EdgeInsets contentInsets {0};
- EdgeInsets borderWidth {0};
- DisplayType displayType {DisplayType::Flex};
- LayoutDirection layoutDirection {LayoutDirection::Undefined};
- Float pointScaleFactor {1.0};
+ EdgeInsets contentInsets{0};
+ EdgeInsets borderWidth{0};
+ DisplayType displayType{DisplayType::Flex};
+ LayoutDirection layoutDirection{LayoutDirection::Undefined};
+ Float pointScaleFactor{1.0};
Rect getContentFrame() const {
- return Rect {
- Point {contentInsets.left, contentInsets.top},
- Size {frame.size.width - contentInsets.left - contentInsets.right, frame.size.height - contentInsets.top - contentInsets.bottom}
- };
+ return Rect{
+ Point{contentInsets.left, contentInsets.top},
+ Size{frame.size.width - contentInsets.left - contentInsets.right,
+ frame.size.height - contentInsets.top - contentInsets.bottom}};
}
- bool operator ==(const LayoutMetrics& rhs) const {
- return
- std::tie(this->frame, this->contentInsets, this->borderWidth, this->displayType, this->layoutDirection) ==
- std::tie(rhs.frame, rhs.contentInsets, rhs.borderWidth, rhs.displayType, rhs.layoutDirection);
+ bool operator==(const LayoutMetrics &rhs) const {
+ return std::tie(
+ this->frame,
+ this->contentInsets,
+ this->borderWidth,
+ this->displayType,
+ this->layoutDirection,
+ this->pointScaleFactor) ==
+ std::tie(
+ rhs.frame,
+ rhs.contentInsets,
+ rhs.borderWidth,
+ rhs.displayType,
+ rhs.layoutDirection,
+ this->pointScaleFactor);
}
- bool operator !=(const LayoutMetrics& rhs) const {
+ bool operator!=(const LayoutMetrics &rhs) const {
return !(*this == rhs);
}
};
+/*
+ * Represents some undefined, not-yet-computed or meaningless value of
+ * `LayoutMetrics` type.
+ */
+static const LayoutMetrics EmptyLayoutMetrics = {.frame = {.size = {-1, -1}}};
+
} // namespace react
} // namespace facebook

ReactCommon/fabric/core/layout/LayoutPrimitives.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,6 +7,9 @@
#pragma once
+#include <functional>
+#include <limits>
+
namespace facebook {
namespace react {
@@ -31,3 +34,12 @@
} // namespace react
} // namespace facebook
+
+namespace std {
+template <>
+struct hash<facebook::react::LayoutDirection> {
+ size_t operator()(const facebook::react::LayoutDirection &v) const {
+ return hash<int>()(static_cast<int>(v));
+ }
+};
+} // namespace std

ReactCommon/fabric/core/primitives/RawProps.cpp

@@ -0,0 +1,8 @@
+/**
+ * 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.
+ */
+
+#include "RawProps.h"

ReactCommon/fabric/core/primitives/RawProps.h

@@ -0,0 +1,97 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <folly/dynamic.h>
+#include <jsi/JSIDynamic.h>
+#include <jsi/jsi.h>
+#include <react/core/RawValue.h>
+
+namespace facebook {
+namespace react {
+
+/*
+ * `RawProps` represents an untyped map of props comes from JavaScript side.
+ * `RawProps` stores JSI (or `folly::dynamic`) primitives inside and abstract
+ * them as `RawValue` objects.
+ * `RawProps` is NOT a thread-safe type nor long-living type.
+ * The caller must not store values of this type.
+ * The class is practically a wrapper around a `jsi::Value and `jsi::Runtime`
+ * pair (or folly::dynamic) preventing direct access to it and inefficient
+ * misuse. Not copyable, not moveable.
+ */
+class RawProps {
+ public:
+ /*
+ * Creates an object with given `runtime` and `value`.
+ */
+ RawProps(jsi::Runtime &runtime, const jsi::Value &value) noexcept
+ : RawProps(
+ value.isNull() ? folly::dynamic::object()
+ : jsi::dynamicFromValue(runtime, value)) {}
+
+ /*
+ * Creates an object with given `folly::dynamic` object.
+ * Deprecated.
+ * We need this temporary, only because we have a callsite that does not have
+ * a `jsi::Runtime` behind the data.
+ */
+ RawProps(const folly::dynamic &dynamic) noexcept
+ :
+#ifdef ANDROID
+ dynamic_(dynamic),
+#endif
+ map_((std::unordered_map<std::string, RawValue>)RawValue(dynamic)) {
+ }
+
+ /*
+ * Not moveable.
+ */
+ RawProps(RawProps &&other) noexcept = delete;
+ RawProps &operator=(RawProps &&other) noexcept = delete;
+
+ /*
+ * Not copyable.
+ */
+ RawProps(const RawProps &other) noexcept = delete;
+ RawProps &operator=(const RawProps &other) noexcept = delete;
+
+#ifdef ANDROID
+ /*
+ * Deprecated. Do not use.
+ * The support for explicit conversion to `folly::dynamic` is deprecated and
+ * will be removed as soon Android implementation does not need it.
+ */
+ explicit operator folly::dynamic() const noexcept {
+ return dynamic_;
+ }
+#endif
+
+ /*
+ * Returns a const unowning pointer to `RawValue` of a prop with a given name.
+ * Returns `nullptr`, it a prop with the given name does not exist.
+ */
+ const RawValue *at(const std::string &name) const noexcept {
+ auto iterator = map_.find(name);
+ if (iterator == map_.end()) {
+ return nullptr;
+ }
+
+ return &iterator->second;
+ }
+
+ private:
+#ifdef ANDROID
+ const folly::dynamic dynamic_;
+#endif
+
+ const std::unordered_map<std::string, RawValue> map_;
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/core/primitives/RawValue.cpp

@@ -0,0 +1,8 @@
+/**
+ * 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.
+ */
+
+#include "RawValue.h"

ReactCommon/fabric/core/primitives/RawValue.h

@@ -0,0 +1,266 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <folly/dynamic.h>
+#include <jsi/JSIDynamic.h>
+#include <jsi/jsi.h>
+
+namespace facebook {
+namespace react {
+
+class RawProps;
+
+/*
+ * `RawValue` abstracts some arbitrary complex data structure similar to JSON.
+ * `RawValue` supports explicit conversion to: `bool`, `int`, `int64_t`,
+ * `float`, `double`, `string`, and `vector` & `map` of those types and itself.
+ *
+ * The main intention of the class is to abstract React props parsing infra from
+ * JSI, to enable support for any non-JSI-based data sources. The particular
+ * implementation of the interface is a very slim abstraction around
+ * `folly::dynamic` though.
+ * In the near future, this class will hold a `jsi::Runtime` and `jsi::Value`
+ * pair instead of `folly::dynamic`.
+ *
+ * How `RawValue` is different from `JSI::Value`:
+ * * `RawValue` provides much more scoped API without any references to
+ * JavaScript specifics.
+ * * The API is much more C++-idiomatic and easy to use from C++ code.
+ * * The API prevents access to JSI/JavaScript internals from prop-parsing
+ * code.
+ * * The `RawValue` is not copyable nor thread-safe, which prevent
+ * misuse and accidental performance problems.
+ *
+ * How `RawValue` is different from `folly::dynamic`:
+ * * `RawValue` is a lazy data structure, it does not copy all content inside,
+ * it provides efficient SAX-like access to the data.
+ * * `RawValue` has more static and C++-idiomatic API.
+ * * The `RawValue` is not copyable nor thread-safe, which prevent
+ * misuse and accidental performance problems.
+ */
+class RawValue {
+ public:
+ /*
+ * Constructors.
+ */
+ RawValue() noexcept : dynamic_(nullptr){};
+
+ RawValue(RawValue &&other) noexcept : dynamic_(std::move(other.dynamic_)) {}
+
+ RawValue &operator=(RawValue &&other) noexcept {
+ if (this != &other) {
+ dynamic_ = std::move(other.dynamic_);
+ }
+ return *this;
+ }
+
+ private:
+ friend RawProps;
+
+ /*
+ * Arbitrary constructors are private only for RawProps and internal usage.
+ */
+ RawValue(const folly::dynamic &dynamic) noexcept : dynamic_(dynamic){};
+
+ RawValue(folly::dynamic &&dynamic) noexcept : dynamic_(std::move(dynamic)){};
+
+ /*
+ * Copy constructor and copy assignment operator are private and only for
+ * internal use. Basically, it's implementation details. Other particular
+ * implementations of the `RawValue` interface may not have them.
+ */
+ RawValue(RawValue const &other) noexcept : dynamic_(other.dynamic_) {}
+
+ RawValue &operator=(const RawValue &other) noexcept {
+ if (this != &other) {
+ dynamic_ = other.dynamic_;
+ }
+ return *this;
+ }
+
+ public:
+ /*
+ * Casts the value to a specified type.
+ */
+ template <typename T>
+ explicit operator T() const noexcept {
+ return castValue(dynamic_, (T *)nullptr);
+ }
+
+ inline explicit operator folly::dynamic() const {
+ return dynamic_;
+ }
+
+ /*
+ * Checks if the stored value has specified type.
+ */
+ template <typename T>
+ bool hasType() const noexcept {
+ return checkValueType(dynamic_, (T *)nullptr);
+ };
+
+ /*
+ * Checks if the stored value is *not* `null`.
+ */
+ bool hasValue() const noexcept {
+ return !dynamic_.isNull();
+ }
+
+ private:
+ folly::dynamic dynamic_;
+
+ static bool checkValueType(
+ const folly::dynamic &dynamic,
+ RawValue *type) noexcept {
+ return true;
+ }
+
+ static bool checkValueType(
+ const folly::dynamic &dynamic,
+ bool *type) noexcept {
+ return dynamic.isBool();
+ }
+
+ static bool checkValueType(
+ const folly::dynamic &dynamic,
+ int *type) noexcept {
+ return dynamic.isNumber();
+ }
+
+ static bool checkValueType(
+ const folly::dynamic &dynamic,
+ int64_t *type) noexcept {
+ return dynamic.isNumber();
+ }
+
+ static bool checkValueType(
+ const folly::dynamic &dynamic,
+ float *type) noexcept {
+ return dynamic.isNumber();
+ }
+
+ static bool checkValueType(
+ const folly::dynamic &dynamic,
+ double *type) noexcept {
+ return dynamic.isNumber();
+ }
+
+ static bool checkValueType(
+ const folly::dynamic &dynamic,
+ std::string *type) noexcept {
+ return dynamic.isString();
+ }
+
+ template <typename T>
+ static bool checkValueType(
+ const folly::dynamic &dynamic,
+ std::vector<T> *type) noexcept {
+ if (!dynamic.isArray()) {
+ return false;
+ }
+
+ for (const auto &item : dynamic) {
+ if (!checkValueType(item, (T *)nullptr)) {
+ return false;
+ }
+
+ // Note: We test only one element.
+ break;
+ }
+
+ return true;
+ }
+
+ template <typename T>
+ static bool checkValueType(
+ const folly::dynamic &dynamic,
+ std::unordered_map<std::string, T> *type) noexcept {
+ if (!dynamic.isObject()) {
+ return false;
+ }
+
+ for (const auto &item : dynamic.items()) {
+ assert(item.first.isString());
+ if (!checkValueType(item.second, (T *)nullptr)) {
+ return false;
+ }
+
+ // Note: We test only one element.
+ break;
+ }
+
+ return true;
+ }
+
+ // Casts
+ static RawValue castValue(
+ const folly::dynamic &dynamic,
+ RawValue *type) noexcept {
+ return RawValue(dynamic);
+ }
+
+ static bool castValue(const folly::dynamic &dynamic, bool *type) noexcept {
+ return dynamic.getBool();
+ }
+
+ static int castValue(const folly::dynamic &dynamic, int *type) noexcept {
+ return dynamic.asInt();
+ }
+
+ static int64_t castValue(
+ const folly::dynamic &dynamic,
+ int64_t *type) noexcept {
+ return dynamic.asInt();
+ }
+
+ static float castValue(const folly::dynamic &dynamic, float *type) noexcept {
+ return dynamic.asDouble();
+ }
+
+ static double castValue(
+ const folly::dynamic &dynamic,
+ double *type) noexcept {
+ return dynamic.asDouble();
+ }
+
+ static std::string castValue(
+ const folly::dynamic &dynamic,
+ std::string *type) noexcept {
+ return dynamic.getString();
+ }
+
+ template <typename T>
+ static std::vector<T> castValue(
+ const folly::dynamic &dynamic,
+ std::vector<T> *type) noexcept {
+ assert(dynamic.isArray());
+ auto result = std::vector<T>{};
+ result.reserve(dynamic.size());
+ for (const auto &item : dynamic) {
+ result.push_back(castValue(item, (T *)nullptr));
+ }
+ return result;
+ }
+
+ template <typename T>
+ static std::unordered_map<std::string, T> castValue(
+ const folly::dynamic &dynamic,
+ std::unordered_map<std::string, T> *type) noexcept {
+ assert(dynamic.isObject());
+ auto result = std::unordered_map<std::string, T>{};
+ for (const auto &item : dynamic.items()) {
+ assert(item.first.isString());
+ result[item.first.getString()] = castValue(item.second, (T *)nullptr);
+ }
+ return result;
+ }
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/core/primitives/ReactPrimitives.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,12 +7,13 @@
#pragma once
+#include <folly/dynamic.h>
+#include <react/core/RawProps.h>
+#include <react/core/RawValue.h>
#include <memory>
#include <string>
#include <unordered_map>
-#include <folly/dynamic.h>
-
namespace facebook {
namespace react {
@@ -20,14 +21,13 @@
* `Tag` and `InstanceHandle` are used to address React Native components.
*/
using Tag = int32_t;
-using InstanceHandle = struct InstanceHandleDummyStruct {} *;
+using InstanceHandle = struct InstanceHandleDummyStruct {
+} *;
/*
- * `RawProps` represents untyped map with props comes from JavaScript side.
+ * An id of a running Surface instance that is used to refer to the instance.
*/
-// TODO(T26954420): Use iterator as underlying type for RawProps.
-using RawProps = std::unordered_map<std::string, folly::dynamic>;
-using SharedRawProps = std::shared_ptr<const RawProps>;
+using SurfaceId = int32_t;
/*
* Universal component handle which allows to refer to `ComponentDescriptor`s

ReactCommon/fabric/core/primitives/Sealable.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -26,11 +26,11 @@
#ifndef NDEBUG
-Sealable::Sealable(): sealed_(false) {}
+Sealable::Sealable() : sealed_(false) {}
-Sealable::Sealable(const Sealable &other): sealed_(false) {};
+Sealable::Sealable(const Sealable &other) : sealed_(false){};
-Sealable::Sealable(Sealable &&other) noexcept: sealed_(false) {};
+Sealable::Sealable(Sealable &&other) noexcept : sealed_(false){};
Sealable::~Sealable() noexcept {};

ReactCommon/fabric/core/primitives/Sealable.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,13 +7,14 @@
#pragma once
-#import <atomic>
+#include <atomic>
namespace facebook {
namespace react {
/*
- * Represents an object which can be *sealed* (imperatively marked as immutable).
+ * Represents an object which can be *sealed* (imperatively marked as
+ * immutable).
*
* The `sealed` flag is tight to a particular instance of the class and resets
* to `false` for all newly created (by copy-constructor, assignment operator
@@ -21,22 +22,22 @@
*
* Why do we need this? In Fabric, some objects are semi-immutable
* even if they are explicitly marked as `const`. It means that in some special
- * cases those objects can be const-casted-away and then mutated. That comes from
- * the fact that we share some object's life-cycle responsibilities with React
- * and the immutability is guaranteed by some logic splitted between native and
- * JavaScript worlds (which makes it impossible to fully use immutability
- * enforcement at a language level).
- * To detect possible errors as early as possible we additionally mark objects
- * as *sealed* after some stages and then enforce this at run-time.
+ * cases those objects can be const-casted-away and then mutated. That comes
+ * from the fact that we share some object's life-cycle responsibilities with
+ * React and the immutability is guaranteed by some logic splitted between
+ * native and JavaScript worlds (which makes it impossible to fully use
+ * immutability enforcement at a language level). To detect possible errors as
+ * early as possible we additionally mark objects as *sealed* after some stages
+ * and then enforce this at run-time.
*
* How to use:
* 1. Inherit your class from `Sealable`.
* 2. Call `ensureUnsealed()` in all cases where the object might be mutated:
* a. At the beginning of all *always* mutating `non-const` methods;
- * b. Right before the place where actual mutation happens in all *possible*
- * mutating `non-const` methods;
- * c. Right after performing `const_cast`. (Optionally. This is not strictly
- * necessary but might help detect problems earlier.)
+ * b. Right before the place where actual mutation happens in all
+ * *possible* mutating `non-const` methods; c. Right after performing
+ * `const_cast`. (Optionally. This is not strictly necessary but might help
+ * detect problems earlier.)
* 3. Call `seal()` at some point from which any modifications
* must be prevented.
*/
@@ -44,16 +45,18 @@
#ifdef NDEBUG
class Sealable {
-public:
+ public:
inline void seal() const {}
- inline bool getSealed() const { return true; }
+ inline bool getSealed() const {
+ return true;
+ }
inline void ensureUnsealed() const {}
};
#else
class Sealable {
-public:
+ public:
Sealable();
Sealable(const Sealable &other);
Sealable(Sealable &&other) noexcept;
@@ -78,8 +81,8 @@
*/
void ensureUnsealed() const;
-private:
- mutable std::atomic<bool> sealed_ {false};
+ private:
+ mutable std::atomic<bool> sealed_{false};
};
#endif

ReactCommon/fabric/core/propsConversions.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,86 +9,86 @@
#include <folly/Optional.h>
#include <folly/dynamic.h>
-#include <fabric/graphics/Color.h>
-#include <fabric/graphics/Geometry.h>
-#include <fabric/graphics/conversions.h>
+#include <react/core/RawProps.h>
+#include <react/graphics/Color.h>
+#include <react/graphics/Geometry.h>
+#include <react/graphics/conversions.h>
namespace facebook {
namespace react {
-inline void fromDynamic(const folly::dynamic &value, bool &result) { result = value.getBool(); }
-inline void fromDynamic(const folly::dynamic &value, int &result) {
- // All numbers from JS are treated as double, and JS cannot represent int64 in practice.
- // So this always converts the value to int64 instead.
- result = value.asInt();
+template <typename T>
+void fromRawValue(const RawValue &rawValue, T &result) {
+ result = (T)rawValue;
}
-inline void fromDynamic(const folly::dynamic &value, float &result) { result = (float)value.asDouble(); }
-inline void fromDynamic(const folly::dynamic &value, double &result) { result = value.asDouble(); }
-inline void fromDynamic(const folly::dynamic &value, std::string &result) { result = value.getString(); }
template <typename T>
-inline void fromDynamic(const folly::dynamic &value, std::vector<T> &result) {
- if (!value.isArray()) {
+void fromRawValue(const RawValue &rawValue, std::vector<T> &result) {
+ if (rawValue.hasType<std::vector<RawValue>>()) {
+ auto items = (std::vector<RawValue>)rawValue;
+ auto length = items.size();
+ result.clear();
+ result.reserve(length);
+ for (int i = 0; i < length; i++) {
T itemResult;
- fromDynamic(value, itemResult);
- result = {itemResult};
+ fromRawValue(items.at(i), itemResult);
+ result.push_back(itemResult);
+ }
return;
}
+ // The case where `value` is not an array.
result.clear();
+ result.reserve(1);
T itemResult;
- for (auto &itemValue : value) {
- fromDynamic(itemValue, itemResult);
+ fromRawValue(rawValue, itemResult);
result.push_back(itemResult);
- }
}
template <typename T>
-inline T convertRawProp(
+T convertRawProp(
const RawProps &rawProps,
const std::string &name,
const T &sourceValue,
- const T &defaultValue = T()
-) {
- const auto &iterator = rawProps.find(name);
- if (iterator == rawProps.end()) {
+ const T &defaultValue = T()) {
+ const auto rawValue = rawProps.at(name);
+
+ if (!rawValue) {
return sourceValue;
}
- const auto &value = iterator->second;
-
- // Special case: `null` always means `the prop was removed, use default value`.
- if (value.isNull()) {
+ // Special case: `null` always means `the prop was removed, use default
+ // value`.
+ if (!rawValue->hasValue()) {
return defaultValue;
}
T result;
- fromDynamic(value, result);
+ fromRawValue(*rawValue, result);
return result;
}
template <typename T>
-inline static folly::Optional<T> convertRawProp(
+static folly::Optional<T> convertRawProp(
const RawProps &rawProps,
const std::string &name,
const folly::Optional<T> &sourceValue,
- const folly::Optional<T> &defaultValue = {}
-) {
- const auto &iterator = rawProps.find(name);
- if (iterator == rawProps.end()) {
+ const folly::Optional<T> &defaultValue = {}) {
+ const auto rawValue = rawProps.at(name);
+
+ if (!rawValue) {
return sourceValue;
}
- const auto &value = iterator->second;
-
- // Special case: `null` always means `the prop was removed, use default value`.
- if (value.isNull()) {
+ // Special case: `null` always means `the prop was removed, use default
+ // value`.
+ if (!rawValue->hasValue()) {
return defaultValue;
}
T result;
- fromDynamic(value, result);
- return result;
+ fromRawValue(*rawValue, result);
+ return folly::Optional<T>{result};
}
} // namespace react

ReactCommon/fabric/core/shadownode/ConcreteShadowNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,8 +7,8 @@
#pragma once
-#include <fabric/core/Props.h>
-#include <fabric/core/ShadowNode.h>
+#include <react/core/Props.h>
+#include <react/core/ShadowNode.h>
namespace facebook {
namespace react {
@@ -22,12 +22,13 @@
template <
const char *concreteComponentName,
typename PropsT,
- typename EventEmitterT = EventEmitter
->
-class ConcreteShadowNode: public ShadowNode {
- static_assert(std::is_base_of<Props, PropsT>::value, "PropsT must be a descendant of Props");
+ typename EventEmitterT = EventEmitter>
+class ConcreteShadowNode : public ShadowNode {
+ static_assert(
+ std::is_base_of<Props, PropsT>::value,
+ "PropsT must be a descendant of Props");
-public:
+ public:
using ShadowNode::ShadowNode;
using ConcreteProps = PropsT;
@@ -44,12 +45,18 @@
return ComponentHandle(concreteComponentName);
}
- static SharedConcreteProps Props(const RawProps &rawProps, const SharedProps &baseProps = nullptr) {
- return std::make_shared<const PropsT>(baseProps ? *std::static_pointer_cast<const PropsT>(baseProps) : PropsT(), rawProps);
+ static SharedConcreteProps Props(
+ const RawProps &rawProps,
+ const SharedProps &baseProps = nullptr) {
+ return std::make_shared<const PropsT>(
+ baseProps ? *std::static_pointer_cast<const PropsT>(baseProps)
+ : PropsT(),
+ rawProps);
}
static SharedConcreteProps defaultSharedProps() {
- static const SharedConcreteProps defaultSharedProps = std::make_shared<const PropsT>();
+ static const SharedConcreteProps defaultSharedProps =
+ std::make_shared<const PropsT>();
return defaultSharedProps;
}
@@ -69,13 +76,15 @@
/*
* Returns subset of children that are inherited from `SpecificShadowNodeT`.
*/
- template<typename SpecificShadowNodeT>
+ template <typename SpecificShadowNodeT>
std::vector<SpecificShadowNodeT *> getChildrenSlice() const {
std::vector<SpecificShadowNodeT *> children;
for (const auto &childShadowNode : getChildren()) {
- auto specificChildShadowNode = dynamic_cast<const SpecificShadowNodeT *>(childShadowNode.get());
+ auto specificChildShadowNode =
+ dynamic_cast<const SpecificShadowNodeT *>(childShadowNode.get());
if (specificChildShadowNode) {
- children.push_back(const_cast<SpecificShadowNodeT *>(specificChildShadowNode));
+ children.push_back(
+ const_cast<SpecificShadowNodeT *>(specificChildShadowNode));
}
}
return children;

ReactCommon/fabric/core/shadownode/LocalData.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,8 +7,9 @@
#pragma once
-#include <fabric/core/Sealable.h>
-#include <fabric/debug/DebugStringConvertible.h>
+#include <folly/dynamic.h>
+#include <react/core/Sealable.h>
+#include <react/debug/DebugStringConvertible.h>
namespace facebook {
namespace react {
@@ -25,11 +26,13 @@
* All `LocalData` objects *must* be immutable (sealed) when they became
* a part of the shadow tree.
*/
-class LocalData:
- public Sealable,
- public DebugStringConvertible {
-
- // Nothing.
+class LocalData : public Sealable, public DebugStringConvertible {
+ public:
+ virtual ~LocalData() = default;
+
+ virtual folly::dynamic getDynamic() const {
+ return folly::dynamic::object();
+ }
};
} // namespace react

ReactCommon/fabric/core/shadownode/Props.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,14 +7,19 @@
#include "Props.h"
-#include <fabric/core/propsConversions.h>
#include <folly/dynamic.h>
+#include <react/core/propsConversions.h>
namespace facebook {
namespace react {
-Props::Props(const Props &sourceProps, const RawProps &rawProps):
- nativeId(convertRawProp(rawProps, "nativeID", sourceProps.nativeId)) {};
+Props::Props(const Props &sourceProps, const RawProps &rawProps)
+ : nativeId(convertRawProp(rawProps, "nativeID", sourceProps.nativeId))
+#ifdef ANDROID
+ ,
+ rawProps((folly::dynamic)rawProps)
+#endif
+ {};
} // namespace react
} // namespace facebook

ReactCommon/fabric/core/shadownode/Props.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,9 +9,9 @@
#include <folly/dynamic.h>
-#include <fabric/core/Sealable.h>
-#include <fabric/core/ReactPrimitives.h>
-#include <fabric/debug/DebugStringConvertible.h>
+#include <react/core/ReactPrimitives.h>
+#include <react/core/Sealable.h>
+#include <react/debug/DebugStringConvertible.h>
namespace facebook {
namespace react {
@@ -23,15 +23,17 @@
/*
* Represents the most generic props object.
*/
-class Props:
- public virtual Sealable,
- public virtual DebugStringConvertible {
-
-public:
+class Props : public virtual Sealable, public virtual DebugStringConvertible {
+ public:
Props() = default;
Props(const Props &sourceProps, const RawProps &rawProps);
+ virtual ~Props() = default;
const std::string nativeId;
+
+#ifdef ANDROID
+ const folly::dynamic rawProps = folly::dynamic::object();
+#endif
};
} // namespace react

ReactCommon/fabric/core/shadownode/ShadowNode.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,15 +9,16 @@
#include <string>
-#include <fabric/core/ShadowNodeFragment.h>
-#include <fabric/debug/DebugStringConvertible.h>
-#include <fabric/debug/debugStringConvertibleUtils.h>
+#include <react/core/ShadowNodeFragment.h>
+#include <react/debug/DebugStringConvertible.h>
+#include <react/debug/debugStringConvertibleUtils.h>
namespace facebook {
namespace react {
SharedShadowNodeSharedList ShadowNode::emptySharedShadowNodeSharedList() {
- static const auto emptySharedShadowNodeSharedList = std::make_shared<SharedShadowNodeList>();
+ static const auto emptySharedShadowNodeSharedList =
+ std::make_shared<SharedShadowNodeList>();
return emptySharedShadowNodeSharedList;
}
@@ -25,9 +26,8 @@
ShadowNode::ShadowNode(
const ShadowNodeFragment &fragment,
- const ShadowNodeCloneFunction &cloneFunction
-):
- tag_(fragment.tag),
+ const ShadowNodeCloneFunction &cloneFunction)
+ : tag_(fragment.tag),
rootTag_(fragment.rootTag),
props_(fragment.props),
eventEmitter_(fragment.eventEmitter),
@@ -35,16 +35,14 @@
cloneFunction_(cloneFunction),
childrenAreShared_(true),
revision_(1) {
-
assert(props_);
assert(children_);
}
ShadowNode::ShadowNode(
const ShadowNode &sourceShadowNode,
- const ShadowNodeFragment &fragment
-):
- tag_(fragment.tag ?: sourceShadowNode.tag_),
+ const ShadowNodeFragment &fragment)
+ : tag_(fragment.tag ?: sourceShadowNode.tag_),
rootTag_(fragment.rootTag ?: sourceShadowNode.rootTag_),
props_(fragment.props ?: sourceShadowNode.props_),
eventEmitter_(fragment.eventEmitter ?: sourceShadowNode.eventEmitter_),
@@ -109,16 +106,21 @@
ensureUnsealed();
cloneChildrenIfShared();
- auto nonConstChildren = std::const_pointer_cast<SharedShadowNodeList>(children_);
+ auto nonConstChildren =
+ std::const_pointer_cast<SharedShadowNodeList>(children_);
nonConstChildren->push_back(child);
}
-void ShadowNode::replaceChild(const SharedShadowNode &oldChild, const SharedShadowNode &newChild, int suggestedIndex) {
+void ShadowNode::replaceChild(
+ const SharedShadowNode &oldChild,
+ const SharedShadowNode &newChild,
+ int suggestedIndex) {
ensureUnsealed();
cloneChildrenIfShared();
- auto nonConstChildren = std::const_pointer_cast<SharedShadowNodeList>(children_);
+ auto nonConstChildren =
+ std::const_pointer_cast<SharedShadowNodeList>(children_);
if (suggestedIndex != -1 && suggestedIndex < nonConstChildren->size()) {
if (nonConstChildren->at(suggestedIndex) == oldChild) {
@@ -127,7 +129,8 @@
}
}
- std::replace(nonConstChildren->begin(), nonConstChildren->end(), oldChild, newChild);
+ std::replace(
+ nonConstChildren->begin(), nonConstChildren->end(), oldChild, newChild);
}
void ShadowNode::setLocalData(const SharedLocalData &localData) {
@@ -143,38 +146,47 @@
children_ = std::make_shared<SharedShadowNodeList>(*children_);
}
-#pragma mark - Equality
-
-bool ShadowNode::operator==(const ShadowNode& rhs) const {
- // Note: Child nodes are not considered as part of instance's value
- // and/or identity.
- return
- tag_ == rhs.tag_ &&
- rootTag_ == rhs.rootTag_ &&
- props_ == rhs.props_ &&
- eventEmitter_ == rhs.eventEmitter_ &&
- localData_ == rhs.localData_;
+void ShadowNode::setMounted(bool mounted) const {
+ eventEmitter_->setEnabled(mounted);
}
-bool ShadowNode::operator!=(const ShadowNode& rhs) const {
- return !(*this == rhs);
+bool ShadowNode::constructAncestorPath(
+ const ShadowNode &ancestorShadowNode,
+ std::vector<std::reference_wrapper<const ShadowNode>> &ancestors) const {
+ // Note: We have a decent idea of how to make it reasonable performant.
+ // This is not implemented yet though. See T36620537 for more details.
+ if (this == &ancestorShadowNode) {
+ return true;
+ }
+
+ for (const auto &childShadowNode : *ancestorShadowNode.children_) {
+ if (constructAncestorPath(*childShadowNode, ancestors)) {
+ ancestors.push_back(std::ref(ancestorShadowNode));
+ return true;
+ }
+ }
+
+ return false;
}
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
std::string ShadowNode::getDebugName() const {
return getComponentName();
}
std::string ShadowNode::getDebugValue() const {
- return "r" + folly::to<std::string>(revision_) + (getSealed() ? "/sealed" : "");
+ return "r" + folly::to<std::string>(revision_) +
+ (getSealed() ? "/sealed" : "");
}
SharedDebugStringConvertibleList ShadowNode::getDebugChildren() const {
- SharedDebugStringConvertibleList debugChildren = {};
+ auto debugChildren = SharedDebugStringConvertibleList{};
for (auto child : *children_) {
- auto debugChild = std::dynamic_pointer_cast<const DebugStringConvertible>(child);
+ auto debugChild =
+ std::dynamic_pointer_cast<const DebugStringConvertible>(child);
if (debugChild) {
debugChildren.push_back(debugChild);
}
@@ -184,12 +196,11 @@
}
SharedDebugStringConvertibleList ShadowNode::getDebugProps() const {
- return
- props_->getDebugProps() +
- SharedDebugStringConvertibleList {
- debugStringConvertibleItem("tag", folly::to<std::string>(tag_))
- };
+ return props_->getDebugProps() +
+ SharedDebugStringConvertibleList{
+ debugStringConvertibleItem("tag", folly::to<std::string>(tag_))};
}
+#endif
} // namespace react
} // namespace facebook

ReactCommon/fabric/core/shadownode/ShadowNodeFragment.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactCommon/fabric/core/shadownode/ShadowNodeFragment.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,11 +7,11 @@
#pragma once
-#include <fabric/core/LocalData.h>
-#include <fabric/core/Props.h>
-#include <fabric/core/ReactPrimitives.h>
-#include <fabric/core/ShadowNode.h>
-#include <fabric/events/EventEmitter.h>
+#include <react/core/LocalData.h>
+#include <react/core/Props.h>
+#include <react/core/ReactPrimitives.h>
+#include <react/core/ShadowNode.h>
+#include <react/events/EventEmitter.h>
namespace facebook {
namespace react {
@@ -31,7 +31,6 @@
const SharedShadowNodeSharedList &children = nullSharedChildren();
const SharedLocalData &localData = nullLocalData();
-private:
static SharedProps &nullSharedProps();
static SharedEventEmitter &nullSharedEventEmitter();
static SharedShadowNodeSharedList &nullSharedChildren();

ReactCommon/fabric/core/shadownode/ShadowNode.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,16 +7,16 @@
#pragma once
-#include <string>
#include <memory>
+#include <string>
#include <vector>
-#include <fabric/core/LocalData.h>
-#include <fabric/core/Props.h>
-#include <fabric/core/ReactPrimitives.h>
-#include <fabric/core/Sealable.h>
-#include <fabric/events/EventEmitter.h>
-#include <fabric/debug/DebugStringConvertible.h>
+#include <react/core/LocalData.h>
+#include <react/core/Props.h>
+#include <react/core/ReactPrimitives.h>
+#include <react/core/Sealable.h>
+#include <react/debug/DebugStringConvertible.h>
+#include <react/events/EventEmitter.h>
namespace facebook {
namespace react {
@@ -27,21 +27,18 @@
using SharedShadowNode = std::shared_ptr<const ShadowNode>;
using UnsharedShadowNode = std::shared_ptr<ShadowNode>;
-using SharedShadowNodeList = std::vector<std::shared_ptr<const ShadowNode>>;
+using SharedShadowNodeList = std::vector<SharedShadowNode>;
using SharedShadowNodeSharedList = std::shared_ptr<const SharedShadowNodeList>;
using SharedShadowNodeUnsharedList = std::shared_ptr<SharedShadowNodeList>;
using ShadowNodeCloneFunction = std::function<UnsharedShadowNode(
const ShadowNode &sourceShadowNode,
- const ShadowNodeFragment &fragment
-)>;
+ const ShadowNodeFragment &fragment)>;
-class ShadowNode:
- public virtual Sealable,
+class ShadowNode : public virtual Sealable,
public virtual DebugStringConvertible,
public std::enable_shared_from_this<ShadowNode> {
-
-public:
+ public:
static SharedShadowNodeSharedList emptySharedShadowNodeSharedList();
#pragma mark - Constructors
@@ -51,8 +48,7 @@
*/
ShadowNode(
const ShadowNodeFragment &fragment,
- const ShadowNodeCloneFunction &cloneFunction
- );
+ const ShadowNodeCloneFunction &cloneFunction);
/*
* Creates a Shadow Node via cloning given `sourceShadowNode` and
@@ -60,8 +56,9 @@
*/
ShadowNode(
const ShadowNode &sourceShadowNode,
- const ShadowNodeFragment &fragment
- );
+ const ShadowNodeFragment &fragment);
+
+ virtual ~ShadowNode() = default;
/*
* Clones the shadow node using stored `cloneFunction`.
@@ -92,7 +89,10 @@
#pragma mark - Mutating Methods
void appendChild(const SharedShadowNode &child);
- void replaceChild(const SharedShadowNode &oldChild, const SharedShadowNode &newChild, int suggestedIndex = -1);
+ void replaceChild(
+ const SharedShadowNode &oldChild,
+ const SharedShadowNode &newChild,
+ int suggestedIndex = -1);
void clearSourceNode();
/*
@@ -101,26 +101,38 @@
*/
void setLocalData(const SharedLocalData &localData);
-#pragma mark - Equality
-
/*
- * Equality operators.
- * Use this to compare `ShadowNode`s values for equality (and non-equality).
- * Same values indicates that nodes must not produce mutation instructions
- * during tree diffing process.
- * Child nodes are not considered as part of the value.
- */
- virtual bool operator==(const ShadowNode& rhs) const;
- virtual bool operator!=(const ShadowNode& rhs) const;
+ * Performs all side effects associated with mounting/unmounting in one place.
+ * This is not `virtual` on purpose, do not override this.
+ * `EventEmitter::DispatchMutex()` must be acquired before calling.
+ */
+ void setMounted(bool mounted) const;
+
+ /*
+ * Forms a list of all ancestors of the node relative to the given ancestor.
+ * The list starts from the parent node and ends with the given ancestor node.
+ * Returns `true` if successful, `false` otherwise.
+ * Thread-safe if the subtree is immutable.
+ * The theoretical complexity of this algorithm is `O(n)`. Use it wisely.
+ * The particular implementation can use some tricks to mitigate the
+ * complexity problem up to `0(ln(n))` but this is not guaranteed.
+ * Particular consumers should use appropriate cache techniques based on
+ * `childIndex` and `nodeId` tracking.
+ */
+ bool constructAncestorPath(
+ const ShadowNode &rootShadowNode,
+ std::vector<std::reference_wrapper<const ShadowNode>> &ancestors) const;
#pragma mark - DebugStringConvertible
+#if RN_DEBUG_STRING_CONVERTIBLE
std::string getDebugName() const override;
std::string getDebugValue() const override;
SharedDebugStringConvertibleList getDebugChildren() const override;
SharedDebugStringConvertibleList getDebugProps() const override;
+#endif
-protected:
+ protected:
Tag tag_;
Tag rootTag_;
SharedProps props_;
@@ -128,8 +140,7 @@
SharedShadowNodeSharedList children_;
SharedLocalData localData_;
-private:
-
+ private:
/*
* Clones the list of children (and creates a new `shared_ptr` to it) if
* `childrenAreShared_` flag is `true`.

ReactCommon/fabric/core/tests/ComponentDescriptorTest.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -12,19 +12,25 @@
using namespace facebook::react;
TEST(ComponentDescriptorTest, createShadowNode) {
- SharedComponentDescriptor descriptor = std::make_shared<TestComponentDescriptor>(nullptr);
+ SharedComponentDescriptor descriptor =
+ std::make_shared<TestComponentDescriptor>(nullptr);
ASSERT_EQ(descriptor->getComponentHandle(), TestShadowNode::Handle());
- ASSERT_STREQ(descriptor->getComponentName().c_str(), TestShadowNode::Name().c_str());
+ ASSERT_STREQ(
+ descriptor->getComponentName().c_str(), TestShadowNode::Name().c_str());
ASSERT_STREQ(descriptor->getComponentName().c_str(), "Test");
- RawProps raw;
- raw["nativeID"] = "abc";
+ const auto &raw = RawProps(folly::dynamic::object("nativeID", "abc"));
SharedProps props = descriptor->cloneProps(nullptr, raw);
- SharedShadowNode node = descriptor->createShadowNode(ShadowNodeFragment {.tag = 9, .rootTag = 1, .props = props, .eventEmitter = descriptor->createEventEmitter(0, 9)});
+ SharedShadowNode node = descriptor->createShadowNode(
+ ShadowNodeFragment{.tag = 9,
+ .rootTag = 1,
+ .props = props,
+ .eventEmitter = descriptor->createEventEmitter(0, 9)});
ASSERT_EQ(node->getComponentHandle(), TestShadowNode::Handle());
- ASSERT_STREQ(node->getComponentName().c_str(), TestShadowNode::Name().c_str());
+ ASSERT_STREQ(
+ node->getComponentName().c_str(), TestShadowNode::Name().c_str());
ASSERT_STREQ(node->getComponentName().c_str(), "Test");
ASSERT_EQ(node->getTag(), 9);
ASSERT_EQ(node->getRootTag(), 1);
@@ -32,12 +38,16 @@
}
TEST(ComponentDescriptorTest, cloneShadowNode) {
- SharedComponentDescriptor descriptor = std::make_shared<TestComponentDescriptor>(nullptr);
+ SharedComponentDescriptor descriptor =
+ std::make_shared<TestComponentDescriptor>(nullptr);
- RawProps raw;
- raw["nativeID"] = "abc";
+ const auto &raw = RawProps(folly::dynamic::object("nativeID", "abc"));
SharedProps props = descriptor->cloneProps(nullptr, raw);
- SharedShadowNode node = descriptor->createShadowNode(ShadowNodeFragment {.tag = 9, .rootTag = 1, .props = props, .eventEmitter = descriptor->createEventEmitter(0, 9)});
+ SharedShadowNode node = descriptor->createShadowNode(
+ ShadowNodeFragment{.tag = 9,
+ .rootTag = 1,
+ .props = props,
+ .eventEmitter = descriptor->createEventEmitter(0, 9)});
SharedShadowNode cloned = descriptor->cloneShadowNode(*node, {});
ASSERT_STREQ(cloned->getComponentName().c_str(), "Test");
@@ -47,14 +57,26 @@
}
TEST(ComponentDescriptorTest, appendChild) {
- SharedComponentDescriptor descriptor = std::make_shared<TestComponentDescriptor>(nullptr);
+ SharedComponentDescriptor descriptor =
+ std::make_shared<TestComponentDescriptor>(nullptr);
- RawProps raw;
- raw["nativeID"] = "abc";
+ const auto &raw = RawProps(folly::dynamic::object("nativeID", "abc"));
SharedProps props = descriptor->cloneProps(nullptr, raw);
- SharedShadowNode node1 = descriptor->createShadowNode(ShadowNodeFragment {.tag = 1, .rootTag = 1, .props = props, .eventEmitter = descriptor->createEventEmitter(0, 1)});
- SharedShadowNode node2 = descriptor->createShadowNode(ShadowNodeFragment {.tag = 2, .rootTag = 1, .props = props, .eventEmitter = descriptor->createEventEmitter(0, 2)});
- SharedShadowNode node3 = descriptor->createShadowNode(ShadowNodeFragment {.tag = 3, .rootTag = 1, .props = props, .eventEmitter = descriptor->createEventEmitter(0, 3)});
+ SharedShadowNode node1 = descriptor->createShadowNode(
+ ShadowNodeFragment{.tag = 1,
+ .rootTag = 1,
+ .props = props,
+ .eventEmitter = descriptor->createEventEmitter(0, 1)});
+ SharedShadowNode node2 = descriptor->createShadowNode(
+ ShadowNodeFragment{.tag = 2,
+ .rootTag = 1,
+ .props = props,
+ .eventEmitter = descriptor->createEventEmitter(0, 2)});
+ SharedShadowNode node3 = descriptor->createShadowNode(
+ ShadowNodeFragment{.tag = 3,
+ .rootTag = 1,
+ .props = props,
+ .eventEmitter = descriptor->createEventEmitter(0, 3)});
descriptor->appendChild(node1, node2);
descriptor->appendChild(node1, node3);

ReactCommon/fabric/core/tests/PrimitivesTest.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,8 +7,8 @@
#include <exception>
-#include <fabric/core/Sealable.h>
#include <gtest/gtest.h>
+#include <react/core/Sealable.h>
using namespace facebook::react;
@@ -30,7 +30,8 @@
Sealable other2;
EXPECT_THROW(obj = other2, std::runtime_error);
- // It doesn't matter if the other object is also sealed, it's still not allowed.
+ // It doesn't matter if the other object is also sealed, it's still not
+ // allowed.
other2.seal();
EXPECT_THROW(obj = other2, std::runtime_error);

ReactCommon/fabric/core/tests/ShadowNodeTest.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,17 +7,16 @@
#include <memory>
-#include <fabric/core/ConcreteShadowNode.h>
-#include <fabric/core/ShadowNode.h>
#include <gtest/gtest.h>
+#include <react/core/ConcreteShadowNode.h>
+#include <react/core/ShadowNode.h>
#include "TestComponent.h"
using namespace facebook::react;
TEST(ShadowNodeTest, handleProps) {
- RawProps raw;
- raw["nativeID"] = "abc";
+ const auto &raw = RawProps(folly::dynamic::object("nativeID", "abc"));
auto props = std::make_shared<Props>(Props(), raw);
@@ -29,14 +28,12 @@
TEST(ShadowNodeTest, handleShadowNodeCreation) {
auto node = std::make_shared<TestShadowNode>(
- ShadowNodeFragment {
+ ShadowNodeFragment{
.tag = 9,
.rootTag = 1,
.props = std::make_shared<const TestProps>(),
- .children = ShadowNode::emptySharedShadowNodeSharedList()
- },
- nullptr
- );
+ .children = ShadowNode::emptySharedShadowNodeSharedList()},
+ nullptr);
ASSERT_FALSE(node->getSealed());
ASSERT_STREQ(node->getComponentName().c_str(), "Test");
@@ -54,15 +51,13 @@
TEST(ShadowNodeTest, handleShadowNodeSimpleCloning) {
auto node = std::make_shared<TestShadowNode>(
- ShadowNodeFragment {
+ ShadowNodeFragment{
.tag = 9,
.rootTag = 1,
.props = std::make_shared<const TestProps>(),
- .children = ShadowNode::emptySharedShadowNodeSharedList()
- },
- nullptr
- );
- auto node2 = std::make_shared<TestShadowNode>(*node, ShadowNodeFragment {});
+ .children = ShadowNode::emptySharedShadowNodeSharedList()},
+ nullptr);
+ auto node2 = std::make_shared<TestShadowNode>(*node, ShadowNodeFragment{});
ASSERT_STREQ(node->getComponentName().c_str(), "Test");
ASSERT_EQ(node->getTag(), 9);
@@ -72,9 +67,27 @@
TEST(ShadowNodeTest, handleShadowNodeMutation) {
auto props = std::make_shared<const TestProps>();
- auto node1 = std::make_shared<TestShadowNode>(ShadowNodeFragment {.tag = 1, .rootTag = 1, .props = std::make_shared<const TestProps>(), .children = ShadowNode::emptySharedShadowNodeSharedList()}, nullptr);
- auto node2 = std::make_shared<TestShadowNode>(ShadowNodeFragment {.tag = 2, .rootTag = 1, .props = std::make_shared<const TestProps>(), .children = ShadowNode::emptySharedShadowNodeSharedList()}, nullptr);
- auto node3 = std::make_shared<TestShadowNode>(ShadowNodeFragment {.tag = 3, .rootTag = 1, .props = std::make_shared<const TestProps>(), .children = ShadowNode::emptySharedShadowNodeSharedList()}, nullptr);
+ auto node1 = std::make_shared<TestShadowNode>(
+ ShadowNodeFragment{
+ .tag = 1,
+ .rootTag = 1,
+ .props = std::make_shared<const TestProps>(),
+ .children = ShadowNode::emptySharedShadowNodeSharedList()},
+ nullptr);
+ auto node2 = std::make_shared<TestShadowNode>(
+ ShadowNodeFragment{
+ .tag = 2,
+ .rootTag = 1,
+ .props = std::make_shared<const TestProps>(),
+ .children = ShadowNode::emptySharedShadowNodeSharedList()},
+ nullptr);
+ auto node3 = std::make_shared<TestShadowNode>(
+ ShadowNodeFragment{
+ .tag = 3,
+ .rootTag = 1,
+ .props = std::make_shared<const TestProps>(),
+ .children = ShadowNode::emptySharedShadowNodeSharedList()},
+ nullptr);
node1->appendChild(node2);
node1->appendChild(node3);
@@ -83,7 +96,7 @@
ASSERT_EQ(node1Children.at(0), node2);
ASSERT_EQ(node1Children.at(1), node3);
- auto node4 = std::make_shared<TestShadowNode>(*node2, ShadowNodeFragment {});
+ auto node4 = std::make_shared<TestShadowNode>(*node2, ShadowNodeFragment{});
node1->replaceChild(node2, node4);
node1Children = node1->getChildren();
ASSERT_EQ(node1Children.size(), 2);
@@ -99,31 +112,32 @@
// No more mutation after sealing.
EXPECT_THROW(node4->setLocalData(nullptr), std::runtime_error);
- auto node5 = std::make_shared<TestShadowNode>(*node4, ShadowNodeFragment {});
+ auto node5 = std::make_shared<TestShadowNode>(*node4, ShadowNodeFragment{});
node5->setLocalData(nullptr);
ASSERT_EQ(node5->getLocalData(), nullptr);
}
TEST(ShadowNodeTest, handleCloneFunction) {
- auto firstNode = std::make_shared<TestShadowNode>(ShadowNodeFragment {.tag = 9, .rootTag = 1, .props = std::make_shared<const TestProps>(), .children = ShadowNode::emptySharedShadowNodeSharedList()}, nullptr);
+ auto firstNode = std::make_shared<TestShadowNode>(
+ ShadowNodeFragment{
+ .tag = 9,
+ .rootTag = 1,
+ .props = std::make_shared<const TestProps>(),
+ .children = ShadowNode::emptySharedShadowNodeSharedList()},
+ nullptr);
// The shadow node is not clonable if `cloneFunction` is not provided,
ASSERT_DEATH_IF_SUPPORTED(firstNode->clone({}), "cloneFunction_");
auto secondNode = std::make_shared<TestShadowNode>(
- ShadowNodeFragment {
+ ShadowNodeFragment{
.tag = 9,
.rootTag = 1,
.props = std::make_shared<const TestProps>(),
- .children = ShadowNode::emptySharedShadowNodeSharedList()
- },
+ .children = ShadowNode::emptySharedShadowNodeSharedList()},
[](const ShadowNode &shadowNode, const ShadowNodeFragment &fragment) {
- return std::make_shared<TestShadowNode>(
- shadowNode,
- fragment
- );
- }
- );
+ return std::make_shared<TestShadowNode>(shadowNode, fragment);
+ });
auto secondNodeClone = secondNode->clone({});
@@ -131,7 +145,9 @@
ASSERT_NE(secondNode, secondNodeClone);
// `secondNodeClone` is an instance of `TestShadowNode`.
- ASSERT_NE(std::dynamic_pointer_cast<const TestShadowNode>(secondNodeClone), nullptr);
+ ASSERT_NE(
+ std::dynamic_pointer_cast<const TestShadowNode>(secondNodeClone),
+ nullptr);
// Both nodes have same content.
ASSERT_EQ(secondNode->getTag(), secondNodeClone->getTag());
@@ -149,21 +165,114 @@
auto localDataOver9000 = std::make_shared<TestLocalData>();
localDataOver9000->setNumber(9001);
auto props = std::make_shared<const TestProps>();
- auto firstNode = std::make_shared<TestShadowNode>(ShadowNodeFragment {.tag = 9, .rootTag = 1, .props = props, .children = ShadowNode::emptySharedShadowNodeSharedList()}, nullptr);
- auto secondNode = std::make_shared<TestShadowNode>(ShadowNodeFragment {.tag = 9, .rootTag = 1, .props = props, .children = ShadowNode::emptySharedShadowNodeSharedList()}, nullptr);
- auto thirdNode = std::make_shared<TestShadowNode>(ShadowNodeFragment {.tag = 9, .rootTag = 1, .props = props, .children = ShadowNode::emptySharedShadowNodeSharedList()}, nullptr);
+ auto firstNode = std::make_shared<TestShadowNode>(
+ ShadowNodeFragment{
+ .tag = 9,
+ .rootTag = 1,
+ .props = props,
+ .children = ShadowNode::emptySharedShadowNodeSharedList()},
+ nullptr);
+ auto secondNode = std::make_shared<TestShadowNode>(
+ ShadowNodeFragment{
+ .tag = 9,
+ .rootTag = 1,
+ .props = props,
+ .children = ShadowNode::emptySharedShadowNodeSharedList()},
+ nullptr);
+ auto thirdNode = std::make_shared<TestShadowNode>(
+ ShadowNodeFragment{
+ .tag = 9,
+ .rootTag = 1,
+ .props = props,
+ .children = ShadowNode::emptySharedShadowNodeSharedList()},
+ nullptr);
firstNode->setLocalData(localData42);
secondNode->setLocalData(localData42);
thirdNode->setLocalData(localDataOver9000);
// LocalData object are compared by pointer, not by value.
- ASSERT_EQ(*firstNode, *secondNode);
- ASSERT_NE(*firstNode, *thirdNode);
+ ASSERT_EQ(firstNode->getLocalData(), secondNode->getLocalData());
+ ASSERT_NE(firstNode->getLocalData(), thirdNode->getLocalData());
secondNode->setLocalData(anotherLocalData42);
- ASSERT_NE(*firstNode, *secondNode);
+ ASSERT_NE(firstNode->getLocalData(), secondNode->getLocalData());
// LocalData cannot be changed for sealed shadow node.
secondNode->sealRecursive();
ASSERT_ANY_THROW(secondNode->setLocalData(localDataOver9000));
}
+
+TEST(ShadowNodeTest, handleBacktracking) {
+ /*
+ * The structure:
+ * <A>
+ * <AA/>
+ * <AB>
+ * <ABA/>
+ * <ABB/>
+ * <ABC/>
+ * </AB>
+ * <AC/>
+ * </A>
+ */
+
+ auto props = std::make_shared<const TestProps>();
+
+ auto nodeAA = std::make_shared<TestShadowNode>(
+ ShadowNodeFragment{
+ .props = props,
+ .children = ShadowNode::emptySharedShadowNodeSharedList()},
+ nullptr);
+
+ auto nodeABA = std::make_shared<TestShadowNode>(
+ ShadowNodeFragment{
+ .props = props,
+ .children = ShadowNode::emptySharedShadowNodeSharedList()},
+ nullptr);
+ auto nodeABB = std::make_shared<TestShadowNode>(
+ ShadowNodeFragment{
+ .props = props,
+ .children = ShadowNode::emptySharedShadowNodeSharedList()},
+ nullptr);
+ auto nodeABC = std::make_shared<TestShadowNode>(
+ ShadowNodeFragment{
+ .props = props,
+ .children = ShadowNode::emptySharedShadowNodeSharedList()},
+ nullptr);
+
+ auto nodeABChildren = std::make_shared<std::vector<SharedShadowNode>>(
+ std::vector<SharedShadowNode>{nodeABA, nodeABB, nodeABC});
+ auto nodeAB = std::make_shared<TestShadowNode>(
+ ShadowNodeFragment{.props = props, .children = nodeABChildren}, nullptr);
+
+ auto nodeAC = std::make_shared<TestShadowNode>(
+ ShadowNodeFragment{
+ .props = props,
+ .children = ShadowNode::emptySharedShadowNodeSharedList()},
+ nullptr);
+
+ auto nodeAChildren = std::make_shared<std::vector<SharedShadowNode>>(
+ std::vector<SharedShadowNode>{nodeAA, nodeAB, nodeAC});
+ auto nodeA = std::make_shared<TestShadowNode>(
+ ShadowNodeFragment{.props = props, .children = nodeAChildren}, nullptr);
+
+ auto nodeZ = std::make_shared<TestShadowNode>(
+ ShadowNodeFragment{
+ .props = props,
+ .children = ShadowNode::emptySharedShadowNodeSharedList()},
+ nullptr);
+
+ std::vector<std::reference_wrapper<const ShadowNode>> ancestors = {};
+
+ // Negative case:
+ auto success = nodeZ->constructAncestorPath(*nodeA, ancestors);
+ ASSERT_FALSE(success);
+ ASSERT_EQ(ancestors.size(), 0);
+
+ // Positive case:
+ success = nodeABC->constructAncestorPath(*nodeA, ancestors);
+ ASSERT_TRUE(success);
+ ASSERT_EQ(ancestors.size(), 2);
+ ASSERT_EQ(&ancestors[0].get(), nodeAB.get());
+ ASSERT_EQ(&ancestors[1].get(), nodeA.get());
+}

ReactCommon/fabric/core/tests/TestComponent.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,21 +9,22 @@
#include <memory>
-#include <fabric/core/ConcreteComponentDescriptor.h>
-#include <fabric/core/ConcreteShadowNode.h>
-#include <fabric/core/LocalData.h>
-#include <fabric/core/ShadowNode.h>
#include <folly/dynamic.h>
+#include <react/core/ConcreteComponentDescriptor.h>
+#include <react/core/ConcreteShadowNode.h>
+#include <react/core/LocalData.h>
+#include <react/core/RawProps.h>
+#include <react/core/ShadowNode.h>
using namespace facebook::react;
/**
- * This defines a set of TestComponent classes: Props, ShadowNode, ComponentDescriptor.
- * To be used for testing purpose.
+ * This defines a set of TestComponent classes: Props, ShadowNode,
+ * ComponentDescriptor. To be used for testing purpose.
*/
-class TestLocalData: public LocalData {
-public:
+class TestLocalData : public LocalData {
+ public:
void setNumber(const int &number) {
number_ = number;
}
@@ -32,28 +33,29 @@
return number_;
}
-private:
- int number_ {0};
+ private:
+ int number_{0};
};
static const char TestComponentName[] = "Test";
class TestProps : public Props {
-public:
+ public:
using Props::Props;
- TestProps():
- Props(Props(), {{"nativeID", "testNativeID"}}) {}
+ TestProps()
+ : Props(Props(), RawProps(folly::dynamic::object("nativeID", "testNativeID"))) {}
};
using SharedTestProps = std::shared_ptr<const TestProps>;
class TestShadowNode;
using SharedTestShadowNode = std::shared_ptr<const TestShadowNode>;
class TestShadowNode : public ConcreteShadowNode<TestComponentName, TestProps> {
-public:
+ public:
using ConcreteShadowNode::ConcreteShadowNode;
};
-class TestComponentDescriptor: public ConcreteComponentDescriptor<TestShadowNode> {
-public:
+class TestComponentDescriptor
+ : public ConcreteComponentDescriptor<TestShadowNode> {
+ public:
using ConcreteComponentDescriptor::ConcreteComponentDescriptor;
};

ReactCommon/fabric/debug/BUCK

@@ -1,7 +1,5 @@
load(
- "//configurations/buck/apple:flag_defs.bzl",
- "OBJC_ARC_PREPROCESSOR_FLAGS",
- "get_application_ios_flags",
+ "@fbsource//tools/build_defs/apple:flag_defs.bzl",
"get_debug_preprocessor_flags",
)
load(
@@ -11,7 +9,6 @@
"fb_xplat_cxx_test",
"get_apple_compiler_flags",
"get_apple_inspector_flags",
- "react_native_xplat_target",
"rn_xplat_cxx_library",
"subdir_glob",
)
@@ -33,7 +30,7 @@
[
("", "*.h"),
],
- prefix = "fabric/debug",
+ prefix = "react/debug",
),
compiler_flags = [
"-fexceptions",
@@ -43,9 +40,6 @@
],
fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
- fbobjc_tests = [
- ":tests",
- ],
force_static = True,
macosx_tests_override = [],
platforms = (ANDROID, APPLE),
@@ -53,7 +47,7 @@
"-DLOG_TAG=\"ReactNative\"",
"-DWITH_FBSYSTRACE=1",
],
- tests = [],
+ tests = [":tests"],
visibility = ["PUBLIC"],
deps = [
"xplat//fbsystrace:fbsystrace",
@@ -74,7 +68,7 @@
"-Wall",
],
contacts = ["oncall+react_native@xmail.facebook.com"],
- platforms = APPLE,
+ platforms = (ANDROID, APPLE),
deps = [
"xplat//folly:molly",
"xplat//third-party/gmock:gtest",

ReactCommon/fabric/debug/DebugStringConvertible.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,7 +10,11 @@
namespace facebook {
namespace react {
-std::string DebugStringConvertible::getDebugChildrenDescription(DebugStringConvertibleOptions options, int depth) const {
+#if RN_DEBUG_STRING_CONVERTIBLE
+
+std::string DebugStringConvertible::getDebugChildrenDescription(
+ DebugStringConvertibleOptions options,
+ int depth) const {
if (depth >= options.maximumDepth) {
return "";
}
@@ -28,7 +32,9 @@
return childrenString;
}
-std::string DebugStringConvertible::getDebugPropsDescription(DebugStringConvertibleOptions options, int depth) const {
+std::string DebugStringConvertible::getDebugPropsDescription(
+ DebugStringConvertibleOptions options,
+ int depth) const {
if (depth >= options.maximumDepth) {
return "";
}
@@ -43,8 +49,10 @@
auto name = prop->getDebugName();
auto value = prop->getDebugValue();
auto children = prop->getDebugPropsDescription(options, depth + 1);
- auto valueAndChildren = value + (children.empty() ? "" : "(" + children + ")");
- propsString += " " + name + (valueAndChildren.empty() ? "" : "=" + valueAndChildren);
+ auto valueAndChildren =
+ value + (children.empty() ? "" : "(" + children + ")");
+ propsString +=
+ " " + name + (valueAndChildren.empty() ? "" : "=" + valueAndChildren);
}
if (!propsString.empty()) {
@@ -55,19 +63,23 @@
return propsString;
}
-std::string DebugStringConvertible::getDebugDescription(DebugStringConvertibleOptions options, int depth) const {
- std::string nameString = getDebugName();
- std::string valueString = getDebugValue();
- std::string childrenString = getDebugChildrenDescription(options, depth);
- std::string propsString = getDebugPropsDescription(options, depth);
+std::string DebugStringConvertible::getDebugDescription(
+ DebugStringConvertibleOptions options,
+ int depth) const {
+ auto nameString = getDebugName();
+ auto valueString = getDebugValue();
+ auto childrenString = getDebugChildrenDescription(options, depth);
+ auto propsString = getDebugPropsDescription(options, depth);
- std::string leading = options.format ? std::string(depth * 2, ' ') : "";
- std::string trailing = options.format ? "\n" : "";
+ auto leading = options.format ? std::string(depth * 2, ' ') : std::string{""};
+ auto trailing = options.format ? std::string{"\n"} : std::string{""};
return leading + "<" + nameString +
(valueString.empty() ? "" : "=" + valueString) +
(propsString.empty() ? "" : " " + propsString) +
- (childrenString.empty() ? "/>" + trailing : ">" + trailing + childrenString + leading + "</" + nameString + ">" + trailing);
+ (childrenString.empty() ? "/>" + trailing
+ : ">" + trailing + childrenString + leading +
+ "</" + nameString + ">" + trailing);
}
std::string DebugStringConvertible::getDebugName() const {
@@ -78,7 +90,8 @@
return "";
}
-SharedDebugStringConvertibleList DebugStringConvertible::getDebugChildren() const {
+SharedDebugStringConvertibleList DebugStringConvertible::getDebugChildren()
+ const {
return SharedDebugStringConvertibleList();
}
@@ -86,5 +99,7 @@
return SharedDebugStringConvertibleList();
}
+#endif
+
} // namespace react
} // namespace facebook

ReactCommon/fabric/debug/DebugStringConvertible.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,31 +7,38 @@
#pragma once
-#include <string>
+#include <climits>
#include <memory>
+#include <string>
#include <vector>
namespace facebook {
namespace react {
+#ifndef NDEBUG
+#define RN_DEBUG_STRING_CONVERTIBLE 1
+#endif
+
+#if RN_DEBUG_STRING_CONVERTIBLE
+
class DebugStringConvertible;
-using SharedDebugStringConvertible = std::shared_ptr<const DebugStringConvertible>;
-using SharedDebugStringConvertibleList = std::vector<SharedDebugStringConvertible>;
+using SharedDebugStringConvertible =
+ std::shared_ptr<const DebugStringConvertible>;
+using SharedDebugStringConvertibleList =
+ std::vector<SharedDebugStringConvertible>;
struct DebugStringConvertibleOptions {
- bool format {true};
- int maximumDepth {INT_MAX};
+ bool format{true};
+ int maximumDepth{INT_MAX};
};
// Abstract class describes conformance to DebugStringConvertible concept
// and implements basic recursive debug string assembly algorithm.
// Use this as a base class for providing a debugging textual representation
// of your class.
-// TODO (#26770211): Clear up the naming.
class DebugStringConvertible {
-
-public:
+ public:
virtual ~DebugStringConvertible() = default;
// Returns a name of the object.
@@ -55,13 +62,25 @@
// Returns a string which represents the object in a human-readable way.
// Default implementation returns a description of the subtree
// rooted at this node, represented in XML-like format.
- virtual std::string getDebugDescription(DebugStringConvertibleOptions options = {}, int depth = 0) const;
+ virtual std::string getDebugDescription(
+ DebugStringConvertibleOptions options = {},
+ int depth = 0) const;
// Do same as `getDebugDescription` but return only *children* and
// *properties* parts (which are used in `getDebugDescription`).
- virtual std::string getDebugPropsDescription(DebugStringConvertibleOptions options = {}, int depth = 0) const;
- virtual std::string getDebugChildrenDescription(DebugStringConvertibleOptions options = {}, int depth = 0) const;
+ virtual std::string getDebugPropsDescription(
+ DebugStringConvertibleOptions options = {},
+ int depth = 0) const;
+ virtual std::string getDebugChildrenDescription(
+ DebugStringConvertibleOptions options = {},
+ int depth = 0) const;
};
+#else
+
+class DebugStringConvertible {};
+
+#endif
+
} // namespace react
} // namespace facebook

ReactCommon/fabric/debug/DebugStringConvertibleItem.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,16 +10,14 @@
namespace facebook {
namespace react {
+#if RN_DEBUG_STRING_CONVERTIBLE
+
DebugStringConvertibleItem::DebugStringConvertibleItem(
const std::string &name,
const std::string &value,
const SharedDebugStringConvertibleList &props,
- const SharedDebugStringConvertibleList &children
-):
- name_(name),
- value_(value),
- props_(props),
- children_(children) {}
+ const SharedDebugStringConvertibleList &children)
+ : name_(name), value_(value), props_(props), children_(children) {}
std::string DebugStringConvertibleItem::getDebugName() const {
return name_;
@@ -29,13 +27,17 @@
return value_;
}
-SharedDebugStringConvertibleList DebugStringConvertibleItem::getDebugProps() const {
+SharedDebugStringConvertibleList DebugStringConvertibleItem::getDebugProps()
+ const {
return props_;
}
-SharedDebugStringConvertibleList DebugStringConvertibleItem::getDebugChildren() const {
+SharedDebugStringConvertibleList DebugStringConvertibleItem::getDebugChildren()
+ const {
return children_;
}
+#endif
+
} // namespace react
} // namespace facebook

ReactCommon/fabric/debug/DebugStringConvertibleItem.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,18 +9,18 @@
#include <string>
-#include <fabric/debug/DebugStringConvertible.h>
+#include <react/debug/DebugStringConvertible.h>
namespace facebook {
namespace react {
+#if RN_DEBUG_STRING_CONVERTIBLE
+
// Trivial implementation of `DebugStringConvertible` abstract class
// with a stored output; useful for assembling `DebugStringConvertible` values
// in custom implementations of `getDebugChildren` and `getDebugProps`.
-class DebugStringConvertibleItem:
- public DebugStringConvertible {
-
-public:
+class DebugStringConvertibleItem : public DebugStringConvertible {
+ public:
DebugStringConvertibleItem() = default;
DebugStringConvertibleItem(const DebugStringConvertibleItem &item) = default;
@@ -28,20 +28,21 @@
const std::string &name = "",
const std::string &value = "",
const SharedDebugStringConvertibleList &props = {},
- const SharedDebugStringConvertibleList &children = {}
- );
+ const SharedDebugStringConvertibleList &children = {});
std::string getDebugName() const override;
std::string getDebugValue() const override;
SharedDebugStringConvertibleList getDebugChildren() const override;
SharedDebugStringConvertibleList getDebugProps() const override;
-private:
+ private:
std::string name_;
std::string value_;
SharedDebugStringConvertibleList props_;
SharedDebugStringConvertibleList children_;
};
+#endif
+
} // namespace react
} // namespace facebook

ReactCommon/fabric/debug/debugStringConvertibleUtils.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,27 +7,40 @@
#pragma once
-#include <string>
#include <limits>
#include <memory>
+#include <string>
#include <vector>
-#include <fabric/debug/DebugStringConvertible.h>
-#include <fabric/debug/DebugStringConvertibleItem.h>
#include <folly/Conv.h>
#include <folly/Optional.h>
+#include <react/debug/DebugStringConvertible.h>
+#include <react/debug/DebugStringConvertibleItem.h>
namespace facebook {
namespace react {
-inline std::string toString(const std::string &value) { return value; }
-inline std::string toString(const int &value) { return folly::to<std::string>(value); }
-inline std::string toString(const bool &value) { return folly::to<std::string>(value); }
-inline std::string toString(const float &value) { return folly::to<std::string>(value); }
-inline std::string toString(const double &value) { return folly::to<std::string>(value); }
+#if RN_DEBUG_STRING_CONVERTIBLE
+
+inline std::string toString(const std::string &value) {
+ return value;
+}
+inline std::string toString(const int &value) {
+ return folly::to<std::string>(value);
+}
+inline std::string toString(const bool &value) {
+ return folly::to<std::string>(value);
+}
+inline std::string toString(const float &value) {
+ return folly::to<std::string>(value);
+}
+inline std::string toString(const double &value) {
+ return folly::to<std::string>(value);
+}
template <typename T>
-inline SharedDebugStringConvertible debugStringConvertibleItem(std::string name, T value, T defaultValue = {}) {
+inline SharedDebugStringConvertible
+debugStringConvertibleItem(std::string name, T value, T defaultValue = {}) {
if (value == defaultValue) {
return nullptr;
}
@@ -36,24 +49,36 @@
}
template <typename T>
-inline SharedDebugStringConvertible debugStringConvertibleItem(std::string name, folly::Optional<T> value, T defaultValue = {}) {
+inline SharedDebugStringConvertible debugStringConvertibleItem(
+ std::string name,
+ folly::Optional<T> value,
+ T defaultValue = {}) {
if (!value.hasValue()) {
return nullptr;
}
- return debugStringConvertibleItem(name, value.value_or(defaultValue), defaultValue);
+ return debugStringConvertibleItem(
+ name, value.value_or(defaultValue), defaultValue);
}
-inline SharedDebugStringConvertibleList operator+(const SharedDebugStringConvertibleList &lhs, const SharedDebugStringConvertibleList &rhs) {
- SharedDebugStringConvertibleList result = {};
+inline SharedDebugStringConvertibleList operator+(
+ const SharedDebugStringConvertibleList &lhs,
+ const SharedDebugStringConvertibleList &rhs) {
+ auto result = SharedDebugStringConvertibleList{};
std::move(lhs.begin(), lhs.end(), std::back_inserter(result));
std::move(rhs.begin(), rhs.end(), std::back_inserter(result));
return result;
}
-inline SharedDebugStringConvertible debugStringConvertibleItem(std::string name, DebugStringConvertible value, std::string defaultValue) {
- return debugStringConvertibleItem(name, value.getDebugDescription(), defaultValue);
+inline SharedDebugStringConvertible debugStringConvertibleItem(
+ std::string name,
+ DebugStringConvertible value,
+ std::string defaultValue) {
+ return debugStringConvertibleItem(
+ name, value.getDebugDescription(), defaultValue);
}
+#endif
+
} // namespace react
} // namespace facebook

ReactCommon/fabric/debug/SystraceSection.h

@@ -0,0 +1,49 @@
+// 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.
+
+#pragma once
+
+#ifdef WITH_FBSYSTRACE
+#include <fbsystrace.h>
+#endif
+
+namespace facebook {
+namespace react {
+
+/**
+ * This is a convenience class to avoid lots of verbose profiling
+ * #ifdefs. If WITH_FBSYSTRACE is not defined, the optimizer will
+ * remove this completely. If it is defined, it will behave as
+ * FbSystraceSection, with the right tag provided. Use two separate classes to
+ * to ensure that the ODR rule isn't violated, that is, if WITH_FBSYSTRACE has
+ * different values in different files, there is no inconsistency in the sizes
+ * of defined symbols.
+ */
+#ifdef WITH_FBSYSTRACE
+struct ConcreteSystraceSection {
+ public:
+ template <typename... ConvertsToStringPiece>
+ explicit ConcreteSystraceSection(
+ const char *name,
+ ConvertsToStringPiece &&... args)
+ : m_section(TRACE_TAG_REACT_CXX_BRIDGE, name, args...) {}
+
+ private:
+ fbsystrace::FbSystraceSection m_section;
+};
+using SystraceSection = ConcreteSystraceSection;
+#else
+struct DummySystraceSection {
+ public:
+ template <typename... ConvertsToStringPiece>
+ explicit DummySystraceSection(
+ const char *name,
+ ConvertsToStringPiece &&... args) {}
+};
+using SystraceSection = DummySystraceSection;
+#endif
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/debug/tests/DebugStringConvertibleTest.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,14 +7,15 @@
#include <memory>
-#include <fabric/debug/DebugStringConvertibleItem.h>
#include <gtest/gtest.h>
+#include <react/debug/DebugStringConvertibleItem.h>
using namespace facebook::react;
TEST(DebugStringConvertibleTest, handleSimpleNode) {
SharedDebugStringConvertibleList empty;
- auto item = std::make_shared<DebugStringConvertibleItem>("View", "hello", empty, empty);
+ auto item = std::make_shared<DebugStringConvertibleItem>(
+ "View", "hello", empty, empty);
ASSERT_STREQ(item->getDebugName().c_str(), "View");
ASSERT_STREQ(item->getDebugValue().c_str(), "hello");
@@ -24,9 +25,9 @@
TEST(DebugStringConvertibleTest, handleSimpleNodeWithProps) {
SharedDebugStringConvertibleList empty;
SharedDebugStringConvertibleList props = {
- std::make_shared<DebugStringConvertibleItem>("x", "1", empty, empty)
- };
- auto item = std::make_shared<DebugStringConvertibleItem>("View", "hello", props, empty);
+ std::make_shared<DebugStringConvertibleItem>("x", "1", empty, empty)};
+ auto item = std::make_shared<DebugStringConvertibleItem>(
+ "View", "hello", props, empty);
ASSERT_STREQ(item->getDebugName().c_str(), "View");
ASSERT_STREQ(item->getDebugValue().c_str(), "hello");
@@ -36,42 +37,48 @@
TEST(DebugStringConvertibleTest, handleSimpleNodeWithChildren) {
SharedDebugStringConvertibleList empty;
SharedDebugStringConvertibleList children = {
- std::make_shared<DebugStringConvertibleItem>("Child", "a", empty, empty)
- };
- auto item = std::make_shared<DebugStringConvertibleItem>("View", "hello", empty, children);
+ std::make_shared<DebugStringConvertibleItem>("Child", "a", empty, empty)};
+ auto item = std::make_shared<DebugStringConvertibleItem>(
+ "View", "hello", empty, children);
ASSERT_STREQ(item->getDebugName().c_str(), "View");
ASSERT_STREQ(item->getDebugValue().c_str(), "hello");
- ASSERT_STREQ(item->getDebugDescription().c_str(), "<View=hello>\n <Child=a/>\n</View>\n");
+ ASSERT_STREQ(
+ item->getDebugDescription().c_str(),
+ "<View=hello>\n <Child=a/>\n</View>\n");
}
TEST(DebugStringConvertibleTest, handleNestedNode) {
SharedDebugStringConvertibleList empty;
SharedDebugStringConvertibleList props = {
- std::make_shared<DebugStringConvertibleItem>("x", "1", empty, empty)
- };
+ std::make_shared<DebugStringConvertibleItem>("x", "1", empty, empty)};
SharedDebugStringConvertibleList children = {
- std::make_shared<DebugStringConvertibleItem>("Child", "a", props, empty)
- };
- auto item = std::make_shared<DebugStringConvertibleItem>("View", "hello", props, children);
+ std::make_shared<DebugStringConvertibleItem>("Child", "a", props, empty)};
+ auto item = std::make_shared<DebugStringConvertibleItem>(
+ "View", "hello", props, children);
ASSERT_STREQ(item->getDebugName().c_str(), "View");
ASSERT_STREQ(item->getDebugValue().c_str(), "hello");
- ASSERT_STREQ(item->getDebugDescription().c_str(), "<View=hello x=1>\n <Child=a x=1/>\n</View>\n");
+ ASSERT_STREQ(
+ item->getDebugDescription().c_str(),
+ "<View=hello x=1>\n <Child=a x=1/>\n</View>\n");
}
TEST(DebugStringConvertibleTest, handleNodeWithComplexProps) {
SharedDebugStringConvertibleList empty;
SharedDebugStringConvertibleList subProps = {
- std::make_shared<DebugStringConvertibleItem>("height", "100", empty, empty),
- std::make_shared<DebugStringConvertibleItem>("width", "200", empty, empty)
- };
+ std::make_shared<DebugStringConvertibleItem>(
+ "height", "100", empty, empty),
+ std::make_shared<DebugStringConvertibleItem>(
+ "width", "200", empty, empty)};
SharedDebugStringConvertibleList props = {
- std::make_shared<DebugStringConvertibleItem>("x", "1", subProps, empty)
- };
- auto item = std::make_shared<DebugStringConvertibleItem>("View", "hello", props, empty);
+ std::make_shared<DebugStringConvertibleItem>("x", "1", subProps, empty)};
+ auto item = std::make_shared<DebugStringConvertibleItem>(
+ "View", "hello", props, empty);
ASSERT_STREQ(item->getDebugName().c_str(), "View");
ASSERT_STREQ(item->getDebugValue().c_str(), "hello");
- ASSERT_STREQ(item->getDebugDescription().c_str(), "<View=hello x=1(height=100 width=200)/>\n");
+ ASSERT_STREQ(
+ item->getDebugDescription().c_str(),
+ "<View=hello x=1(height=100 width=200)/>\n");
}

ReactCommon/fabric/events/BatchedEventQueue.cpp

@@ -0,0 +1,19 @@
+/**
+ * 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.
+ */
+
+#include "BatchedEventQueue.h"
+
+namespace facebook {
+namespace react {
+
+void BatchedEventQueue::enqueueEvent(const RawEvent &rawEvent) const {
+ EventQueue::enqueueEvent(rawEvent);
+ eventBeat_->request();
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/events/BatchedEventQueue.h

@@ -0,0 +1,27 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <react/events/EventQueue.h>
+
+namespace facebook {
+namespace react {
+
+/*
+ * Event Queue that dispatches event in batches synchronizing them with
+ * an Event Beat.
+ */
+class BatchedEventQueue final : public EventQueue {
+ public:
+ using EventQueue::EventQueue;
+
+ void enqueueEvent(const RawEvent &rawEvent) const override;
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/events/BUCK

@@ -1,4 +1,4 @@
-load("//configurations/buck/apple:flag_defs.bzl", "OBJC_ARC_PREPROCESSOR_FLAGS", "get_application_ios_flags", "get_debug_preprocessor_flags")
+load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags")
load(
"//tools/build_defs/oss:rn_defs.bzl",
"ANDROID",
@@ -28,7 +28,7 @@
[
("", "*.h"),
],
- prefix = "fabric/events",
+ prefix = "react/events",
),
compiler_flags = [
"-fexceptions",
@@ -38,23 +38,23 @@
],
fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
- fbobjc_tests = [
- ":tests",
- ],
force_static = True,
macosx_tests_override = [],
platforms = (ANDROID, APPLE),
preprocessor_flags = [
"-DLOG_TAG=\"ReactNative\"",
- "-DWITH_FBSYSTRACE=1",
+ # Systraces are temporary disabled.
+ # "-DWITH_FBSYSTRACE=1",
],
- tests = [],
+ tests = [":tests"],
visibility = ["PUBLIC"],
deps = [
"xplat//fbsystrace:fbsystrace",
"xplat//folly:headers_only",
"xplat//folly:memory",
"xplat//folly:molly",
+ "xplat//jsi:JSIDynamic",
+ "xplat//jsi:jsi",
"xplat//third-party/glog:glog",
react_native_xplat_target("fabric/debug:debug"),
],
@@ -71,7 +71,7 @@
"-Wall",
],
contacts = ["oncall+react_native@xmail.facebook.com"],
- platforms = APPLE,
+ platforms = (ANDROID, APPLE),
deps = [
"xplat//folly:molly",
"xplat//third-party/gmock:gtest",

ReactCommon/fabric/events/EventBeatBasedExecutor.cpp

@@ -0,0 +1,80 @@
+/**
+ * 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.
+ */
+
+#include <cassert>
+
+#include "EventBeatBasedExecutor.h"
+
+#include <cassert>
+
+namespace facebook {
+namespace react {
+
+using Mode = EventBeatBasedExecutor::Mode;
+
+EventBeatBasedExecutor::EventBeatBasedExecutor(
+ std::unique_ptr<EventBeat> eventBeat)
+ : eventBeat_(std::move(eventBeat)) {
+ eventBeat_->setBeatCallback(
+ std::bind(&EventBeatBasedExecutor::onBeat, this, true));
+ eventBeat_->setFailCallback(
+ std::bind(&EventBeatBasedExecutor::onBeat, this, false));
+}
+
+void EventBeatBasedExecutor::operator()(Routine routine, Mode mode) const {
+ if (mode == Mode::Asynchronous) {
+ execute({.routine = std::move(routine)});
+ return;
+ }
+
+ std::mutex mutex;
+ mutex.lock();
+
+ execute({.routine = std::move(routine),
+ .callback = [&mutex]() { mutex.unlock(); }});
+
+ mutex.lock();
+}
+
+void EventBeatBasedExecutor::execute(Task task) const {
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+
+ tasks_.push_back(std::move(task));
+ }
+
+ eventBeat_->request();
+ eventBeat_->induce();
+}
+
+void EventBeatBasedExecutor::onBeat(bool success) const {
+ std::vector<Task> tasks;
+
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+
+ if (tasks_.size() == 0) {
+ return;
+ }
+
+ tasks = std::move(tasks_);
+ tasks_.clear();
+ }
+
+ for (const auto task : tasks) {
+ if (success) {
+ task.routine();
+ }
+
+ if (task.callback) {
+ task.callback();
+ }
+ }
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/events/EventBeatBasedExecutor.h

@@ -0,0 +1,53 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <mutex>
+#include <vector>
+
+#include <react/events/EventBeat.h>
+
+namespace facebook {
+namespace react {
+
+/*
+ * General purpose executor that uses EventBeat to ensure proper threading.
+ */
+class EventBeatBasedExecutor {
+ public:
+ using Routine = std::function<void()>;
+ using Callback = std::function<void()>;
+
+ struct Task {
+ Routine routine;
+ Callback callback;
+ };
+
+ enum class Mode { Synchronous, Asynchronous };
+
+ EventBeatBasedExecutor(std::unique_ptr<EventBeat> eventBeat);
+
+ /*
+ * Executes given routine with given mode.
+ */
+ void operator()(Routine routine, Mode mode = Mode::Asynchronous) const;
+
+ private:
+ void onBeat(bool success = true) const;
+ void execute(Task task) const;
+
+ std::unique_ptr<EventBeat> eventBeat_;
+ mutable std::vector<Task> tasks_; // Protected by `mutex_`.
+ mutable std::mutex mutex_;
+};
+
+using EventBeatFactory = std::function<std::unique_ptr<EventBeat>()>;
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/events/EventBeat.cpp

@@ -0,0 +1,42 @@
+/**
+ * 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.
+ */
+
+#include "EventBeat.h"
+
+namespace facebook {
+namespace react {
+
+void EventBeat::request() const {
+ isRequested_ = true;
+}
+
+void EventBeat::beat(jsi::Runtime &runtime) const {
+ if (!this->isRequested_) {
+ return;
+ }
+
+ isRequested_ = false;
+
+ if (beatCallback_) {
+ beatCallback_(runtime);
+ }
+}
+
+void EventBeat::induce() const {
+ // Default implementation does nothing.
+}
+
+void EventBeat::setBeatCallback(const BeatCallback &beatCallback) {
+ beatCallback_ = beatCallback;
+}
+
+void EventBeat::setFailCallback(const FailCallback &failCallback) {
+ failCallback_ = failCallback;
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/events/EventBeat.h

@@ -0,0 +1,76 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <jsi/jsi.h>
+#include <atomic>
+#include <functional>
+#include <memory>
+
+namespace facebook {
+namespace react {
+
+/*
+ * Event Beat serves two interleaving purposes: synchronization of event queues
+ * and ensuring that event dispatching happens on propper threads.
+ */
+class EventBeat {
+ public:
+ virtual ~EventBeat() = default;
+
+ using BeatCallback = std::function<void(jsi::Runtime &runtime)>;
+ using FailCallback = std::function<void()>;
+
+ /*
+ * Communicates to the Beat that a consumer is waiting for the coming beat.
+ * A consumer must request coming beat after the previous beat happened
+ * to receive a next coming one.
+ */
+ virtual void request() const;
+
+ /*
+ * Induces the next beat to happen as soon as possible. If the method
+ * is called on the proper thread, the beat must happen synchronously.
+ * Subclasses might override this method to implement specific
+ * out-of-turn beat scheduling.
+ * Some types of Event Beats do not support inducing, hence the default
+ * implementation does nothing.
+ * Receiver might ignore the call if a beat was not requested.
+ */
+ virtual void induce() const;
+
+ /*
+ * Sets the beat callback function.
+ * The callback is must be called on the proper thread.
+ */
+ void setBeatCallback(const BeatCallback &beatCallback);
+
+ /*
+ * Sets the fail callback function.
+ * Called in case if the beat cannot be performed anymore because of
+ * some external circumstances (e.g. execution thread is beling destructed).
+ * The callback can be called on any thread.
+ */
+ void setFailCallback(const FailCallback &failCallback);
+
+ /*
+ * Should be used by sublasses to send a beat.
+ * Receiver might ignore the call if a beat was not requested.
+ */
+ void beat(jsi::Runtime &runtime) const;
+
+ protected:
+ BeatCallback beatCallback_;
+ FailCallback failCallback_;
+ mutable std::atomic<bool> isRequested_{false};
+};
+
+using EventBeatFactory = std::function<std::unique_ptr<EventBeat>()>;
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/events/EventDispatcher.cpp

@@ -0,0 +1,62 @@
+/**
+ * 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.
+ */
+
+#include "EventDispatcher.h"
+
+#include "BatchedEventQueue.h"
+#include "UnbatchedEventQueue.h"
+
+#define REACT_FABRIC_SYNC_EVENT_DISPATCHING_DISABLED
+
+namespace facebook {
+namespace react {
+
+EventDispatcher::EventDispatcher(
+ const EventPipe &eventPipe,
+ const EventBeatFactory &synchonousEventBeatFactory,
+ const EventBeatFactory &asynchonousEventBeatFactory) {
+ // Synchronous/Unbatched
+ eventQueues_[(int)EventPriority::SynchronousUnbatched] =
+ std::make_unique<UnbatchedEventQueue>(
+ eventPipe, synchonousEventBeatFactory());
+
+ // Synchronous/Batched
+ eventQueues_[(int)EventPriority::SynchronousBatched] =
+ std::make_unique<BatchedEventQueue>(
+ eventPipe, synchonousEventBeatFactory());
+
+ // Asynchronous/Unbatched
+ eventQueues_[(int)EventPriority::AsynchronousUnbatched] =
+ std::make_unique<UnbatchedEventQueue>(
+ eventPipe, asynchonousEventBeatFactory());
+
+ // Asynchronous/Batched
+ eventQueues_[(int)EventPriority::AsynchronousBatched] =
+ std::make_unique<BatchedEventQueue>(
+ eventPipe, asynchonousEventBeatFactory());
+}
+
+void EventDispatcher::dispatchEvent(
+ const RawEvent &rawEvent,
+ EventPriority priority) const {
+#ifdef REACT_FABRIC_SYNC_EVENT_DISPATCHING_DISABLED
+ // Synchronous dispatch works, but JavaScript interop layer does not have
+ // proper synchonization yet and it crashes.
+ if (priority == EventPriority::SynchronousUnbatched) {
+ priority = EventPriority::AsynchronousUnbatched;
+ }
+
+ if (priority == EventPriority::SynchronousBatched) {
+ priority = EventPriority::AsynchronousBatched;
+ }
+#endif
+
+ eventQueues_[(int)priority]->enqueueEvent(rawEvent);
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/events/EventDispatcher.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -8,8 +8,10 @@
#include <memory>
-#include <fabric/events/primitives.h>
-#include <folly/dynamic.h>
+#include <react/events/EventBeat.h>
+#include <react/events/EventQueue.h>
+#include <react/events/RawEvent.h>
+#include <react/events/primitives.h>
namespace facebook {
namespace react {
@@ -15,30 +17,27 @@
namespace react {
class EventDispatcher;
-
using SharedEventDispatcher = std::shared_ptr<const EventDispatcher>;
+using WeakEventDispatcher = std::weak_ptr<const EventDispatcher>;
/*
- * Abstract class that represent event-delivery infrastructure.
- * Particular `EventEmitter` clases use an object of this class to invoke
- * events.
+ * Represents event-delivery infrastructure.
+ * Particular `EventEmitter` clases use this for sending events.
*/
class EventDispatcher {
-
-public:
+ public:
+ EventDispatcher(
+ const EventPipe &eventPipe,
+ const EventBeatFactory &synchonousEventBeatFactory,
+ const EventBeatFactory &asynchonousEventBeatFactory);
/*
- * Dispatches "raw" event using some event-delivery infrastructure.
+ * Dispatches a raw event with given priority using event-delivery pipe.
*/
- virtual void dispatchEvent(
- const EventTarget &eventTarget,
- const std::string &type,
- const folly::dynamic &payload,
- const EventPriority &priority
- ) const = 0;
-
- virtual void releaseEventTarget(const EventTarget &eventTarget) const = 0;
+ void dispatchEvent(const RawEvent &rawEvent, EventPriority priority) const;
+ private:
+ std::array<std::unique_ptr<EventQueue>, 4> eventQueues_;
};
} // namespace react

ReactCommon/fabric/events/EventEmitter.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -8,42 +8,96 @@
#include "EventEmitter.h"
#include <folly/dynamic.h>
+#include <jsi/JSIDynamic.h>
+#include <jsi/jsi.h>
+#include <react/debug/SystraceSection.h>
+
+#include "RawEvent.h"
namespace facebook {
namespace react {
-EventEmitter::EventEmitter(const EventTarget &eventTarget, const Tag &tag, const SharedEventDispatcher &eventDispatcher):
- eventTarget_(eventTarget),
- tag_(tag),
- eventDispatcher_(eventDispatcher) {
+// TODO(T29874519): Get rid of "top" prefix once and for all.
+/*
+ * Capitalizes the first letter of the event type and adds "top" prefix if
+ * necessary (e.g. "layout" becames "topLayout").
+ */
+static std::string normalizeEventType(const std::string &type) {
+ auto prefixedType = type;
+ if (type.find("top", 0) != 0) {
+ prefixedType.insert(0, "top");
+ prefixedType[3] = toupper(prefixedType[3]);
+ }
+ return prefixedType;
}
-EventEmitter::~EventEmitter() {
- auto &&eventDispatcher = eventDispatcher_.lock();
- if (eventDispatcher && eventTarget_) {
- eventDispatcher->releaseEventTarget(eventTarget_);
- }
+std::mutex &EventEmitter::DispatchMutex() {
+ static std::mutex mutex;
+ return mutex;
}
+ValueFactory EventEmitter::defaultPayloadFactory() {
+ static auto payloadFactory =
+ ValueFactory{[](jsi::Runtime &runtime) { return jsi::Object(runtime); }};
+ return payloadFactory;
+}
+
+EventEmitter::EventEmitter(
+ SharedEventTarget eventTarget,
+ Tag tag,
+ WeakEventDispatcher eventDispatcher)
+ : eventTarget_(std::move(eventTarget)),
+ eventDispatcher_(std::move(eventDispatcher)) {}
+
void EventEmitter::dispatchEvent(
const std::string &type,
const folly::dynamic &payload,
- const EventPriority &priority
-) const {
- const auto &eventDispatcher = eventDispatcher_.lock();
+ const EventPriority &priority) const {
+ dispatchEvent(
+ type,
+ [payload](jsi::Runtime &runtime) {
+ return valueFromDynamic(runtime, payload);
+ },
+ priority);
+}
+
+void EventEmitter::dispatchEvent(
+ const std::string &type,
+ const ValueFactory &payloadFactory,
+ const EventPriority &priority) const {
+ SystraceSection s("EventEmitter::dispatchEvent");
+
+ auto eventDispatcher = eventDispatcher_.lock();
if (!eventDispatcher) {
return;
}
- assert(eventTarget_ && "Attempted to dispatch an event without an eventTarget.");
+ eventDispatcher->dispatchEvent(
+ RawEvent(normalizeEventType(type), payloadFactory, eventTarget_),
+ priority);
+}
- // Mixing `target` into `payload`.
- assert(payload.isObject());
- folly::dynamic extendedPayload = folly::dynamic::object("target", tag_);
- extendedPayload.merge_patch(payload);
+void EventEmitter::setEnabled(bool enabled) const {
+ enableCounter_ += enabled ? 1 : -1;
- // TODO(T29610783): Reconsider using dynamic dispatch here.
- eventDispatcher->dispatchEvent(eventTarget_, type, extendedPayload, priority);
+ bool shouldBeEnabled = enableCounter_ > 0;
+ if (isEnabled_ != shouldBeEnabled) {
+ isEnabled_ = shouldBeEnabled;
+ if (eventTarget_) {
+ eventTarget_->setEnabled(isEnabled_);
+ }
+ }
+
+ // Note: Initially, the state of `eventTarget_` and the value `enableCounter_`
+ // is mismatched intentionally (it's `non-null` and `0` accordingly). We need
+ // this to support an initial nebula state where the event target must be
+ // retained without any associated mounted node.
+ bool shouldBeRetained = enableCounter_ > 0;
+ if (shouldBeRetained != (eventTarget_ != nullptr)) {
+ if (!shouldBeRetained) {
+ eventTarget_.reset();
+ }
+ }
}
} // namespace react

ReactCommon/fabric/events/EventEmitter.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,8 +10,8 @@
#include <mutex>
#include <folly/dynamic.h>
-#include <fabric/events/EventDispatcher.h>
-#include <fabric/events/primitives.h>
+#include <react/events/EventDispatcher.h>
+#include <react/events/primitives.h>
namespace facebook {
namespace react {
@@ -22,24 +22,47 @@
/*
* Base class for all particular typed event handlers.
- * Stores `InstanceHandle` identifying a particular component and the pointer
- * to `EventDispatcher` which is responsible for delivering the event.
- *
- * TODO: Reconsider naming of all event-related things.
+ * Stores a pointer to `EventTarget` identifying a particular component and
+ * a weak pointer to `EventDispatcher` which is responsible for delivering the
+ * event.
*/
class EventEmitter {
-
/*
* We have to repeat `Tag` type definition here because `events` module does
* not depend on `core` module (and should not).
*/
using Tag = int32_t;
-public:
- EventEmitter(const EventTarget &eventTarget, const Tag &tag, const SharedEventDispatcher &eventDispatcher);
- virtual ~EventEmitter();
+ public:
+ static std::mutex &DispatchMutex();
+
+ static ValueFactory defaultPayloadFactory();
+
+ EventEmitter(
+ SharedEventTarget eventTarget,
+ Tag tag,
+ WeakEventDispatcher eventDispatcher);
-protected:
+ virtual ~EventEmitter() = default;
+
+ /*
+ * Enables/disables event emitter.
+ * Enabled event emitter retains a pointer to `eventTarget` strongly (as
+ * `std::shared_ptr`) whereas disabled one don't.
+ * Enabled/disabled state is also proxied to `eventTarget` where it indicates
+ * a possibility to extract JSI value from it.
+ * The enable state is additive; a number of `enable` calls should be equal to
+ * a number of `disable` calls to release the event target.
+ * `DispatchMutex` must be acquired before calling.
+ */
+ void setEnabled(bool enabled) const;
+
+ protected:
+#ifdef ANDROID
+ // We need this temporarily due to lack of Java-counterparts for particular
+ // subclasses.
+ public:
+#endif
/*
* Initates an event delivery process.
@@ -47,15 +70,22 @@
*/
void dispatchEvent(
const std::string &type,
- const folly::dynamic &payload = folly::dynamic::object(),
- const EventPriority &priority = EventPriority::AsynchronousBatched
- ) const;
-
-private:
-
- mutable EventTarget eventTarget_ {nullptr};
- Tag tag_;
- std::weak_ptr<const EventDispatcher> eventDispatcher_;
+ const ValueFactory &payloadFactory =
+ EventEmitter::defaultPayloadFactory(),
+ const EventPriority &priority = EventPriority::AsynchronousBatched) const;
+
+ void dispatchEvent(
+ const std::string &type,
+ const folly::dynamic &payload,
+ const EventPriority &priority = EventPriority::AsynchronousBatched) const;
+
+ private:
+ void toggleEventTargetOwnership_() const;
+
+ mutable SharedEventTarget eventTarget_;
+ WeakEventDispatcher eventDispatcher_;
+ mutable int enableCounter_{0};
+ mutable bool isEnabled_{false};
};
} // namespace react

ReactCommon/fabric/events/EventQueue.cpp

@@ -0,0 +1,69 @@
+/**
+ * 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.
+ */
+
+#include "EventQueue.h"
+
+#include "EventEmitter.h"
+
+namespace facebook {
+namespace react {
+
+EventQueue::EventQueue(
+ EventPipe eventPipe,
+ std::unique_ptr<EventBeat> eventBeat)
+ : eventPipe_(std::move(eventPipe)), eventBeat_(std::move(eventBeat)) {
+ eventBeat_->setBeatCallback(
+ std::bind(&EventQueue::onBeat, this, std::placeholders::_1));
+}
+
+void EventQueue::enqueueEvent(const RawEvent &rawEvent) const {
+ std::lock_guard<std::mutex> lock(queueMutex_);
+ queue_.push_back(rawEvent);
+}
+
+void EventQueue::onBeat(jsi::Runtime &runtime) const {
+ std::vector<RawEvent> queue;
+
+ {
+ std::lock_guard<std::mutex> lock(queueMutex_);
+
+ if (queue_.size() == 0) {
+ return;
+ }
+
+ queue = std::move(queue_);
+ queue_.clear();
+ }
+
+ {
+ std::lock_guard<std::mutex> lock(EventEmitter::DispatchMutex());
+
+ for (const auto &event : queue) {
+ if (event.eventTarget) {
+ event.eventTarget->retain(runtime);
+ }
+ }
+ }
+
+ for (const auto &event : queue) {
+ eventPipe_(
+ runtime, event.eventTarget.get(), event.type, event.payloadFactory);
+ }
+
+ // No need to lock `EventEmitter::DispatchMutex()` here.
+ // The mutex protects from a situation when the `instanceHandle` can be
+ // deallocated during accessing, but that's impossible at this point because
+ // we have a strong pointer to it.
+ for (const auto &event : queue) {
+ if (event.eventTarget) {
+ event.eventTarget->release(runtime);
+ }
+ }
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/events/EventQueue.h

@@ -0,0 +1,48 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <mutex>
+#include <vector>
+
+#include <jsi/jsi.h>
+#include <react/events/EventBeat.h>
+#include <react/events/RawEvent.h>
+#include <react/events/primitives.h>
+
+namespace facebook {
+namespace react {
+
+/*
+ * Event Queue synchronized with given Event Beat and dispatching event
+ * using given Event Pipe.
+ */
+class EventQueue {
+ public:
+ EventQueue(EventPipe eventPipe, std::unique_ptr<EventBeat> eventBeat);
+ virtual ~EventQueue() = default;
+
+ /*
+ * Enqueues and (probably later) dispatch a given event.
+ * Can be called on any thread.
+ */
+ virtual void enqueueEvent(const RawEvent &rawEvent) const;
+
+ protected:
+ void onBeat(jsi::Runtime &runtime) const;
+
+ const EventPipe eventPipe_;
+ const std::unique_ptr<EventBeat> eventBeat_;
+ // Thread-safe, protected by `queueMutex_`.
+ mutable std::vector<RawEvent> queue_;
+ mutable std::mutex queueMutex_;
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/events/EventTarget.cpp

@@ -0,0 +1,66 @@
+/**
+ * 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.
+ */
+
+#include "EventTarget.h"
+
+namespace facebook {
+namespace react {
+
+using Tag = EventTarget::Tag;
+
+EventTarget::EventTarget(
+ jsi::Runtime &runtime,
+ const jsi::Value &instanceHandle,
+ Tag tag)
+ : weakInstanceHandle_(
+ jsi::WeakObject(runtime, instanceHandle.asObject(runtime))),
+ strongInstanceHandle_(jsi::Value::null()),
+ tag_(tag) {}
+
+void EventTarget::setEnabled(bool enabled) const {
+ enabled_ = enabled;
+}
+
+void EventTarget::retain(jsi::Runtime &runtime) const {
+ if (!enabled_) {
+ return;
+ }
+
+ strongInstanceHandle_ = weakInstanceHandle_.lock(runtime);
+
+ // Having a `null` or `undefined` object here indicates that
+ // `weakInstanceHandle_` was already deallocated. This should *not* happen by
+ // design, and if it happens it's a severe problem. This basically means that
+ // particular implementation of JSI was able to detect this inconsistency and
+ // dealt with it, but some JSI implementation may not support this feature and
+ // that case will lead to a crash in those environments.
+ assert(!strongInstanceHandle_.isNull());
+ assert(!strongInstanceHandle_.isUndefined());
+}
+
+void EventTarget::release(jsi::Runtime &runtime) const {
+ // The method does not use `jsi::Runtime` reference.
+ // It takes it only to ensure thread-safety (if the caller has the reference,
+ // we are on a proper thread).
+ strongInstanceHandle_ = jsi::Value::null();
+}
+
+jsi::Value EventTarget::getInstanceHandle(jsi::Runtime &runtime) const {
+ if (strongInstanceHandle_.isNull()) {
+ // The `instanceHandle` is not retained.
+ return jsi::Value::null();
+ }
+
+ return jsi::Value(runtime, strongInstanceHandle_);
+}
+
+Tag EventTarget::getTag() const {
+ return tag_;
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/events/EventTarget.h

@@ -0,0 +1,77 @@
+/**
+ * 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.
+ */
+#pragma once
+
+#include <memory>
+
+#include <jsi/jsi.h>
+
+namespace facebook {
+namespace react {
+
+/*
+ * `EventTarget` represents storage of a weak instance handle object with some
+ * information about the possibility of retaining that strongly on demand.
+ * Note: Retaining an `EventTarget` does *not* guarantee that actual event
+ * target (a JavaScript object) is retaining and/or valid in JavaScript realm.
+ * The `EventTarget` retains an `instanceHandle` value in `unsafe-unretained`
+ * manner.
+ * All `EventTarget` instances must be deallocated before
+ * stopping JavaScript machine.
+ */
+class EventTarget {
+ public:
+ /*
+ * We have to repeat `Tag` type definition here because `events` module does
+ * not depend on `core` module (and should not).
+ */
+ using Tag = int32_t;
+
+ /*
+ * Constructs an EventTarget from a weak instance handler and a tag.
+ */
+ EventTarget(jsi::Runtime &runtime, const jsi::Value &instanceHandle, Tag tag);
+
+ /*
+ * Sets the `enabled` flag that allows creating a strong instance handle from
+ * a weak one.
+ */
+ void setEnabled(bool enabled) const;
+
+ /*
+ * Retains an instance handler by creating a strong reference to it.
+ * If the EventTarget is disabled, does nothing.
+ */
+ void retain(jsi::Runtime &runtime) const;
+
+ /*
+ * Releases the instance handler by nulling a strong reference to it.
+ */
+ void release(jsi::Runtime &runtime) const;
+
+ /*
+ * Creates and returns the `instanceHandle`.
+ * Returns `null` if the `instanceHandle` is not retained at this moment.
+ */
+ jsi::Value getInstanceHandle(jsi::Runtime &runtime) const;
+
+ /*
+ * Deprecated. Do not use.
+ */
+ Tag getTag() const;
+
+ private:
+ mutable bool enabled_{false}; // Protected by `EventEmitter::DispatchMutex()`.
+ mutable jsi::WeakObject weakInstanceHandle_; // Protected by `jsi::Runtime &`.
+ mutable jsi::Value strongInstanceHandle_; // Protected by `jsi::Runtime &`.
+ Tag tag_;
+};
+
+using SharedEventTarget = std::shared_ptr<const EventTarget>;
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/events/primitives.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,10 +7,15 @@
#pragma once
+#include <folly/dynamic.h>
+#include <jsi/jsi.h>
+
+#include <react/events/EventTarget.h>
+
namespace facebook {
namespace react {
-enum class EventPriority {
+enum class EventPriority : int {
SynchronousUnbatched,
SynchronousBatched,
AsynchronousUnbatched,
@@ -19,18 +24,30 @@
Sync = SynchronousUnbatched,
Work = SynchronousBatched,
Interactive = AsynchronousUnbatched,
- Deferred = AsynchronousBatched,
+ Deferred = AsynchronousBatched
};
-/* `InstanceHandler`, `EventTarget`, and `EventHandler` are all opaque
- * raw pointers. We use `struct {} *` trick to differentiate them in compiler's
- * eyes to ensure type safety.
- * These structs must have names (and the names must be exported)
- * to allow consistent template (e.g. `std::function`) instantiating
- * across different modules.
+/*
+ * We need this types only to ensure type-safety when we deal with them.
+ * Conceptually, they are opaque pointers to some types that derived from those
+ * classes.
+ *
+ * `EventHandler` is managed as a `unique_ptr`, so it must have a *virtual*
+ * destructor to allow proper deallocation having only a pointer
+ * to the base (`EventHandler`) class.
*/
-using EventTarget = struct EventTargetDummyStruct {} *;
-using EventHandler = struct EventHandlerDummyStruct {} *;
+struct EventHandler {
+ virtual ~EventHandler() = default;
+};
+using UniqueEventHandler = std::unique_ptr<const EventHandler>;
+
+using ValueFactory = std::function<jsi::Value(jsi::Runtime &runtime)>;
+
+using EventPipe = std::function<void(
+ jsi::Runtime &runtime,
+ const EventTarget *eventTarget,
+ const std::string &type,
+ const ValueFactory &payloadFactory)>;
} // namespace react
} // namespace facebook

ReactCommon/fabric/events/RawEvent.cpp

@@ -0,0 +1,22 @@
+/**
+ * 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.
+ */
+
+#include "RawEvent.h"
+
+namespace facebook {
+namespace react {
+
+RawEvent::RawEvent(
+ std::string type,
+ ValueFactory payloadFactory,
+ SharedEventTarget eventTarget)
+ : type(std::move(type)),
+ payloadFactory(std::move(payloadFactory)),
+ eventTarget(std::move(eventTarget)) {}
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/events/RawEvent.h

@@ -0,0 +1,34 @@
+/**
+ * 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.
+ */
+#pragma once
+
+#include <memory>
+
+#include <folly/dynamic.h>
+#include <jsi/jsi.h>
+#include <react/events/primitives.h>
+
+namespace facebook {
+namespace react {
+
+/*
+ * Represents ready-to-dispatch event object.
+ */
+class RawEvent {
+ public:
+ RawEvent(
+ std::string type,
+ ValueFactory payloadFactory,
+ SharedEventTarget eventTarget);
+
+ const std::string type;
+ const ValueFactory payloadFactory;
+ const SharedEventTarget eventTarget;
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/events/tests/EventsTest.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactCommon/fabric/events/UnbatchedEventQueue.cpp

@@ -0,0 +1,21 @@
+/**
+ * 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.
+ */
+
+#include "UnbatchedEventQueue.h"
+
+namespace facebook {
+namespace react {
+
+void UnbatchedEventQueue::enqueueEvent(const RawEvent &rawEvent) const {
+ EventQueue::enqueueEvent(rawEvent);
+
+ eventBeat_->request();
+ eventBeat_->induce();
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/events/UnbatchedEventQueue.h

@@ -0,0 +1,27 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <react/events/EventQueue.h>
+
+namespace facebook {
+namespace react {
+
+/*
+ * Event Queue that dispatches events as granular as possible without waiting
+ * for the next beat.
+ */
+class UnbatchedEventQueue final : public EventQueue {
+ public:
+ using EventQueue::EventQueue;
+
+ void enqueueEvent(const RawEvent &rawEvent) const override;
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/graphics/BUCK

@@ -1,4 +1,4 @@
-load("//configurations/buck/apple:flag_defs.bzl", "OBJC_ARC_PREPROCESSOR_FLAGS", "get_application_ios_flags", "get_debug_preprocessor_flags")
+load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags")
load(
"//tools/build_defs/oss:rn_defs.bzl",
"ANDROID",
@@ -6,7 +6,6 @@
"fb_xplat_cxx_test",
"get_apple_compiler_flags",
"get_apple_inspector_flags",
- "react_native_xplat_target",
"rn_xplat_cxx_library",
"subdir_glob",
)
@@ -31,7 +30,7 @@
[
("", "*.h"),
],
- prefix = "fabric/graphics",
+ prefix = "react/graphics",
),
compiler_flags = [
"-fexceptions",
@@ -43,7 +42,7 @@
[
("platform/android", "**/*.h"),
],
- prefix = "fabric/graphics",
+ prefix = "react/graphics",
),
fbandroid_srcs = glob(
[
@@ -52,9 +51,6 @@
),
fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
- fbobjc_tests = [
- ":tests",
- ],
force_static = True,
ios_deps = [
"xplat//js:RCTImage",
@@ -64,7 +60,7 @@
[
("platform/ios", "*.h"),
],
- prefix = "fabric/graphics",
+ prefix = "react/graphics",
),
ios_frameworks = [
"$SDKROOT/System/Library/Frameworks/CoreGraphics.framework",
@@ -83,7 +79,7 @@
"-DLOG_TAG=\"ReactNative\"",
"-DWITH_FBSYSTRACE=1",
],
- tests = [],
+ tests = [":tests"],
visibility = ["PUBLIC"],
deps = [
"xplat//fbsystrace:fbsystrace",
@@ -105,7 +101,7 @@
"-Wall",
],
contacts = ["oncall+react_native@xmail.facebook.com"],
- platforms = APPLE,
+ platforms = (ANDROID, APPLE),
deps = [
"xplat//folly:molly",
"xplat//third-party/gmock:gtest",

ReactCommon/fabric/graphics/ColorComponents.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,10 +11,10 @@
namespace react {
struct ColorComponents {
- float red {0};
- float green {0};
- float blue {0};
- float alpha {0};
+ float red{0};
+ float green{0};
+ float blue{0};
+ float alpha{0};
};
} // namespace react

ReactCommon/fabric/graphics/conversions.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -8,34 +8,36 @@
#pragma once
#include <folly/dynamic.h>
-#include <fabric/graphics/Color.h>
-#include <fabric/graphics/Geometry.h>
+#include <react/core/RawProps.h>
+#include <react/graphics/Color.h>
+#include <react/graphics/Geometry.h>
namespace facebook {
namespace react {
#pragma mark - Color
-inline void fromDynamic(const folly::dynamic &value, SharedColor &result) {
+inline void fromRawValue(const RawValue &value, SharedColor &result) {
float red;
float green;
float blue;
float alpha;
- if (value.isNumber()) {
- auto argb = value.asInt();
- float ratio = 256;
+ if (value.hasType<int>()) {
+ auto argb = (int64_t)value;
+ auto ratio = 256.f;
alpha = ((argb >> 24) & 0xFF) / ratio;
red = ((argb >> 16) & 0xFF) / ratio;
green = ((argb >> 8) & 0xFF) / ratio;
blue = (argb & 0xFF) / ratio;
- } else if (value.isArray()) {
- auto size = value.size();
- assert(size == 3 || size == 4);
- red = value[0].asDouble();
- green = value[1].asDouble();
- blue = value[2].asDouble();
- alpha = size == 4 ? value[3].asDouble() : 1.0;
+ } else if (value.hasType<std::vector<float>>()) {
+ auto items = (std::vector<float>)value;
+ auto length = items.size();
+ assert(length == 3 || length == 4);
+ red = items.at(0);
+ green = items.at(1);
+ blue = items.at(2);
+ alpha = length == 4 ? items.at(3) : 1.0;
} else {
abort();
}
@@ -39,106 +41,123 @@
} else {
abort();
}
-
result = colorFromComponents({red, green, blue, alpha});
}
+#ifdef ANDROID
+
+inline folly::dynamic toDynamic(const SharedColor &color) {
+ ColorComponents components = colorComponentsFromColor(color);
+ auto ratio = 256.f;
+ return (
+ ((int)(components.alpha * ratio) & 0xff) << 24 |
+ ((int)(components.red * ratio) & 0xff) << 16 |
+ ((int)(components.green * ratio) & 0xff) << 8 |
+ ((int)(components.blue * ratio) & 0xff));
+}
+
+#endif
+
inline std::string toString(const SharedColor &value) {
ColorComponents components = colorComponentsFromColor(value);
- const float ratio = 256;
- return "rgba(" +
- folly::to<std::string>(round(components.red * ratio)) + ", " +
- folly::to<std::string>(round(components.green * ratio)) + ", " +
+ auto ratio = 256.f;
+ return "rgba(" + folly::to<std::string>(round(components.red * ratio)) +
+ ", " + folly::to<std::string>(round(components.green * ratio)) + ", " +
folly::to<std::string>(round(components.blue * ratio)) + ", " +
folly::to<std::string>(round(components.alpha * ratio)) + ")";
}
#pragma mark - Geometry
-inline void fromDynamic(const folly::dynamic &value, Point &result) {
- if (value.isObject()) {
- result = Point {(Float)value["x"].asDouble(), (Float)value["y"].asDouble()};
+inline void fromRawValue(const RawValue &value, Point &result) {
+ if (value.hasType<std::unordered_map<std::string, Float>>()) {
+ auto map = (std::unordered_map<std::string, Float>)value;
+ result = {map.at("x"), map.at("y")};
return;
}
- if (value.isArray()) {
- result = Point {(Float)value[0].asDouble(), (Float)value[1].asDouble()};
+
+ if (value.hasType<std::vector<Float>>()) {
+ auto array = (std::vector<Float>)value;
+ assert(array.size() == 2);
+ result = {array.at(0), array.at(1)};
return;
}
+
abort();
}
-inline void fromDynamic(const folly::dynamic &value, Size &result) {
- if (value.isObject()) {
- result = Size {(Float)value["width"].asDouble(), (Float)value["height"].asDouble()};
+inline void fromRawValue(const RawValue &value, Size &result) {
+ if (value.hasType<std::unordered_map<std::string, Float>>()) {
+ auto map = (std::unordered_map<std::string, Float>)value;
+ result = {map.at("width"), map.at("height")};
return;
}
- if (value.isArray()) {
- result = Size {(Float)value[0].asDouble(), (Float)value[1].asDouble()};
+
+ if (value.hasType<std::vector<Float>>()) {
+ auto array = (std::vector<Float>)value;
+ assert(array.size() == 2);
+ result = {array.at(0), array.at(1)};
return;
}
+
abort();
}
-inline void fromDynamic(const folly::dynamic &value, EdgeInsets &result) {
- if (value.isNumber()) {
- const Float number = value.asDouble();
- result = EdgeInsets {number, number, number, number};
- return;
- }
- if (value.isObject()) {
- result = EdgeInsets {
- (Float)value["top"].asDouble(),
- (Float)value["left"].asDouble(),
- (Float)value["bottom"].asDouble(),
- (Float)value["right"].asDouble()
- };
- return;
- }
- if (value.isArray()) {
- result = EdgeInsets {
- (Float)value[0].asDouble(),
- (Float)value[1].asDouble(),
- (Float)value[2].asDouble(),
- (Float)value[3].asDouble()
- };
+inline void fromRawValue(const RawValue &value, EdgeInsets &result) {
+ if (value.hasType<Float>()) {
+ auto number = (Float)value;
+ result = {number, number, number, number};
+ }
+
+ if (value.hasType<std::unordered_map<std::string, Float>>()) {
+ auto map = (std::unordered_map<std::string, Float>)value;
+ result = {map.at("top"), map.at("left"), map.at("bottom"), map.at("right")};
return;
}
+
+ if (value.hasType<std::vector<Float>>()) {
+ auto array = (std::vector<Float>)value;
+ assert(array.size() == 4);
+ result = {array.at(0), array.at(1), array.at(2), array.at(3)};
+ return;
+ }
+
abort();
}
-inline void fromDynamic(const folly::dynamic &value, CornerInsets &result) {
- if (value.isNumber()) {
- const Float number = value.asDouble();
- result = CornerInsets {number, number, number, number};
- return;
- }
- if (value.isObject()) {
- result = CornerInsets {
- (Float)value["topLeft"].asDouble(),
- (Float)value["topRight"].asDouble(),
- (Float)value["bottomLeft"].asDouble(),
- (Float)value["bottomRight"].asDouble()
- };
- return;
- }
- if (value.isArray()) {
- result = CornerInsets {
- (Float)value[0].asDouble(),
- (Float)value[1].asDouble(),
- (Float)value[2].asDouble(),
- (Float)value[3].asDouble()
- };
+inline void fromRawValue(const RawValue &value, CornerInsets &result) {
+ if (value.hasType<Float>()) {
+ auto number = (Float)value;
+ result = {number, number, number, number};
+ }
+
+ if (value.hasType<std::unordered_map<std::string, Float>>()) {
+ auto map = (std::unordered_map<std::string, Float>)value;
+ result = {map.at("topLeft"),
+ map.at("topRight"),
+ map.at("bottomLeft"),
+ map.at("bottomRight")};
return;
}
+
+ if (value.hasType<std::vector<Float>>()) {
+ auto array = (std::vector<Float>)value;
+ assert(array.size() == 4);
+ result = {array.at(0), array.at(1), array.at(2), array.at(3)};
+ return;
+ }
+
abort();
}
inline std::string toString(const Point &point) {
- return "{" + folly::to<std::string>(point.x) + ", " + folly::to<std::string>(point.y) + "}";
+ return "{" + folly::to<std::string>(point.x) + ", " +
+ folly::to<std::string>(point.y) + "}";
}
inline std::string toString(const Size &size) {
- return "{" + folly::to<std::string>(size.width) + ", " + folly::to<std::string>(size.height) + "}";
+ return "{" + folly::to<std::string>(size.width) + ", " +
+ folly::to<std::string>(size.height) + "}";
}
inline std::string toString(const Rect &rect) {
@@ -146,16 +165,14 @@
}
inline std::string toString(const EdgeInsets &edgeInsets) {
- return "{" +
- folly::to<std::string>(edgeInsets.left) + ", " +
+ return "{" + folly::to<std::string>(edgeInsets.left) + ", " +
folly::to<std::string>(edgeInsets.top) + ", " +
folly::to<std::string>(edgeInsets.right) + ", " +
folly::to<std::string>(edgeInsets.bottom) + "}";
}
inline std::string toString(const CornerInsets &cornerInsets) {
- return "{" +
- folly::to<std::string>(cornerInsets.topLeft) + ", " +
+ return "{" + folly::to<std::string>(cornerInsets.topLeft) + ", " +
folly::to<std::string>(cornerInsets.topRight) + ", " +
folly::to<std::string>(cornerInsets.bottomLeft) + ", " +
folly::to<std::string>(cornerInsets.bottomRight) + "}";

ReactCommon/fabric/graphics/Geometry.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -6,9 +6,11 @@
#pragma once
#include <algorithm>
+#include <functional>
#include <tuple>
-#include <fabric/graphics/Float.h>
+#include <folly/Hash.h>
+#include <react/graphics/Float.h>
namespace facebook {
namespace react {
@@ -17,26 +19,30 @@
* Point
*/
struct Point {
- Float x {0};
- Float y {0};
+ Float x{0};
+ Float y{0};
- Point& operator += (const Point& rhs) {
- x += rhs.x;
- y += rhs.y;
+ Point &operator+=(const Point &point) {
+ x += point.x;
+ y += point.y;
return *this;
}
- friend Point operator + (Point lhs, const Point& rhs) {
+ Point &operator*=(const Point &point) {
+ x *= point.x;
+ y *= point.y;
+ return *this;
+ }
+
+ friend Point operator+(Point lhs, const Point &rhs) {
return lhs += rhs;
}
- bool operator ==(const Point& rhs) const {
- return
- std::tie(this->x, this->y) ==
- std::tie(rhs.x, rhs.y);
+ bool operator==(const Point &rhs) const {
+ return std::tie(this->x, this->y) == std::tie(rhs.x, rhs.y);
}
- bool operator !=(const Point& rhs) const {
+ bool operator!=(const Point &rhs) const {
return !(*this == rhs);
}
};
@@ -45,16 +51,27 @@
* Size
*/
struct Size {
- Float width {0};
- Float height {0};
+ Float width{0};
+ Float height{0};
+
+ Size &operator+=(const Point &point) {
+ width += point.x;
+ height += point.y;
+ return *this;
+ }
- bool operator ==(const Size& rhs) const {
- return
- std::tie(this->width, this->height) ==
+ Size &operator*=(const Point &point) {
+ width *= point.x;
+ height *= point.y;
+ return *this;
+ }
+
+ bool operator==(const Size &rhs) const {
+ return std::tie(this->width, this->height) ==
std::tie(rhs.width, rhs.height);
}
- bool operator !=(const Size& rhs) const {
+ bool operator!=(const Size &rhs) const {
return !(*this == rhs);
}
};
@@ -63,85 +80,158 @@
* Rect: Point and Size
*/
struct Rect {
- Point origin {0, 0};
- Size size {0, 0};
+ Point origin{0, 0};
+ Size size{0, 0};
- bool operator ==(const Rect& rhs) const {
- return
- std::tie(this->origin, this->size) ==
- std::tie(rhs.origin, rhs.size);
+ bool operator==(const Rect &rhs) const {
+ return std::tie(this->origin, this->size) == std::tie(rhs.origin, rhs.size);
}
- bool operator !=(const Rect& rhs) const {
+ bool operator!=(const Rect &rhs) const {
return !(*this == rhs);
}
- Float getMaxX() const { return size.width > 0 ? origin.x + size.width : origin.x; }
- Float getMaxY() const { return size.height > 0 ? origin.y + size.height : origin.y; }
- Float getMinX() const { return size.width >= 0 ? origin.x : origin.x + size.width; }
- Float getMinY() const { return size.height >= 0 ? origin.y : origin.y + size.height; }
+ Float getMaxX() const {
+ return size.width > 0 ? origin.x + size.width : origin.x;
+ }
+ Float getMaxY() const {
+ return size.height > 0 ? origin.y + size.height : origin.y;
+ }
+ Float getMinX() const {
+ return size.width >= 0 ? origin.x : origin.x + size.width;
+ }
+ Float getMinY() const {
+ return size.height >= 0 ? origin.y : origin.y + size.height;
+ }
void unionInPlace(const Rect &rect) {
- Float x1 = std::min(getMinX(), rect.getMinX());
- Float y1 = std::min(getMinY(), rect.getMinY());
- Float x2 = std::max(getMaxX(), rect.getMaxX());
- Float y2 = std::max(getMaxY(), rect.getMaxY());
+ auto x1 = std::min(getMinX(), rect.getMinX());
+ auto y1 = std::min(getMinY(), rect.getMinY());
+ auto x2 = std::max(getMaxX(), rect.getMaxX());
+ auto y2 = std::max(getMaxY(), rect.getMaxY());
origin = {x1, y1};
size = {x2 - x1, y2 - y1};
}
};
/*
- * EdgeInsets
+ * Generic data structure describes some values associated with *edges*
+ * of a rectangle.
*/
-struct EdgeInsets {
- Float left {0};
- Float top {0};
- Float right {0};
- Float bottom {0};
-
- bool operator ==(const EdgeInsets& rhs) const {
- return
- std::tie(this->left, this->top, this->right, this->bottom) ==
+template <typename T>
+struct RectangleEdges {
+ T left{};
+ T top{};
+ T right{};
+ T bottom{};
+
+ bool operator==(const RectangleEdges<T> &rhs) const {
+ return std::tie(this->left, this->top, this->right, this->bottom) ==
std::tie(rhs.left, rhs.top, rhs.right, rhs.bottom);
}
- bool operator !=(const EdgeInsets& rhs) const {
+ bool operator!=(const RectangleEdges<T> &rhs) const {
return !(*this == rhs);
}
bool isUniform() const {
- return left == top &&
- left == right &&
- left == bottom;
+ return left == top && left == right && left == bottom;
}
};
/*
- * CornerInsets
+ * Generic data structure describes some values associated with *corners*
+ * of a rectangle.
*/
-struct CornerInsets {
- Float topLeft {0};
- Float topRight {0};
- Float bottomLeft {0};
- Float bottomRight {0};
-
- bool operator ==(const CornerInsets& rhs) const {
- return
- std::tie(this->topLeft, this->topRight, this->bottomLeft, this->bottomRight) ==
+template <typename T>
+struct RectangleCorners {
+ T topLeft{};
+ T topRight{};
+ T bottomLeft{};
+ T bottomRight{};
+
+ bool operator==(const RectangleCorners<T> &rhs) const {
+ return std::tie(
+ this->topLeft,
+ this->topRight,
+ this->bottomLeft,
+ this->bottomRight) ==
std::tie(rhs.topLeft, rhs.topRight, rhs.bottomLeft, rhs.bottomRight);
}
- bool operator !=(const CornerInsets& rhs) const {
+ bool operator!=(const RectangleCorners<T> &rhs) const {
return !(*this == rhs);
}
bool isUniform() const {
- return topLeft == topRight &&
- topLeft == bottomLeft &&
+ return topLeft == topRight && topLeft == bottomLeft &&
topLeft == bottomRight;
}
};
+/*
+ * EdgeInsets
+ */
+using EdgeInsets = RectangleEdges<Float>;
+
+/*
+ * CornerInsets
+ */
+using CornerInsets = RectangleCorners<Float>;
+
} // namespace react
} // namespace facebook
+
+namespace std {
+template <>
+struct hash<facebook::react::Point> {
+ size_t operator()(const facebook::react::Point &point) const {
+ auto seed = size_t{0};
+ folly::hash::hash_combine(seed, point.x, point.y);
+ return seed;
+ }
+};
+
+template <>
+struct hash<facebook::react::Size> {
+ size_t operator()(const facebook::react::Size &size) const {
+ auto seed = size_t{0};
+ folly::hash::hash_combine(seed, size.width, size.height);
+ return seed;
+ }
+};
+
+template <>
+struct hash<facebook::react::Rect> {
+ size_t operator()(const facebook::react::Rect &rect) const {
+ auto seed = size_t{0};
+ folly::hash::hash_combine(seed, rect.origin, rect.size);
+ return seed;
+ }
+};
+
+template <typename T>
+struct hash<facebook::react::RectangleEdges<T>> {
+ size_t operator()(const facebook::react::RectangleEdges<T> &edges) const {
+ auto seed = size_t{0};
+ folly::hash::hash_combine(
+ seed, edges.left, edges.right, edges.top, edges.bottom);
+ return seed;
+ }
+};
+
+template <typename T>
+struct hash<facebook::react::RectangleCorners<T>> {
+ size_t operator()(const facebook::react::RectangleCorners<T> &corners) const {
+ auto seed = size_t{0};
+ folly::hash::hash_combine(
+ seed,
+ corners.topLeft,
+ corners.bottomLeft,
+ corners.topRight,
+ corners.bottomRight);
+ return seed;
+ }
+};
+
+} // namespace std

ReactCommon/fabric/graphics/platform/android/Color.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,22 +11,36 @@
namespace react {
SharedColor colorFromComponents(ColorComponents components) {
+ float ratio = 255.9999;
return SharedColor(
- ((int)components.alpha & 0xff) << 24 |
- ((int)components.red & 0xff) << 16 |
- ((int)components.green & 0xff) << 8 |
- ((int)components.blue & 0xff)
- );
+ ((int)(components.alpha * ratio) & 0xff) << 24 |
+ ((int)(components.red * ratio) & 0xff) << 16 |
+ ((int)(components.green * ratio) & 0xff) << 8 |
+ ((int)(components.blue * ratio) & 0xff));
}
ColorComponents colorComponentsFromColor(SharedColor sharedColor) {
+ float ratio = 256;
Color color = *sharedColor;
- return ColorComponents {
- (float)((color >> 16) & 0xff),
- (float)((color >> 8) & 0xff),
- (float)((color ) & 0xff),
- (float)((color >> 24) & 0xff)
- };
+ return ColorComponents{(float)((color >> 16) & 0xff) / ratio,
+ (float)((color >> 8) & 0xff) / ratio,
+ (float)((color >> 0) & 0xff) / ratio,
+ (float)((color >> 24) & 0xff) / ratio};
+}
+
+SharedColor clearColor() {
+ static SharedColor color = colorFromComponents(ColorComponents{0, 0, 0, 0});
+ return color;
+}
+
+SharedColor blackColor() {
+ static SharedColor color = colorFromComponents(ColorComponents{0, 0, 0, 1});
+ return color;
+}
+
+SharedColor whiteColor() {
+ static SharedColor color = colorFromComponents(ColorComponents{1, 1, 1, 1});
+ return color;
}
} // namespace react

ReactCommon/fabric/graphics/platform/android/Color.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,9 +7,10 @@
#pragma once
+#include <functional>
#include <limits>
-#include <fabric/graphics/ColorComponents.h>
+#include <react/graphics/ColorComponents.h>
namespace facebook {
namespace react {
@@ -17,24 +18,20 @@
using Color = int;
/*
- * On Android, a color can be represented as 32 bits integer, so there is no need
- * to instantiate complex color objects and then pass them as shared pointers.
- * Hense instead of using shared_ptr, we use a simple wrapper class
+ * On Android, a color can be represented as 32 bits integer, so there is no
+ * need to instantiate complex color objects and then pass them as shared
+ * pointers. Hense instead of using shared_ptr, we use a simple wrapper class
* which provides a pointer-like interface.
*/
class SharedColor {
-
-public:
+ public:
static const Color UndefinedColor = std::numeric_limits<Color>::max();
- SharedColor():
- color_(UndefinedColor) {}
+ SharedColor() : color_(UndefinedColor) {}
- SharedColor(const SharedColor &sharedColor) :
- color_(sharedColor.color_) {}
+ SharedColor(const SharedColor &sharedColor) : color_(sharedColor.color_) {}
- SharedColor(Color color):
- color_(color) {}
+ SharedColor(Color color) : color_(color) {}
SharedColor &operator=(const SharedColor &sharedColor) {
color_ = sharedColor.color_;
@@ -49,12 +46,25 @@
return color_ != UndefinedColor;
}
-private:
+ private:
Color color_;
};
SharedColor colorFromComponents(ColorComponents components);
ColorComponents colorComponentsFromColor(SharedColor color);
+SharedColor clearColor();
+SharedColor blackColor();
+SharedColor whiteColor();
+
} // namespace react
} // namespace facebook
+
+namespace std {
+template <>
+struct hash<facebook::react::SharedColor> {
+ size_t operator()(const facebook::react::SharedColor &sharedColor) const {
+ return hash<decltype(*sharedColor)>{}(*sharedColor);
+ }
+};
+} // namespace std

ReactCommon/fabric/graphics/platform/android/Float.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactCommon/fabric/graphics/platform/ios/Color.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -12,30 +12,42 @@
SharedColor colorFromComponents(ColorComponents components) {
const CGFloat componentsArray[] = {
- components.red,
- components.green,
- components.blue,
- components.alpha
- };
-
- CGColorRef color = CGColorCreate(
- CGColorSpaceCreateDeviceRGB(),
- componentsArray
- );
+ components.red, components.green, components.blue, components.alpha};
+
+ auto color = CGColorCreate(CGColorSpaceCreateDeviceRGB(), componentsArray);
return SharedColor(color, CFRelease);
}
ColorComponents colorComponentsFromColor(SharedColor color) {
- int numberOfComponents = CGColorGetNumberOfComponents(color.get());
+ if (!color) {
+ // Empty color object can be considered as `clear` (black, fully
+ // transparent) color.
+ return ColorComponents{0, 0, 0, 0};
+ }
+
+ auto numberOfComponents = CGColorGetNumberOfComponents(color.get());
assert(numberOfComponents == 4);
const CGFloat *components = CGColorGetComponents(color.get());
- return ColorComponents {
- (float)components[0],
+ return ColorComponents{(float)components[0],
(float)components[1],
(float)components[2],
- (float)components[3]
- };
+ (float)components[3]};
+}
+
+SharedColor clearColor() {
+ static SharedColor color = colorFromComponents(ColorComponents{0, 0, 0, 0});
+ return color;
+}
+
+SharedColor blackColor() {
+ static SharedColor color = colorFromComponents(ColorComponents{0, 0, 0, 1});
+ return color;
+}
+
+SharedColor whiteColor() {
+ static SharedColor color = colorFromComponents(ColorComponents{1, 1, 1, 1});
+ return color;
}
} // namespace react

ReactCommon/fabric/graphics/platform/ios/Color.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,9 +9,9 @@
#include <memory>
-#include <fabric/graphics/Float.h>
-
-#include <fabric/graphics/ColorComponents.h>
+#include <CoreGraphics/CoreGraphics.h>
+#include <react/graphics/ColorComponents.h>
+#include <react/graphics/Float.h>
namespace facebook {
namespace react {
@@ -22,5 +22,9 @@
SharedColor colorFromComponents(ColorComponents components);
ColorComponents colorComponentsFromColor(SharedColor color);
+SharedColor clearColor();
+SharedColor blackColor();
+SharedColor whiteColor();
+
} // namespace react
} // namespace facebook

ReactCommon/fabric/graphics/platform/ios/Float.h

@@ -1,12 +1,12 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
#pragma once
-#include <limits>
#include <CoreGraphics/CoreGraphics.h>
+#include <limits>
namespace facebook {
namespace react {

ReactCommon/fabric/graphics/tests/GraphicsTest.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactCommon/fabric/imagemanager/BUCK

@@ -1,13 +1,13 @@
-load("//configurations/buck/apple:flag_defs.bzl", "OBJC_ARC_PREPROCESSOR_FLAGS", "get_application_ios_flags", "get_debug_preprocessor_flags")
+load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags")
load(
"//tools/build_defs/oss:rn_defs.bzl",
"ANDROID",
"APPLE",
- "get_apple_inspector_flags",
+ "fb_xplat_cxx_test",
"get_apple_compiler_flags",
+ "get_apple_inspector_flags",
"react_native_xplat_target",
"rn_xplat_cxx_library",
- "fb_xplat_cxx_test",
"subdir_glob",
)
@@ -32,7 +32,7 @@
[
("", "*.h"),
],
- prefix = "fabric/imagemanager",
+ prefix = "react/imagemanager",
),
fbandroid_headers = subdir_glob(
[
@@ -48,9 +48,6 @@
),
fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
- fbobjc_tests = [
- ":tests",
- ],
force_static = True,
ios_deps = [
"xplat//js:RCTImage",
@@ -61,7 +58,7 @@
("", "*.h"),
("platform/ios", "RCTImagePrimitivesConversions.h"),
],
- prefix = "fabric/imagemanager",
+ prefix = "react/imagemanager",
),
ios_frameworks = [
"$SDKROOT/System/Library/Frameworks/CoreGraphics.framework",
@@ -87,7 +84,7 @@
"-DLOG_TAG=\"ReactNative\"",
"-DWITH_FBSYSTRACE=1",
],
- tests = [],
+ tests = [":tests"],
visibility = ["PUBLIC"],
deps = [
"xplat//fbsystrace:fbsystrace",
@@ -98,6 +95,7 @@
"xplat//third-party/glog:glog",
"xplat//yoga:yoga",
react_native_xplat_target("fabric/core:core"),
+ react_native_xplat_target("fabric/mounting:mounting"),
react_native_xplat_target("fabric/debug:debug"),
react_native_xplat_target("fabric/graphics:graphics"),
],
@@ -114,7 +112,7 @@
"-Wall",
],
contacts = ["oncall+react_native@xmail.facebook.com"],
- platforms = APPLE,
+ platforms = (ANDROID, APPLE),
deps = [
"xplat//folly:molly",
"xplat//third-party/gmock:gtest",

ReactCommon/fabric/imagemanager/ImageManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,8 +9,8 @@
#include <memory>
-#include <fabric/imagemanager/ImageRequest.h>
-#include <fabric/imagemanager/primitives.h>
+#include <react/imagemanager/ImageRequest.h>
+#include <react/imagemanager/primitives.h>
namespace facebook {
namespace react {
@@ -23,14 +23,13 @@
* Cross platform facade for iOS-specific RCTImageManager.
*/
class ImageManager {
-public:
-
+ public:
ImageManager(void *platformSpecificCounterpart);
~ImageManager();
ImageRequest requestImage(const ImageSource &imageSource) const;
-private:
+ private:
void *self_;
};

ReactCommon/fabric/imagemanager/ImageRequest.cpp

@@ -1,49 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#include "ImageRequest.h"
-
-namespace facebook {
-namespace react {
-
-class ImageRequest::ImageNoLongerNeededException:
- public std::logic_error {
-public:
- ImageNoLongerNeededException():
- std::logic_error("Image no longer needed.") {}
-};
-
-ImageRequest::ImageRequest(const ImageSource &imageSource, folly::Future<ImageResponse> &&responseFuture):
- imageSource_(imageSource),
- responseFutureSplitter_(folly::splitFuture(std::move(responseFuture))) {}
-
-ImageRequest::ImageRequest(ImageRequest &&other) noexcept:
- imageSource_(std::move(other.imageSource_)),
- responseFutureSplitter_(std::move(other.responseFutureSplitter_)) {
- other.moved_ = true;
- };
-
-ImageRequest::~ImageRequest() {
- if (!moved_) {
- auto future = responseFutureSplitter_.getFuture();
- if (!future.isReady()) {
- future.raise(ImageNoLongerNeededException());
- }
- }
-}
-
-folly::Future<ImageResponse> ImageRequest::getResponseFuture() const {
- if (moved_) {
- abort();
- }
-
- std::lock_guard<std::mutex> lock(mutex_);
- return responseFutureSplitter_.getFuture();
-}
-
-} // namespace react
-} // namespace facebook

ReactCommon/fabric/imagemanager/ImageRequest.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,12 +7,10 @@
#pragma once
-#include <mutex>
-
-#include <fabric/imagemanager/ImageResponse.h>
-#include <fabric/imagemanager/primitives.h>
-#include <folly/futures/Future.h>
-#include <folly/futures/FutureSplitter.h>
+#include <react/imagemanager/ImageResponse.h>
+#include <react/imagemanager/ImageResponseObserver.h>
+#include <react/imagemanager/ImageResponseObserverCoordinator.h>
+#include <react/imagemanager/primitives.h>
namespace facebook {
namespace react {
@@ -22,13 +20,10 @@
* The separate object must be constructed for every single separate
* image request. The object cannot be copied because it would make managing of
* event listeners hard and inefficient; the object can be moved though.
- * To subscribe for notifications use `getResponseFuture()` method.
* Destroy to cancel the underlying request.
*/
class ImageRequest final {
-
-public:
-
+ public:
/*
* The exception which is thrown when `ImageRequest` is being deallocated
* if the future is not ready yet.
@@ -36,10 +31,9 @@
class ImageNoLongerNeededException;
/*
- * `ImageRequest` is constructed with `ImageSource` and
- * `ImageResponse` future which must be moved in inside the object.
+ * The default constructor
*/
- ImageRequest(const ImageSource &imageSource, folly::Future<ImageResponse> &&responseFuture);
+ ImageRequest(const ImageSource &imageSource);
/*
* The move constructor.
@@ -49,38 +43,40 @@
/*
* `ImageRequest` does not support copying by design.
*/
- ImageRequest(const ImageRequest &) = delete;
+ ImageRequest(const ImageRequest &other) = delete;
~ImageRequest();
- /*
- * Creates and returns a *new* future object with promised `ImageResponse`
- * result. Multiple consumers can call this method many times to create
- * their own subscriptions to promised value.
+ /**
+ * Set cancelation function.
*/
- folly::Future<ImageResponse> getResponseFuture() const;
-
-private:
+ void setCancelationFunction(std::function<void(void)> cancelationFunction);
/*
- * Mutext to protect an access to the future.
+ * Get observer coordinator.
*/
- mutable std::mutex mutex_;
+ const ImageResponseObserverCoordinator *getObserverCoordinator() const;
+ private:
/*
* Image source assosiated with the request.
*/
ImageSource imageSource_;
/*
- * Future splitter powers factory-like `getResponseFuture()` method.
+ * Event coordinator associated with the reqest.
+ */
+ std::shared_ptr<const ImageResponseObserverCoordinator> coordinator_{};
+
+ /*
+ * Function we can call to cancel image request (see destructor).
*/
- mutable folly::FutureSplitter<ImageResponse> responseFutureSplitter_;
+ std::function<void(void)> cancelRequest_;
/*
* Indicates that the object was moved and hence cannot be used anymore.
*/
- bool moved_ {false};
+ bool moved_{false};
};
} // namespace react

ReactCommon/fabric/imagemanager/ImageResponse.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,8 +10,8 @@
namespace facebook {
namespace react {
-ImageResponse::ImageResponse(const std::shared_ptr<void> &image):
- image_(image) {}
+ImageResponse::ImageResponse(const std::shared_ptr<void> &image)
+ : image_(image) {}
std::shared_ptr<void> ImageResponse::getImage() const {
return image_;

ReactCommon/fabric/imagemanager/ImageResponse.h

@@ -1,11 +1,13 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
*/
-#import <memory>
+#pragma once
+
+#include <memory>
namespace facebook {
namespace react {
@@ -14,14 +16,19 @@
* Represents retrieved image bitmap and any assotiated platform-specific info.
*/
class ImageResponse final {
+ public:
+ enum class Status {
+ Loading,
+ Completed,
+ Failed,
+ };
-public:
ImageResponse(const std::shared_ptr<void> &image);
std::shared_ptr<void> getImage() const;
-private:
- std::shared_ptr<void> image_;
+ private:
+ std::shared_ptr<void> image_{};
};
} // namespace react

ReactCommon/fabric/imagemanager/ImageResponseObserverCoordinator.cpp

@@ -0,0 +1,103 @@
+/**
+ * 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.
+ */
+
+#include "ImageResponseObserverCoordinator.h"
+
+#include <algorithm>
+
+namespace facebook {
+namespace react {
+
+ImageResponseObserverCoordinator::ImageResponseObserverCoordinator() {
+ status_ = ImageResponse::Status::Loading;
+}
+
+ImageResponseObserverCoordinator::~ImageResponseObserverCoordinator() {}
+
+void ImageResponseObserverCoordinator::addObserver(
+ ImageResponseObserver *observer) const {
+ ImageResponse::Status status = [this] {
+ std::shared_lock<folly::SharedMutex> read(mutex_);
+ return status_;
+ }();
+
+ if (status == ImageResponse::Status::Loading) {
+ std::unique_lock<folly::SharedMutex> write(mutex_);
+ observers_.push_back(observer);
+ } else if (status == ImageResponse::Status::Completed) {
+ ImageResponse imageResponseCopy = [this] {
+ std::unique_lock<folly::SharedMutex> read(mutex_);
+ return ImageResponse(imageData_);
+ }();
+ observer->didReceiveImage(imageResponseCopy);
+ } else {
+ observer->didReceiveFailure();
+ }
+}
+
+void ImageResponseObserverCoordinator::removeObserver(
+ ImageResponseObserver *observer) const {
+ std::unique_lock<folly::SharedMutex> write(mutex_);
+
+ auto position = std::find(observers_.begin(), observers_.end(), observer);
+ if (position != observers_.end()) {
+ observers_.erase(position, observers_.end());
+ }
+}
+
+void ImageResponseObserverCoordinator::nativeImageResponseProgress(
+ float progress) const {
+ std::vector<ImageResponseObserver *> observersCopy = [this] {
+ std::shared_lock<folly::SharedMutex> read(mutex_);
+ return observers_;
+ }();
+
+ for (auto observer : observersCopy) {
+ observer->didReceiveProgress(progress);
+ }
+}
+
+void ImageResponseObserverCoordinator::nativeImageResponseComplete(
+ const ImageResponse &imageResponse) const {
+ {
+ std::unique_lock<folly::SharedMutex> write(mutex_);
+ imageData_ = imageResponse.getImage();
+ status_ = ImageResponse::Status::Completed;
+ }
+
+ std::vector<ImageResponseObserver *> observersCopy = [this] {
+ std::shared_lock<folly::SharedMutex> read(mutex_);
+ return observers_;
+ }();
+
+ for (auto observer : observersCopy) {
+ ImageResponse imageResponseCopy = [this] {
+ std::unique_lock<folly::SharedMutex> read(mutex_);
+ return ImageResponse(imageData_);
+ }();
+ observer->didReceiveImage(imageResponseCopy);
+ }
+}
+
+void ImageResponseObserverCoordinator::nativeImageResponseFailed() const {
+ {
+ std::unique_lock<folly::SharedMutex> write(mutex_);
+ status_ = ImageResponse::Status::Failed;
+ }
+
+ std::vector<ImageResponseObserver *> observersCopy = [this] {
+ std::shared_lock<folly::SharedMutex> read(mutex_);
+ return observers_;
+ }();
+
+ for (auto observer : observersCopy) {
+ observer->didReceiveFailure();
+ }
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/imagemanager/ImageResponseObserverCoordinator.h

@@ -0,0 +1,91 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <react/imagemanager/ImageResponse.h>
+#include <react/imagemanager/ImageResponseObserver.h>
+
+#include <folly/SharedMutex.h>
+#include <shared_mutex>
+#include <vector>
+
+namespace facebook {
+namespace react {
+
+/*
+ * The ImageResponseObserverCoordinator receives events and completed image
+ * data from native image loaders and sends events to any observers attached
+ * to the coordinator. The Coordinator also keeps track of response status
+ * and caches completed images.
+ */
+class ImageResponseObserverCoordinator {
+ public:
+ /*
+ * Default constructor.
+ */
+ ImageResponseObserverCoordinator();
+
+ /*
+ * Default destructor.
+ */
+ ~ImageResponseObserverCoordinator();
+
+ /*
+ * Interested parties may observe the image response.
+ */
+ void addObserver(ImageResponseObserver *observer) const;
+
+ /*
+ * Interested parties may stop observing the image response.
+ */
+ void removeObserver(ImageResponseObserver *observer) const;
+
+ /*
+ * Platform-specific image loader will call this method with progress updates.
+ */
+ void nativeImageResponseProgress(float) const;
+
+ /*
+ * Platform-specific image loader will call this method with a completed image
+ * response.
+ */
+ void nativeImageResponseComplete(const ImageResponse &imageResponse) const;
+
+ /*
+ * Platform-specific image loader will call this method in case of any
+ * failures.
+ */
+ void nativeImageResponseFailed() const;
+
+ private:
+ /*
+ * List of observers.
+ * Mutable: protected by mutex_.
+ */
+ mutable std::vector<ImageResponseObserver *> observers_;
+
+ /*
+ * Current status of image loading.
+ * Mutable: protected by mutex_.
+ */
+ mutable ImageResponse::Status status_;
+
+ /*
+ * Cache image data.
+ * Mutable: protected by mutex_.
+ */
+ mutable std::shared_ptr<void> imageData_{};
+
+ /*
+ * Observer and data mutex.
+ */
+ mutable folly::SharedMutex mutex_;
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/imagemanager/ImageResponseObserver.h

@@ -0,0 +1,27 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <react/imagemanager/ImageResponse.h>
+
+namespace facebook {
+namespace react {
+
+/*
+ * Represents any observer of ImageResponse progression, completion, or failure.
+ */
+class ImageResponseObserver {
+ public:
+ virtual void didReceiveProgress(float) = 0;
+ virtual void didReceiveImage(const ImageResponse &imageResponse) = 0;
+ virtual void didReceiveFailure() = 0;
+ virtual ~ImageResponseObserver() noexcept = default;
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/imagemanager/platform/android/ImageManager.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -11,6 +11,8 @@
namespace react {
ImageManager::ImageManager(void *platformSpecificCounterpart) {
+ // Silence unused-private-field warning.
+ (void)self_;
// Not implemented.
}
@@ -20,6 +22,7 @@
ImageRequest ImageManager::requestImage(const ImageSource &imageSource) const {
// Not implemented.
+ return ImageRequest(imageSource);
}
} // namespace react

ReactCommon/fabric/imagemanager/platform/android/ImageRequest.cpp

@@ -0,0 +1,35 @@
+/**
+ * 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.
+ */
+
+#include "ImageRequest.h"
+
+namespace facebook {
+namespace react {
+
+ImageRequest::ImageRequest(const ImageSource &imageSource)
+ : imageSource_(imageSource) {
+ // Not implemented.
+}
+
+ImageRequest::ImageRequest(ImageRequest &&other) noexcept
+ : imageSource_(std::move(other.imageSource_)),
+ coordinator_(std::move(other.coordinator_)) {
+ // Not implemented.
+}
+
+ImageRequest::~ImageRequest() {
+ // Not implemented.
+}
+
+const ImageResponseObserverCoordinator *ImageRequest::getObserverCoordinator()
+ const {
+ // Not implemented
+ abort();
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/imagemanager/platform/ios/ImageManager.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -15,7 +15,9 @@
namespace react {
ImageManager::ImageManager(void *platformSpecificCounterpart) {
- self_ = (__bridge_retained void *)[[RCTImageManager alloc] initWithImageLoader:(__bridge_transfer RCTImageLoader *)platformSpecificCounterpart];
+ self_ = (__bridge_retained void *)[[RCTImageManager alloc]
+ initWithImageLoader:(__bridge RCTImageLoader *)
+ platformSpecificCounterpart];
}
ImageManager::~ImageManager() {

ReactCommon/fabric/imagemanager/platform/ios/ImageRequest.cpp

@@ -0,0 +1,49 @@
+/**
+ * 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.
+ */
+
+#include "ImageRequest.h"
+
+namespace facebook {
+namespace react {
+
+class ImageRequest::ImageNoLongerNeededException : public std::logic_error {
+ public:
+ ImageNoLongerNeededException()
+ : std::logic_error("Image no longer needed.") {}
+};
+
+ImageRequest::ImageRequest(const ImageSource &imageSource)
+ : imageSource_(imageSource) {
+ coordinator_ = std::make_shared<ImageResponseObserverCoordinator>();
+}
+
+ImageRequest::ImageRequest(ImageRequest &&other) noexcept
+ : imageSource_(std::move(other.imageSource_)),
+ coordinator_(std::move(other.coordinator_)) {
+ other.moved_ = true;
+ other.coordinator_ = nullptr;
+ other.cancelRequest_ = nullptr;
+}
+
+ImageRequest::~ImageRequest() {
+ if (cancelRequest_) {
+ cancelRequest_();
+ }
+}
+
+void ImageRequest::setCancelationFunction(
+ std::function<void(void)> cancelationFunction) {
+ cancelRequest_ = cancelationFunction;
+}
+
+const ImageResponseObserverCoordinator *ImageRequest::getObserverCoordinator()
+ const {
+ return coordinator_.get();
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/imagemanager/platform/ios/RCTImageManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,8 +7,8 @@
#import <UIKit/UIKit.h>
-#import <fabric/imagemanager/ImageRequest.h>
-#import <fabric/imagemanager/primitives.h>
+#import <react/imagemanager/ImageRequest.h>
+#import <react/imagemanager/primitives.h>
NS_ASSUME_NONNULL_BEGIN
@@ -21,7 +21,8 @@
- (instancetype)initWithImageLoader:(RCTImageLoader *)imageLoader;
-- (facebook::react::ImageRequest)requestImage:(const facebook::react::ImageSource &)imageSource;
+- (facebook::react::ImageRequest)requestImage:
+ (const facebook::react::ImageSource &)imageSource;
@end

ReactCommon/fabric/imagemanager/platform/ios/RCTImageManager.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,22 +7,19 @@
#import "RCTImageManager.h"
-#import <folly/futures/Future.h>
-#import <folly/futures/Promise.h>
-
#import <React/RCTImageLoader.h>
+#import <react/imagemanager/ImageResponse.h>
+#import <react/imagemanager/ImageResponseObserver.h>
#import "RCTImagePrimitivesConversions.h"
using namespace facebook::react;
-@implementation RCTImageManager
-{
+@implementation RCTImageManager {
RCTImageLoader *_imageLoader;
}
-- (instancetype)initWithImageLoader:(RCTImageLoader *)imageLoader
-{
+- (instancetype)initWithImageLoader:(RCTImageLoader *)imageLoader {
if (self = [super init]) {
_imageLoader = imageLoader;
}
@@ -30,39 +27,47 @@
return self;
}
-- (ImageRequest)requestImage:(const ImageSource &)imageSource
-{
- __block auto promise = folly::Promise<ImageResponse>();
+- (ImageRequest)requestImage:(const ImageSource &)imageSource {
+ auto imageRequest = ImageRequest(imageSource);
+
+ auto observerCoordinator = imageRequest.getObserverCoordinator();
NSURLRequest *request = NSURLRequestFromImageSource(imageSource);
auto completionBlock = ^(NSError *error, UIImage *image) {
- auto imageResponse = ImageResponse(std::shared_ptr<void>((__bridge_retained void *)image, CFRelease));
- promise.setValue(std::move(imageResponse));
+ if (image && !error) {
+ auto imageResponse = ImageResponse(
+ std::shared_ptr<void>((__bridge_retained void *)image, CFRelease));
+ observerCoordinator->nativeImageResponseComplete(
+ std::move(imageResponse));
+ } else {
+ observerCoordinator->nativeImageResponseFailed();
+ }
};
- auto interruptBlock = ^(const folly::exception_wrapper &exceptionWrapper) {
- if (!promise.isFulfilled()) {
- promise.setException(exceptionWrapper);
- }
+ auto progressBlock = ^(int64_t progress, int64_t total) {
+ observerCoordinator->nativeImageResponseProgress(progress / (float)total);
};
- RCTImageLoaderCancellationBlock cancellationBlock =
+ RCTImageLoaderCancellationBlock cancelationBlock =
[_imageLoader loadImageWithURLRequest:request
- size:CGSizeMake(imageSource.size.width, imageSource.size.height)
+ size:CGSizeMake(
+ imageSource.size.width,
+ imageSource.size.height)
scale:imageSource.scale
clipped:YES
resizeMode:RCTResizeModeStretch
- progressBlock:nil
+ progressBlock:progressBlock
partialLoadBlock:nil
completionBlock:completionBlock];
- promise.setInterruptHandler([cancellationBlock, interruptBlock](const folly::exception_wrapper &exceptionWrapper) {
- cancellationBlock();
- interruptBlock(exceptionWrapper);
- });
+ std::function<void(void)> cancelationFunction = [cancelationBlock](void) {
+ cancelationBlock();
+ };
+
+ imageRequest.setCancelationFunction(cancelationFunction);
- return ImageRequest(imageSource, promise.getFuture());
+ return imageRequest;
}
@end

ReactCommon/fabric/imagemanager/platform/ios/RCTImagePrimitivesConversions.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,28 +7,39 @@
#import <UIKit/UIKit.h>
-#import <fabric/imagemanager/primitives.h>
#import <React/RCTImageLoader.h>
+#import <react/imagemanager/primitives.h>
using namespace facebook::react;
-inline static RCTResizeMode RCTResizeModeFromImageResizeMode(ImageResizeMode imageResizeMode) {
+inline static RCTResizeMode RCTResizeModeFromImageResizeMode(
+ ImageResizeMode imageResizeMode) {
switch (imageResizeMode) {
- case ImageResizeMode::Cover: return RCTResizeModeCover;
- case ImageResizeMode::Contain: return RCTResizeModeContain;
- case ImageResizeMode::Stretch: return RCTResizeModeStretch;
- case ImageResizeMode::Center: return RCTResizeModeCenter;
- case ImageResizeMode::Repeat: return RCTResizeModeRepeat;
+ case ImageResizeMode::Cover:
+ return RCTResizeModeCover;
+ case ImageResizeMode::Contain:
+ return RCTResizeModeContain;
+ case ImageResizeMode::Stretch:
+ return RCTResizeModeStretch;
+ case ImageResizeMode::Center:
+ return RCTResizeModeCenter;
+ case ImageResizeMode::Repeat:
+ return RCTResizeModeRepeat;
}
}
inline std::string toString(const ImageResizeMode &value) {
switch (value) {
- case ImageResizeMode::Cover: return "cover";
- case ImageResizeMode::Contain: return "contain";
- case ImageResizeMode::Stretch: return "stretch";
- case ImageResizeMode::Center: return "center";
- case ImageResizeMode::Repeat: return "repeat";
+ case ImageResizeMode::Cover:
+ return "cover";
+ case ImageResizeMode::Contain:
+ return "contain";
+ case ImageResizeMode::Stretch:
+ return "stretch";
+ case ImageResizeMode::Center:
+ return "center";
+ case ImageResizeMode::Repeat:
+ return "repeat";
}
}
@@ -41,7 +52,8 @@
if (!imageSource.bundle.empty()) {
NSString *bundle = [NSString stringWithCString:imageSource.bundle.c_str()
encoding:NSASCIIStringEncoding];
- urlString = [NSString stringWithFormat:@"%@.bundle/%@", bundle, urlString];
+ urlString =
+ [NSString stringWithFormat:@"%@.bundle/%@", bundle, urlString];
}
NSURL *url = [[NSURL alloc] initWithString:urlString];
@@ -53,7 +65,8 @@
if ([urlString rangeOfString:@":"].location != NSNotFound) {
// The URL has a scheme.
- urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+ urlString = [urlString
+ stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
url = [NSURL URLWithString:urlString];
return url;
}
@@ -67,20 +80,21 @@
} else {
if (![urlString isAbsolutePath]) {
// Assume it's a resource path.
- urlString = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:urlString];
+ urlString = [[[NSBundle mainBundle] resourcePath]
+ stringByAppendingPathComponent:urlString];
}
}
url = [NSURL fileURLWithPath:urlString];
return url;
- }
- @catch (__unused NSException *exception) {
+ } @catch (__unused NSException *exception) {
return nil;
}
}
-inline static NSURLRequest *NSURLRequestFromImageSource(const ImageSource &imageSource) {
+inline static NSURLRequest *NSURLRequestFromImageSource(
+ const ImageSource &imageSource) {
NSURL *url = NSURLFromImageSource(imageSource);
if (!url) {

ReactCommon/fabric/imagemanager/primitives.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -10,30 +10,23 @@
#include <string>
#include <vector>
-#include <fabric/graphics/Geometry.h>
+#include <react/graphics/Geometry.h>
namespace facebook {
namespace react {
class ImageSource {
+ public:
+ enum class Type { Invalid, Remote, Local };
-public:
- enum class Type {
- Invalid,
- Remote,
- Local
- };
-
- Type type {};
- std::string uri {};
- std::string bundle {};
- Float scale {3};
- Size size {0};
+ Type type{};
+ std::string uri{};
+ std::string bundle{};
+ Float scale{3};
+ Size size{0};
bool operator==(const ImageSource &rhs) const {
- return
- std::tie(this->type, this->uri) ==
- std::tie(rhs.type, rhs.uri);
+ return std::tie(this->type, this->uri) == std::tie(rhs.type, rhs.uri);
}
bool operator!=(const ImageSource &rhs) const {

ReactCommon/fabric/imagemanager/tests/ImageManagerTest.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,7 +9,7 @@
#include <gtest/gtest.h>
-#include <fabric/imagemanager/ImageManager.h>
+#include <react/imagemanager/ImageManager.h>
using namespace facebook::react;

ReactCommon/fabric/mounting/BUCK

@@ -0,0 +1,81 @@
+load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags")
+load(
+ "//tools/build_defs/oss:rn_defs.bzl",
+ "ANDROID",
+ "APPLE",
+ "fb_xplat_cxx_test",
+ "get_apple_compiler_flags",
+ "get_apple_inspector_flags",
+ "react_native_xplat_target",
+ "rn_xplat_cxx_library",
+ "subdir_glob",
+)
+
+APPLE_COMPILER_FLAGS = get_apple_compiler_flags()
+
+rn_xplat_cxx_library(
+ name = "mounting",
+ srcs = glob(
+ ["**/*.cpp"],
+ exclude = glob(["tests/**/*.cpp"]),
+ ),
+ headers = glob(
+ ["**/*.h"],
+ exclude = glob(["tests/**/*.h"]),
+ ),
+ header_namespace = "",
+ exported_headers = subdir_glob(
+ [
+ ("", "*.h"),
+ ],
+ prefix = "react/mounting",
+ ),
+ compiler_flags = [
+ "-fexceptions",
+ "-frtti",
+ "-std=c++14",
+ "-Wall",
+ ],
+ fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
+ fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
+ force_static = True,
+ macosx_tests_override = [],
+ platforms = (ANDROID, APPLE),
+ preprocessor_flags = [
+ "-DLOG_TAG=\"ReactNative\"",
+ # Systraces are temporary disabled.
+ # "-DWITH_FBSYSTRACE=1",
+ ],
+ tests = [":tests"],
+ visibility = ["PUBLIC"],
+ deps = [
+ "xplat//fbsystrace:fbsystrace",
+ "xplat//folly:headers_only",
+ "xplat//folly:memory",
+ "xplat//folly:molly",
+ "xplat//third-party/glog:glog",
+ react_native_xplat_target("better:better"),
+ react_native_xplat_target("fabric/core:core"),
+ react_native_xplat_target("fabric/debug:debug"),
+ react_native_xplat_target("fabric/events:events"),
+ ],
+)
+
+fb_xplat_cxx_test(
+ name = "tests",
+ srcs = glob(["tests/**/*.cpp"]),
+ headers = glob(["tests/**/*.h"]),
+ compiler_flags = [
+ "-fexceptions",
+ "-frtti",
+ "-std=c++14",
+ "-Wall",
+ ],
+ contacts = ["oncall+react_native@xmail.facebook.com"],
+ platforms = (ANDROID, APPLE),
+ deps = [
+ "xplat//folly:molly",
+ "xplat//third-party/gmock:gtest",
+ ":mounting",
+ ],
+)

ReactCommon/fabric/mounting/Differentiator.cpp

@@ -0,0 +1,244 @@
+// 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.
+
+#include "Differentiator.h"
+
+#include <better/map.h>
+#include <react/core/LayoutableShadowNode.h>
+#include <react/debug/SystraceSection.h>
+#include "ShadowView.h"
+
+namespace facebook {
+namespace react {
+
+static void sliceChildShadowNodeViewPairsRecursively(
+ ShadowViewNodePairList &pairList,
+ Point layoutOffset,
+ const ShadowNode &shadowNode) {
+ for (const auto &childShadowNode : shadowNode.getChildren()) {
+ auto shadowView = ShadowView(*childShadowNode);
+
+ const auto layoutableShadowNode =
+ dynamic_cast<const LayoutableShadowNode *>(childShadowNode.get());
+#ifndef ANDROID
+ // New approach (iOS):
+ // Non-view components are treated as layout-only views (they aren't
+ // represented as `ShadowView`s).
+ if (!layoutableShadowNode || layoutableShadowNode->isLayoutOnly()) {
+#else
+ // Previous approach (Android):
+ // Non-view components are treated as normal views with an empty layout
+ // (they are represented as `ShadowView`s).
+ if (layoutableShadowNode && layoutableShadowNode->isLayoutOnly()) {
+#endif
+ sliceChildShadowNodeViewPairsRecursively(
+ pairList,
+ layoutOffset + shadowView.layoutMetrics.frame.origin,
+ *childShadowNode);
+ } else {
+ shadowView.layoutMetrics.frame.origin += layoutOffset;
+ pairList.push_back({shadowView, *childShadowNode});
+ }
+ }
+}
+
+static ShadowViewNodePairList sliceChildShadowNodeViewPairs(
+ const ShadowNode &shadowNode) {
+ ShadowViewNodePairList pairList;
+ sliceChildShadowNodeViewPairsRecursively(pairList, {0, 0}, shadowNode);
+ return pairList;
+}
+
+static void calculateShadowViewMutations(
+ ShadowViewMutationList &mutations,
+ const ShadowView &parentShadowView,
+ const ShadowViewNodePairList &oldChildPairs,
+ const ShadowViewNodePairList &newChildPairs) {
+ // The current version of the algorithm is otimized for simplicity,
+ // not for performance or optimal result.
+
+ if (oldChildPairs == newChildPairs) {
+ return;
+ }
+
+ if (oldChildPairs.size() == 0 && newChildPairs.size() == 0) {
+ return;
+ }
+
+ better::map<Tag, ShadowViewNodePair> insertedPairs;
+ int index = 0;
+
+ ShadowViewMutationList createMutations = {};
+ ShadowViewMutationList deleteMutations = {};
+ ShadowViewMutationList insertMutations = {};
+ ShadowViewMutationList removeMutations = {};
+ ShadowViewMutationList updateMutations = {};
+ ShadowViewMutationList downwardMutations = {};
+ ShadowViewMutationList destructiveDownwardMutations = {};
+
+ // Stage 1: Collecting `Update` mutations
+ for (index = 0; index < oldChildPairs.size() && index < newChildPairs.size();
+ index++) {
+ const auto &oldChildPair = oldChildPairs[index];
+ const auto &newChildPair = newChildPairs[index];
+
+ if (oldChildPair.shadowView.tag != newChildPair.shadowView.tag) {
+ // Totally different nodes, updating is impossible.
+ break;
+ }
+
+ if (oldChildPair.shadowView != newChildPair.shadowView) {
+ updateMutations.push_back(ShadowViewMutation::UpdateMutation(
+ parentShadowView,
+ oldChildPair.shadowView,
+ newChildPair.shadowView,
+ index));
+ }
+
+ const auto oldGrandChildPairs =
+ sliceChildShadowNodeViewPairs(oldChildPair.shadowNode);
+ const auto newGrandChildPairs =
+ sliceChildShadowNodeViewPairs(newChildPair.shadowNode);
+ calculateShadowViewMutations(
+ *(newGrandChildPairs.size() ? &downwardMutations
+ : &destructiveDownwardMutations),
+ oldChildPair.shadowView,
+ oldGrandChildPairs,
+ newGrandChildPairs);
+ }
+
+ int lastIndexAfterFirstStage = index;
+
+ // Stage 2: Collecting `Insert` mutations
+ for (; index < newChildPairs.size(); index++) {
+ const auto &newChildPair = newChildPairs[index];
+
+ insertMutations.push_back(ShadowViewMutation::InsertMutation(
+ parentShadowView, newChildPair.shadowView, index));
+
+ insertedPairs.insert({newChildPair.shadowView.tag, newChildPair});
+ }
+
+ // Stage 3: Collecting `Delete` and `Remove` mutations
+ for (index = lastIndexAfterFirstStage; index < oldChildPairs.size();
+ index++) {
+ const auto &oldChildPair = oldChildPairs[index];
+
+ // Even if the old view was (re)inserted, we have to generate `remove`
+ // mutation.
+ removeMutations.push_back(ShadowViewMutation::RemoveMutation(
+ parentShadowView, oldChildPair.shadowView, index));
+
+ const auto &it = insertedPairs.find(oldChildPair.shadowView.tag);
+
+ if (it == insertedPairs.end()) {
+ // The old view was *not* (re)inserted.
+ // We have to generate `delete` mutation and apply the algorithm
+ // recursively.
+ deleteMutations.push_back(
+ ShadowViewMutation::DeleteMutation(oldChildPair.shadowView));
+
+ // We also have to call the algorithm recursively to clean up the entire
+ // subtree starting from the removed view.
+ calculateShadowViewMutations(
+ destructiveDownwardMutations,
+ oldChildPair.shadowView,
+ sliceChildShadowNodeViewPairs(oldChildPair.shadowNode),
+ {});
+ } else {
+ // The old view *was* (re)inserted.
+ // We have to call the algorithm recursively if the inserted view
+ // is *not* the same as removed one.
+ const auto &newChildPair = it->second;
+ if (newChildPair.shadowView != oldChildPair.shadowView) {
+ const auto oldGrandChildPairs =
+ sliceChildShadowNodeViewPairs(oldChildPair.shadowNode);
+ const auto newGrandChildPairs =
+ sliceChildShadowNodeViewPairs(newChildPair.shadowNode);
+ calculateShadowViewMutations(
+ *(newGrandChildPairs.size() ? &downwardMutations
+ : &destructiveDownwardMutations),
+ newChildPair.shadowView,
+ oldGrandChildPairs,
+ newGrandChildPairs);
+ }
+
+ // In any case we have to remove the view from `insertedPairs` as
+ // indication that the view was actually removed (which means that
+ // the view existed before), hence we don't have to generate
+ // `create` mutation.
+ insertedPairs.erase(it);
+ }
+ }
+
+ // Stage 4: Collecting `Create` mutations
+ for (index = lastIndexAfterFirstStage; index < newChildPairs.size();
+ index++) {
+ const auto &newChildPair = newChildPairs[index];
+
+ if (insertedPairs.find(newChildPair.shadowView.tag) ==
+ insertedPairs.end()) {
+ // The new view was (re)inserted, so there is no need to create it.
+ continue;
+ }
+
+ createMutations.push_back(
+ ShadowViewMutation::CreateMutation(newChildPair.shadowView));
+
+ calculateShadowViewMutations(
+ downwardMutations,
+ newChildPair.shadowView,
+ {},
+ sliceChildShadowNodeViewPairs(newChildPair.shadowNode));
+ }
+
+ // All mutations in an optimal order:
+ mutations.insert(
+ mutations.end(),
+ destructiveDownwardMutations.begin(),
+ destructiveDownwardMutations.end());
+ mutations.insert(
+ mutations.end(), updateMutations.begin(), updateMutations.end());
+ mutations.insert(
+ mutations.end(), removeMutations.rbegin(), removeMutations.rend());
+ mutations.insert(
+ mutations.end(), deleteMutations.begin(), deleteMutations.end());
+ mutations.insert(
+ mutations.end(), createMutations.begin(), createMutations.end());
+ mutations.insert(
+ mutations.end(), insertMutations.begin(), insertMutations.end());
+ mutations.insert(
+ mutations.end(), downwardMutations.begin(), downwardMutations.end());
+}
+
+ShadowViewMutationList calculateShadowViewMutations(
+ const ShadowNode &oldRootShadowNode,
+ const ShadowNode &newRootShadowNode) {
+ SystraceSection s("calculateShadowViewMutations");
+
+ // Root shadow nodes must have same tag.
+ assert(oldRootShadowNode.getTag() == newRootShadowNode.getTag());
+
+ ShadowViewMutationList mutations;
+
+ auto oldRootShadowView = ShadowView(oldRootShadowNode);
+ auto newRootShadowView = ShadowView(newRootShadowNode);
+
+ if (oldRootShadowView != newRootShadowView) {
+ mutations.push_back(ShadowViewMutation::UpdateMutation(
+ ShadowView(), oldRootShadowView, newRootShadowView, -1));
+ }
+
+ calculateShadowViewMutations(
+ mutations,
+ ShadowView(oldRootShadowNode),
+ sliceChildShadowNodeViewPairs(oldRootShadowNode),
+ sliceChildShadowNodeViewPairs(newRootShadowNode));
+
+ return mutations;
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/mounting/Differentiator.h

@@ -0,0 +1,24 @@
+// 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.
+
+#pragma once
+
+#include <react/core/ShadowNode.h>
+#include <react/mounting/ShadowViewMutation.h>
+
+namespace facebook {
+namespace react {
+
+/*
+ * Calculates a list of view mutations which describes how the old
+ * `ShadowTree` can be transformed to the new one.
+ * The list of mutations might be and might not be optimal.
+ */
+ShadowViewMutationList calculateShadowViewMutations(
+ const ShadowNode &oldRootShadowNode,
+ const ShadowNode &newRootShadowNode);
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/mounting/ShadowView.cpp

@@ -0,0 +1,59 @@
+// 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.
+
+#include "ShadowView.h"
+
+#include <react/core/LayoutableShadowNode.h>
+
+namespace facebook {
+namespace react {
+
+static LayoutMetrics layoutMetricsFromShadowNode(const ShadowNode &shadowNode) {
+ auto layoutableShadowNode =
+ dynamic_cast<const LayoutableShadowNode *>(&shadowNode);
+ return layoutableShadowNode ? layoutableShadowNode->getLayoutMetrics()
+ : EmptyLayoutMetrics;
+}
+
+ShadowView::ShadowView(const ShadowNode &shadowNode)
+ : componentName(shadowNode.getComponentName()),
+ componentHandle(shadowNode.getComponentHandle()),
+ tag(shadowNode.getTag()),
+ props(shadowNode.getProps()),
+ eventEmitter(shadowNode.getEventEmitter()),
+ layoutMetrics(layoutMetricsFromShadowNode(shadowNode)),
+ localData(shadowNode.getLocalData()) {}
+
+bool ShadowView::operator==(const ShadowView &rhs) const {
+ return std::tie(
+ this->tag,
+ this->componentName,
+ this->props,
+ this->eventEmitter,
+ this->layoutMetrics,
+ this->localData) ==
+ std::tie(
+ rhs.tag,
+ rhs.componentName,
+ rhs.props,
+ rhs.eventEmitter,
+ rhs.layoutMetrics,
+ rhs.localData);
+}
+
+bool ShadowView::operator!=(const ShadowView &rhs) const {
+ return !(*this == rhs);
+}
+
+bool ShadowViewNodePair::operator==(const ShadowViewNodePair &rhs) const {
+ return &this->shadowNode == &rhs.shadowNode;
+}
+
+bool ShadowViewNodePair::operator!=(const ShadowViewNodePair &rhs) const {
+ return !(*this == rhs);
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/mounting/ShadowView.h

@@ -0,0 +1,81 @@
+// Copyright (c) Facebook, Inc. and its affiliates.
+
+// This source code is licensed under the MIT license found in the
+// LICENSE file in the root directory of this source tree.
+
+#pragma once
+
+#include <folly/Hash.h>
+#include <react/core/LayoutMetrics.h>
+#include <react/core/LocalData.h>
+#include <react/core/Props.h>
+#include <react/core/ReactPrimitives.h>
+#include <react/core/ShadowNode.h>
+#include <react/events/EventEmitter.h>
+
+namespace facebook {
+namespace react {
+
+/*
+ * Describes a view that can be mounted.
+ */
+struct ShadowView final {
+ ShadowView() = default;
+ ShadowView(const ShadowView &shadowView) = default;
+
+ /*
+ * Constructs a `ShadowView` from given `ShadowNode`.
+ */
+ explicit ShadowView(const ShadowNode &shadowNode);
+
+ ShadowView &operator=(const ShadowView &other) = default;
+
+ bool operator==(const ShadowView &rhs) const;
+ bool operator!=(const ShadowView &rhs) const;
+
+ ComponentName componentName = "";
+ ComponentHandle componentHandle = 0;
+ Tag tag = -1; // Tag does not change during the lifetime of a shadow view.
+ SharedProps props = {};
+ SharedEventEmitter eventEmitter = {};
+ LayoutMetrics layoutMetrics = EmptyLayoutMetrics;
+ SharedLocalData localData = {};
+};
+
+/*
+ * Describes pair of a `ShadowView` and a `ShadowNode`.
+ */
+struct ShadowViewNodePair final {
+ const ShadowView shadowView;
+ const ShadowNode &shadowNode;
+
+ /*
+ * The stored pointer to `ShadowNode` represents an indentity of the pair.
+ */
+ bool operator==(const ShadowViewNodePair &rhs) const;
+ bool operator!=(const ShadowViewNodePair &rhs) const;
+};
+
+using ShadowViewNodePairList = std::vector<ShadowViewNodePair>;
+
+} // namespace react
+} // namespace facebook
+
+namespace std {
+
+template <>
+struct hash<facebook::react::ShadowView> {
+ size_t operator()(const facebook::react::ShadowView &shadowView) const {
+ auto seed = size_t{0};
+ folly::hash::hash_combine(
+ seed,
+ shadowView.componentHandle,
+ shadowView.tag,
+ shadowView.props,
+ shadowView.eventEmitter,
+ shadowView.localData);
+ return seed;
+ }
+};
+
+} // namespace std

ReactCommon/fabric/mounting/ShadowViewMutation.cpp

@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include "ShadowViewMutation.h"
+
+namespace facebook {
+namespace react {
+
+ShadowViewMutation ShadowViewMutation::CreateMutation(ShadowView shadowView) {
+ return ShadowViewMutation{
+ .type = Create, .newChildShadowView = shadowView, .index = -1};
+}
+
+ShadowViewMutation ShadowViewMutation::DeleteMutation(ShadowView shadowView) {
+ return {.type = Delete, .oldChildShadowView = shadowView, .index = -1};
+}
+
+ShadowViewMutation ShadowViewMutation::InsertMutation(
+ ShadowView parentShadowView,
+ ShadowView childShadowView,
+ int index) {
+ return {.type = Insert,
+ .parentShadowView = parentShadowView,
+ .newChildShadowView = childShadowView,
+ .index = index};
+}
+
+ShadowViewMutation ShadowViewMutation::RemoveMutation(
+ ShadowView parentShadowView,
+ ShadowView childShadowView,
+ int index) {
+ return {.type = Remove,
+ .parentShadowView = parentShadowView,
+ .oldChildShadowView = childShadowView,
+ .index = index};
+}
+
+ShadowViewMutation ShadowViewMutation::UpdateMutation(
+ ShadowView parentShadowView,
+ ShadowView oldChildShadowView,
+ ShadowView newChildShadowView,
+ int index) {
+ return {.type = Update,
+ .parentShadowView = parentShadowView,
+ .oldChildShadowView = oldChildShadowView,
+ .newChildShadowView = newChildShadowView,
+ .index = index};
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/mounting/ShadowViewMutation.h

@@ -0,0 +1,77 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include <react/mounting/ShadowView.h>
+
+namespace facebook {
+namespace react {
+
+/*
+ * Describes a single native view tree mutation which may contain
+ * pointers to an old shadow view, a new shadow view, a parent shadow view and
+ * final index of inserted or updated view.
+ * Use static methods to instantiate mutations of different types.
+ */
+struct ShadowViewMutation final {
+#pragma mark - Designated Initializers
+
+ /*
+ * Creates and returns an `Create` mutation.
+ */
+ static ShadowViewMutation CreateMutation(ShadowView shadowView);
+
+ /*
+ * Creates and returns an `Delete` mutation.
+ */
+ static ShadowViewMutation DeleteMutation(ShadowView shadowView);
+
+ /*
+ * Creates and returns an `Insert` mutation.
+ */
+ static ShadowViewMutation InsertMutation(
+ ShadowView parentShadowView,
+ ShadowView childShadowView,
+ int index);
+
+ /*
+ * Creates and returns a `Remove` mutation.
+ */
+ static ShadowViewMutation RemoveMutation(
+ ShadowView parentShadowView,
+ ShadowView childShadowView,
+ int index);
+
+ /*
+ * Creates and returns an `Update` mutation.
+ */
+ static ShadowViewMutation UpdateMutation(
+ ShadowView parentShadowView,
+ ShadowView oldChildShadowView,
+ ShadowView newChildShadowView,
+ int index);
+
+#pragma mark - Type
+
+ enum Type { Create, Delete, Insert, Remove, Update };
+
+#pragma mark - Fields
+
+ Type type = {Create};
+ ShadowView parentShadowView = {};
+ ShadowView oldChildShadowView = {};
+ ShadowView newChildShadowView = {};
+ int index = {};
+};
+
+using ShadowViewMutationList = std::vector<ShadowViewMutation>;
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/mounting/tests/MountingTest.cpp

@@ -0,0 +1,14 @@
+/**
+ * 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.
+ */
+
+#include <memory>
+
+#include <gtest/gtest.h>
+
+TEST(MountingTest, testSomething) {
+ // TODO
+}

ReactCommon/fabric/sample/SampleComponentDescriptorFactor.cpp

@@ -1,13 +1,13 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
*/
-#include <fabric/uimanager/ComponentDescriptorFactory.h>
-#include <fabric/uimanager/ComponentDescriptorRegistry.h>
-#include <fabric/uimanager/ContextContainer.h>
+#include <react/uimanager/ComponentDescriptorFactory.h>
+#include <react/uimanager/ComponentDescriptorRegistry.h>
+#include <react/uimanager/ContextContainer.h>
namespace facebook {
namespace react {
@@ -15,12 +15,12 @@
/**
* This is a sample implementation. Each app should provide its own.
*/
-SharedComponentDescriptorRegistry ComponentDescriptorFactory::buildRegistry(
- const SharedEventDispatcher &eventDispatcher,
- const SharedContextContainer &contextContainer
-) {
+ComponentRegistryFactory getDefaultComponentRegistryFactory() {
+ return [](const SharedEventDispatcher &eventDispatcher,
+ const SharedContextContainer &contextContainer) {
auto registry = std::make_shared<ComponentDescriptorRegistry>();
return registry;
+ }
}
} // namespace react

ReactCommon/fabric/textlayoutmanager/BUCK

@@ -1,4 +1,4 @@
-load("//configurations/buck/apple:flag_defs.bzl", "OBJC_ARC_PREPROCESSOR_FLAGS", "get_application_ios_flags", "get_debug_preprocessor_flags")
+load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags")
load(
"//tools/build_defs/oss:rn_defs.bzl",
"ANDROID",
@@ -6,6 +6,7 @@
"fb_xplat_cxx_test",
"get_apple_compiler_flags",
"get_apple_inspector_flags",
+ "react_native_target",
"react_native_xplat_target",
"rn_xplat_cxx_library",
"subdir_glob",
@@ -31,7 +32,7 @@
[
("", "*.h"),
],
- prefix = "fabric/textlayoutmanager",
+ prefix = "react/textlayoutmanager",
),
compiler_flags = [
"-fexceptions",
@@ -39,12 +40,15 @@
"-std=c++14",
"-Wall",
],
+ fbandroid_deps = [
+ react_native_target("jni/react/jni:jni"),
+ ],
fbandroid_exported_headers = subdir_glob(
[
("", "*.h"),
("platform/android", "*.h"),
],
- prefix = "fabric/textlayoutmanager",
+ prefix = "react/textlayoutmanager",
),
fbandroid_headers = subdir_glob(
[
@@ -59,9 +63,6 @@
),
fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
- fbobjc_tests = [
- ":tests",
- ],
force_static = True,
ios_deps = [
],
@@ -69,7 +70,7 @@
[
("platform/ios", "*.h"),
],
- prefix = "fabric/textlayoutmanager",
+ prefix = "react/textlayoutmanager",
),
ios_frameworks = [
"$SDKROOT/System/Library/Frameworks/CoreGraphics.framework",
@@ -94,7 +95,7 @@
"-DLOG_TAG=\"ReactNative\"",
"-DWITH_FBSYSTRACE=1",
],
- tests = [],
+ tests = [":tests"],
visibility = ["PUBLIC"],
deps = [
"xplat//fbsystrace:fbsystrace",
@@ -107,6 +108,7 @@
react_native_xplat_target("fabric/core:core"),
react_native_xplat_target("fabric/debug:debug"),
react_native_xplat_target("fabric/graphics:graphics"),
+ react_native_xplat_target("fabric/uimanager:uimanager"),
],
)
@@ -121,7 +123,7 @@
"-Wall",
],
contacts = ["oncall+react_native@xmail.facebook.com"],
- platforms = APPLE,
+ platforms = (ANDROID, APPLE),
deps = [
"xplat//folly:molly",
"xplat//third-party/gmock:gtest",

ReactCommon/fabric/textlayoutmanager/platform/android/TextLayoutManager.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,14 +7,16 @@
#include "TextLayoutManager.h"
+#include <react/attributedstring/conversions.h>
+#include <react/core/conversions.h>
+#include <react/jni/ReadableNativeMap.h>
+
+using namespace facebook::jni;
+
namespace facebook {
namespace react {
-TextLayoutManager::TextLayoutManager() {
-}
-
-TextLayoutManager::~TextLayoutManager() {
-}
+TextLayoutManager::~TextLayoutManager() {}
void *TextLayoutManager::getNativeTextLayoutManager() const {
return self_;
@@ -23,10 +25,38 @@
Size TextLayoutManager::measure(
AttributedString attributedString,
ParagraphAttributes paragraphAttributes,
- LayoutConstraints layoutConstraints
-) const {
- // Not implemented.
- return {};
+ LayoutConstraints layoutConstraints) const {
+ const jni::global_ref<jobject> &fabricUIManager =
+ contextContainer_->getInstance<jni::global_ref<jobject>>(
+ "FabricUIManager");
+
+ static auto measure =
+ jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
+ ->getMethod<jlong(
+ jstring,
+ ReadableNativeMap::javaobject,
+ ReadableNativeMap::javaobject,
+ jint,
+ jint,
+ jint,
+ jint)>("measure");
+
+ auto minimumSize = layoutConstraints.minimumSize;
+ auto maximumSize = layoutConstraints.maximumSize;
+ int minWidth = (int)minimumSize.width;
+ int minHeight = (int)minimumSize.height;
+ int maxWidth = (int)maximumSize.width;
+ int maxHeight = (int)maximumSize.height;
+ local_ref<JString> componentName = make_jstring("RCTText");
+ return yogaMeassureToSize(measure(
+ fabricUIManager,
+ componentName.get(),
+ ReadableNativeMap::newObjectCxxArgs(toDynamic(attributedString)).get(),
+ ReadableNativeMap::newObjectCxxArgs(toDynamic(paragraphAttributes)).get(),
+ minWidth,
+ maxWidth,
+ minHeight,
+ maxHeight));
}
} // namespace react

ReactCommon/fabric/textlayoutmanager/platform/android/TextLayoutManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,9 +9,10 @@
#include <memory>
-#include <fabric/attributedstring/AttributedString.h>
-#include <fabric/attributedstring/ParagraphAttributes.h>
-#include <fabric/core/LayoutConstraints.h>
+#include <react/attributedstring/AttributedString.h>
+#include <react/attributedstring/ParagraphAttributes.h>
+#include <react/core/LayoutConstraints.h>
+#include <react/uimanager/ContextContainer.h>
namespace facebook {
namespace react {
@@ -24,10 +25,9 @@
* Cross platform facade for Android-specific TextLayoutManager.
*/
class TextLayoutManager {
-
-public:
-
- TextLayoutManager();
+ public:
+ TextLayoutManager(const SharedContextContainer &contextContainer)
+ : contextContainer_(contextContainer){};
~TextLayoutManager();
/*
@@ -36,8 +36,7 @@
Size measure(
AttributedString attributedString,
ParagraphAttributes paragraphAttributes,
- LayoutConstraints layoutConstraints
- ) const;
+ LayoutConstraints layoutConstraints) const;
/*
* Returns an opaque pointer to platform-specific TextLayoutManager.
@@ -45,9 +44,10 @@
*/
void *getNativeTextLayoutManager() const;
-private:
-
+ private:
void *self_;
+
+ SharedContextContainer contextContainer_;
};
} // namespace react

ReactCommon/fabric/textlayoutmanager/platform/ios/NSTextStorage+FontScaling.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactCommon/fabric/textlayoutmanager/platform/ios/NSTextStorage+FontScaling.m

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -17,9 +17,8 @@
- (void)scaleFontSizeToFitSize:(CGSize)size
minimumFontSize:(CGFloat)minimumFontSize
- maximumFontSize:(CGFloat)maximumFontSize
-{
- CGFloat bottomRatio = 1.0/128.0;
+ maximumFontSize:(CGFloat)maximumFontSize {
+ CGFloat bottomRatio = 1.0 / 128.0;
CGFloat topRatio = 128.0;
CGFloat ratio = 1.0;
@@ -32,13 +31,11 @@
minimumFontSize:minimumFontSize
maximumFontSize:maximumFontSize];
- RCTTextSizeComparisonOptions comparsion =
- [self compareToSize:size thresholdRatio:0.01];
+ RCTTextSizeComparisonOptions comparsion = [self compareToSize:size
+ thresholdRatio:0.01];
- if (
- (comparsion & RCTTextSizeComparisonWithinRange) &&
- (comparsion & RCTTextSizeComparisonSmaller)
- ) {
+ if ((comparsion & RCTTextSizeComparisonWithinRange) &&
+ (comparsion & RCTTextSizeComparisonSmaller)) {
return;
} else if (comparsion & RCTTextSizeComparisonSmaller) {
bottomRatio = ratio;
@@ -50,11 +47,9 @@
ratio = (topRatio + bottomRatio) / 2.0;
CGFloat kRatioThreshold = 0.005;
- if (
- ABS(topRatio - bottomRatio) < kRatioThreshold ||
+ if (ABS(topRatio - bottomRatio) < kRatioThreshold ||
ABS(topRatio - ratio) < kRatioThreshold ||
- ABS(bottomRatio - ratio) < kRatioThreshold
- ) {
+ ABS(bottomRatio - ratio) < kRatioThreshold) {
[self replaceCharactersInRange:(NSRange){0, self.length}
withAttributedString:originalAttributedString];
@@ -69,9 +64,8 @@
}
}
-
-- (RCTTextSizeComparisonOptions)compareToSize:(CGSize)size thresholdRatio:(CGFloat)thresholdRatio
-{
+- (RCTTextSizeComparisonOptions)compareToSize:(CGSize)size
+ thresholdRatio:(CGFloat)thresholdRatio {
NSLayoutManager *layoutManager = self.layoutManagers.firstObject;
NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
@@ -79,18 +73,19 @@
// Does it fit the text container?
NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer];
- NSRange truncatedGlyphRange = [layoutManager truncatedGlyphRangeInLineFragmentForGlyphAtIndex:glyphRange.length - 1];
+ NSRange truncatedGlyphRange = [layoutManager
+ truncatedGlyphRangeInLineFragmentForGlyphAtIndex:glyphRange.length - 1];
if (truncatedGlyphRange.location != NSNotFound) {
return RCTTextSizeComparisonLarger;
}
- CGSize measuredSize = [layoutManager usedRectForTextContainer:textContainer].size;
+ CGSize measuredSize =
+ [layoutManager usedRectForTextContainer:textContainer].size;
// Does it fit the size?
BOOL fitsSize =
- size.width >= measuredSize.width &&
- size.height >= measuredSize.height;
+ size.width >= measuredSize.width && size.height >= measuredSize.height;
CGSize thresholdSize = (CGSize){
size.width * thresholdRatio,
@@ -99,7 +94,8 @@
RCTTextSizeComparisonOptions result = 0;
- result |= (fitsSize) ? RCTTextSizeComparisonSmaller : RCTTextSizeComparisonLarger;
+ result |=
+ (fitsSize) ? RCTTextSizeComparisonSmaller : RCTTextSizeComparisonLarger;
if (ABS(measuredSize.width - size.width) < thresholdSize.width) {
result = result | RCTTextSizeComparisonWithinRange;
@@ -110,26 +106,28 @@
- (void)scaleFontSizeWithRatio:(CGFloat)ratio
minimumFontSize:(CGFloat)minimumFontSize
- maximumFontSize:(CGFloat)maximumFontSize
-{
+ maximumFontSize:(CGFloat)maximumFontSize {
[self beginEditing];
- [self enumerateAttribute:NSFontAttributeName
+ [self
+ enumerateAttribute:NSFontAttributeName
inRange:(NSRange){0, self.length}
- options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
- usingBlock:
- ^(UIFont *_Nullable font, NSRange range, BOOL *_Nonnull stop) {
+ options:
+ NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
+ usingBlock:^(
+ UIFont *_Nullable font, NSRange range, BOOL *_Nonnull stop) {
if (!font) {
return;
}
- CGFloat fontSize = MAX(MIN(font.pointSize * ratio, maximumFontSize), minimumFontSize);
+ CGFloat fontSize =
+ MAX(MIN(font.pointSize * ratio, maximumFontSize),
+ minimumFontSize);
[self addAttribute:NSFontAttributeName
value:[font fontWithSize:fontSize]
range:range];
- }
- ];
+ }];
[self endEditing];
}

ReactCommon/fabric/textlayoutmanager/platform/ios/RCTAttributedTextUtils.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,17 +7,23 @@
#import <UIKit/UIKit.h>
-#include <fabric/attributedstring/AttributedString.h>
-#include <fabric/attributedstring/TextAttributes.h>
+#include <react/attributedstring/AttributedString.h>
+#include <react/attributedstring/TextAttributes.h>
NS_ASSUME_NONNULL_BEGIN
-NSString *const RCTAttributedStringIsHighlightedAttributeName = @"IsHighlighted";
-NSString *const RCTAttributedStringReactTagAttributeName = @"ReactTag";
+NSString *const RCTAttributedStringIsHighlightedAttributeName =
+ @"IsHighlighted";
+NSString *const RCTAttributedStringEventEmitterKey = @"EventEmitter";
/**
* Constructs ready-to-render `NSAttributedString` by given `AttributedString`.
*/
-NSAttributedString *RCTNSAttributedStringFromAttributedString(const facebook::react::AttributedString &attributedString);
+NSAttributedString *RCTNSAttributedStringFromAttributedString(
+ const facebook::react::AttributedString &attributedString);
+
+@interface RCTWeakEventEmitterWrapper : NSObject
+@property(nonatomic, assign) facebook::react::SharedEventEmitter eventEmitter;
+@end
NS_ASSUME_NONNULL_END

ReactCommon/fabric/textlayoutmanager/platform/ios/RCTAttributedTextUtils.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,53 +7,95 @@
#import "RCTAttributedTextUtils.h"
-#include <fabric/core/LayoutableShadowNode.h>
-#include <fabric/textlayoutmanager/RCTFontProperties.h>
-#include <fabric/textlayoutmanager/RCTFontUtils.h>
-#include <fabric/textlayoutmanager/RCTTextPrimitivesConversions.h>
+#include <react/core/LayoutableShadowNode.h>
+#include <react/textlayoutmanager/RCTFontProperties.h>
+#include <react/textlayoutmanager/RCTFontUtils.h>
+#include <react/textlayoutmanager/RCTTextPrimitivesConversions.h>
-inline static UIFont *RCTEffectiveFontFromTextAttributes(const TextAttributes &textAttributes) {
- NSString *fontFamily = [NSString stringWithCString:textAttributes.fontFamily.c_str()
+using namespace facebook::react;
+
+@implementation RCTWeakEventEmitterWrapper {
+ std::weak_ptr<const EventEmitter> _weakEventEmitter;
+}
+
+- (void)setEventEmitter:(SharedEventEmitter)eventEmitter {
+ _weakEventEmitter = eventEmitter;
+}
+
+- (SharedEventEmitter)eventEmitter {
+ return _weakEventEmitter.lock();
+}
+
+- (void)dealloc {
+ _weakEventEmitter.reset();
+}
+
+@end
+
+inline static UIFont *RCTEffectiveFontFromTextAttributes(
+ const TextAttributes &textAttributes) {
+ NSString *fontFamily =
+ [NSString stringWithCString:textAttributes.fontFamily.c_str()
encoding:NSUTF8StringEncoding];
RCTFontProperties fontProperties;
fontProperties.family = fontFamily;
fontProperties.size = textAttributes.fontSize;
- fontProperties.style = textAttributes.fontStyle.hasValue() ? RCTFontStyleFromFontStyle(textAttributes.fontStyle.value()) : RCTFontStyleUndefined;
- fontProperties.variant = textAttributes.fontVariant.hasValue() ? RCTFontVariantFromFontVariant(textAttributes.fontVariant.value()) : RCTFontVariantDefault;
- fontProperties.weight = textAttributes.fontWeight.hasValue() ? CGFloat(textAttributes.fontWeight.value()) : NAN;
+ fontProperties.style = textAttributes.fontStyle.hasValue()
+ ? RCTFontStyleFromFontStyle(textAttributes.fontStyle.value())
+ : RCTFontStyleUndefined;
+ fontProperties.variant = textAttributes.fontVariant.hasValue()
+ ? RCTFontVariantFromFontVariant(textAttributes.fontVariant.value())
+ : RCTFontVariantDefault;
+ fontProperties.weight = textAttributes.fontWeight.hasValue()
+ ? CGFloat(textAttributes.fontWeight.value())
+ : NAN;
fontProperties.sizeMultiplier = textAttributes.fontSizeMultiplier;
return RCTFontWithFontProperties(fontProperties);
}
-inline static CGFloat RCTEffectiveFontSizeMultiplierFromTextAttributes(const TextAttributes &textAttributes) {
- return textAttributes.allowFontScaling.value_or(true) && !isnan(textAttributes.fontSizeMultiplier) ? textAttributes.fontSizeMultiplier : 1.0;
+inline static CGFloat RCTEffectiveFontSizeMultiplierFromTextAttributes(
+ const TextAttributes &textAttributes) {
+ return textAttributes.allowFontScaling.value_or(true) &&
+ !isnan(textAttributes.fontSizeMultiplier)
+ ? textAttributes.fontSizeMultiplier
+ : 1.0;
}
-inline static UIColor *RCTEffectiveForegroundColorFromTextAttributes(const TextAttributes &textAttributes) {
- UIColor *effectiveForegroundColor = RCTUIColorFromSharedColor(textAttributes.foregroundColor) ?: [UIColor blackColor];
+inline static UIColor *RCTEffectiveForegroundColorFromTextAttributes(
+ const TextAttributes &textAttributes) {
+ UIColor *effectiveForegroundColor =
+ RCTUIColorFromSharedColor(textAttributes.foregroundColor)
+ ?: [UIColor blackColor];
if (!isnan(textAttributes.opacity)) {
- effectiveForegroundColor =
- [effectiveForegroundColor colorWithAlphaComponent:CGColorGetAlpha(effectiveForegroundColor.CGColor) * textAttributes.opacity];
+ effectiveForegroundColor = [effectiveForegroundColor
+ colorWithAlphaComponent:CGColorGetAlpha(
+ effectiveForegroundColor.CGColor) *
+ textAttributes.opacity];
}
return effectiveForegroundColor;
}
-inline static UIColor *RCTEffectiveBackgroundColorFromTextAttributes(const TextAttributes &textAttributes) {
- UIColor *effectiveBackgroundColor = RCTUIColorFromSharedColor(textAttributes.backgroundColor);
+inline static UIColor *RCTEffectiveBackgroundColorFromTextAttributes(
+ const TextAttributes &textAttributes) {
+ UIColor *effectiveBackgroundColor =
+ RCTUIColorFromSharedColor(textAttributes.backgroundColor);
if (effectiveBackgroundColor && !isnan(textAttributes.opacity)) {
- effectiveBackgroundColor =
- [effectiveBackgroundColor colorWithAlphaComponent:CGColorGetAlpha(effectiveBackgroundColor.CGColor) * textAttributes.opacity];
+ effectiveBackgroundColor = [effectiveBackgroundColor
+ colorWithAlphaComponent:CGColorGetAlpha(
+ effectiveBackgroundColor.CGColor) *
+ textAttributes.opacity];
}
return effectiveBackgroundColor ?: [UIColor clearColor];
}
-static NSDictionary<NSAttributedStringKey, id> *RCTNSTextAttributesFromTextAttributes(const TextAttributes &textAttributes) {
+static NSDictionary<NSAttributedStringKey, id> *
+RCTNSTextAttributesFromTextAttributes(const TextAttributes &textAttributes) {
NSMutableDictionary<NSAttributedStringKey, id> *attributes =
[NSMutableDictionary dictionaryWithCapacity:10];
@@ -64,14 +106,16 @@
}
// Colors
- UIColor *effectiveForegroundColor = RCTEffectiveForegroundColorFromTextAttributes(textAttributes);
+ UIColor *effectiveForegroundColor =
+ RCTEffectiveForegroundColorFromTextAttributes(textAttributes);
if (textAttributes.foregroundColor || !isnan(textAttributes.opacity)) {
attributes[NSForegroundColorAttributeName] = effectiveForegroundColor;
}
if (textAttributes.backgroundColor || !isnan(textAttributes.opacity)) {
- attributes[NSBackgroundColorAttributeName] = RCTEffectiveBackgroundColorFromTextAttributes(textAttributes);
+ attributes[NSBackgroundColorAttributeName] =
+ RCTEffectiveBackgroundColorFromTextAttributes(textAttributes);
}
// Kerning
@@ -83,8 +127,10 @@
NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
BOOL isParagraphStyleUsed = NO;
if (textAttributes.alignment.hasValue()) {
- TextAlignment textAlignment = textAttributes.alignment.value_or(TextAlignment::Natural);
- if (textAttributes.layoutDirection.value_or(LayoutDirection::LeftToRight) == LayoutDirection::RightToLeft) {
+ TextAlignment textAlignment =
+ textAttributes.alignment.value_or(TextAlignment::Natural);
+ if (textAttributes.layoutDirection.value_or(LayoutDirection::LeftToRight) ==
+ LayoutDirection::RightToLeft) {
if (textAlignment == TextAlignment::Right) {
textAlignment = TextAlignment::Left;
} else if (textAlignment == TextAlignment::Left) {
@@ -99,13 +145,14 @@
if (textAttributes.baseWritingDirection.hasValue()) {
paragraphStyle.baseWritingDirection =
- RCTNSWritingDirectionFromWritingDirection(textAttributes.baseWritingDirection.value());
+ RCTNSWritingDirectionFromWritingDirection(
+ textAttributes.baseWritingDirection.value());
isParagraphStyleUsed = YES;
}
if (!isnan(textAttributes.lineHeight)) {
- CGFloat lineHeight =
- textAttributes.lineHeight * RCTEffectiveFontSizeMultiplierFromTextAttributes(textAttributes);
+ CGFloat lineHeight = textAttributes.lineHeight *
+ RCTEffectiveFontSizeMultiplierFromTextAttributes(textAttributes);
paragraphStyle.minimumLineHeight = lineHeight;
paragraphStyle.maximumLineHeight = lineHeight;
isParagraphStyleUsed = YES;
@@ -116,21 +163,23 @@
}
// Decoration
- if (textAttributes.textDecorationLineType.value_or(TextDecorationLineType::None) != TextDecorationLineType::None) {
+ if (textAttributes.textDecorationLineType.value_or(
+ TextDecorationLineType::None) != TextDecorationLineType::None) {
auto textDecorationLineType = textAttributes.textDecorationLineType.value();
- NSUnderlineStyle style =
- RCTNSUnderlineStyleFromStyleAndPattern(
- textAttributes.textDecorationLineStyle.value_or(TextDecorationLineStyle::Single),
- textAttributes.textDecorationLinePattern.value_or(TextDecorationLinePattern::Solid)
- );
+ NSUnderlineStyle style = RCTNSUnderlineStyleFromStyleAndPattern(
+ textAttributes.textDecorationLineStyle.value_or(
+ TextDecorationLineStyle::Single),
+ textAttributes.textDecorationLinePattern.value_or(
+ TextDecorationLinePattern::Solid));
- UIColor *textDecorationColor = RCTUIColorFromSharedColor(textAttributes.textDecorationColor);
+ UIColor *textDecorationColor =
+ RCTUIColorFromSharedColor(textAttributes.textDecorationColor);
// Underline
if (textDecorationLineType == TextDecorationLineType::Underline ||
- textDecorationLineType == TextDecorationLineType::UnderlineStrikethrough) {
-
+ textDecorationLineType ==
+ TextDecorationLineType::UnderlineStrikethrough) {
attributes[NSUnderlineStyleAttributeName] = @(style);
if (textDecorationColor) {
@@ -140,8 +189,8 @@
// Strikethrough
if (textDecorationLineType == TextDecorationLineType::Strikethrough ||
- textDecorationLineType == TextDecorationLineType::UnderlineStrikethrough) {
-
+ textDecorationLineType ==
+ TextDecorationLineType::UnderlineStrikethrough) {
attributes[NSStrikethroughStyleAttributeName] = @(style);
if (textDecorationColor) {
@@ -154,9 +203,11 @@
if (textAttributes.textShadowOffset.hasValue()) {
auto textShadowOffset = textAttributes.textShadowOffset.value();
NSShadow *shadow = [NSShadow new];
- shadow.shadowOffset = CGSize {textShadowOffset.width, textShadowOffset.height};
+ shadow.shadowOffset =
+ CGSize{textShadowOffset.width, textShadowOffset.height};
shadow.shadowBlurRadius = textAttributes.textShadowRadius;
- shadow.shadowColor = RCTUIColorFromSharedColor(textAttributes.textShadowColor);
+ shadow.shadowColor =
+ RCTUIColorFromSharedColor(textAttributes.textShadowColor);
attributes[NSShadowAttributeName] = shadow;
}
@@ -168,57 +219,59 @@
return [attributes copy];
}
-NSAttributedString *RCTNSAttributedStringFromAttributedString(const AttributedString &attributedString) {
- NSMutableAttributedString *nsAttributedString = [[NSMutableAttributedString alloc] init];
+NSAttributedString *RCTNSAttributedStringFromAttributedString(
+ const AttributedString &attributedString) {
+ NSMutableAttributedString *nsAttributedString =
+ [[NSMutableAttributedString alloc] init];
[nsAttributedString beginEditing];
for (auto fragment : attributedString.getFragments()) {
NSAttributedString *nsAttributedStringFragment;
- auto layoutableShadowNode =
- std::dynamic_pointer_cast<const LayoutableShadowNode>(fragment.shadowNode);
+ auto layoutMetrics = fragment.shadowView.layoutMetrics;
- if (layoutableShadowNode) {
- auto layoutMetrics = layoutableShadowNode->getLayoutMetrics();
- CGRect bounds = {
- .origin = {
- .x = layoutMetrics.frame.origin.x,
- .y = layoutMetrics.frame.origin.y
- },
- .size = {
- .width = layoutMetrics.frame.size.width,
- .height = layoutMetrics.frame.size.height
- }
- };
+ if (layoutMetrics != EmptyLayoutMetrics) {
+ CGRect bounds = {.origin = {.x = layoutMetrics.frame.origin.x,
+ .y = layoutMetrics.frame.origin.y},
+ .size = {.width = layoutMetrics.frame.size.width,
+ .height = layoutMetrics.frame.size.height}};
NSTextAttachment *attachment = [NSTextAttachment new];
attachment.bounds = bounds;
- nsAttributedStringFragment = [NSAttributedString attributedStringWithAttachment:attachment];
+ nsAttributedStringFragment =
+ [NSAttributedString attributedStringWithAttachment:attachment];
} else {
- NSString *string =
- [NSString stringWithCString:fragment.string.c_str()
+ NSString *string = [NSString stringWithCString:fragment.string.c_str()
encoding:NSUTF8StringEncoding];
- nsAttributedStringFragment =
- [[NSAttributedString alloc] initWithString:string
- attributes:RCTNSTextAttributesFromTextAttributes(fragment.textAttributes)];
+ nsAttributedStringFragment = [[NSAttributedString alloc]
+ initWithString:string
+ attributes:RCTNSTextAttributesFromTextAttributes(
+ fragment.textAttributes)];
}
NSMutableAttributedString *nsMutableAttributedStringFragment =
- [[NSMutableAttributedString alloc] initWithAttributedString:nsAttributedStringFragment];
+ [[NSMutableAttributedString alloc]
+ initWithAttributedString:nsAttributedStringFragment];
+
+ if (fragment.parentShadowView.componentHandle) {
+ RCTWeakEventEmitterWrapper *eventEmitterWrapper =
+ [RCTWeakEventEmitterWrapper new];
+ eventEmitterWrapper.eventEmitter = fragment.parentShadowView.eventEmitter;
- if (fragment.shadowNode) {
- NSDictionary<NSAttributedStringKey, id> *additionalTextAttributes = @{
- RCTAttributedStringReactTagAttributeName: @(fragment.shadowNode->getTag())
- };
+ NSDictionary<NSAttributedStringKey, id> *additionalTextAttributes =
+ @{RCTAttributedStringEventEmitterKey : eventEmitterWrapper};
- [nsMutableAttributedStringFragment setAttributes:additionalTextAttributes
- range:NSMakeRange(0, nsMutableAttributedStringFragment.length)];
+ [nsMutableAttributedStringFragment
+ addAttributes:additionalTextAttributes
+ range:NSMakeRange(
+ 0, nsMutableAttributedStringFragment.length)];
}
- [nsAttributedString appendAttributedString:nsMutableAttributedStringFragment];
+ [nsAttributedString
+ appendAttributedString:nsMutableAttributedStringFragment];
}
[nsAttributedString endEditing];

ReactCommon/fabric/textlayoutmanager/platform/ios/RCTFontProperties.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.

ReactCommon/fabric/textlayoutmanager/platform/ios/RCTFontUtils.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,7 +7,7 @@
#import <UIKit/UIKit.h>
-#import <fabric/textlayoutmanager/RCTFontProperties.h>
+#import <react/textlayoutmanager/RCTFontProperties.h>
NS_ASSUME_NONNULL_BEGIN

ReactCommon/fabric/textlayoutmanager/platform/ios/RCTFontUtils.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -26,24 +26,39 @@
return defaultFontProperties;
}
-static RCTFontProperties RCTResolveFontProperties(RCTFontProperties fontProperties) {
+static RCTFontProperties RCTResolveFontProperties(
+ RCTFontProperties fontProperties) {
RCTFontProperties defaultFontProperties = RCTDefaultFontProperties();
- fontProperties.family = fontProperties.family.length && ![fontProperties.family isEqualToString:@"System"] ? fontProperties.family : defaultFontProperties.family;
- fontProperties.size = !isnan(fontProperties.size) ? fontProperties.size : defaultFontProperties.size;
- fontProperties.weight = !isnan(fontProperties.weight) ? fontProperties.weight : defaultFontProperties.weight;
- fontProperties.style = fontProperties.style != RCTFontStyleUndefined ? fontProperties.style : defaultFontProperties.style;
- fontProperties.variant = fontProperties.variant != RCTFontVariantUndefined ? fontProperties.variant : defaultFontProperties.variant;
+ fontProperties.family = fontProperties.family.length &&
+ ![fontProperties.family isEqualToString:@"System"]
+ ? fontProperties.family
+ : defaultFontProperties.family;
+ fontProperties.size = !isnan(fontProperties.size)
+ ? fontProperties.size
+ : defaultFontProperties.size;
+ fontProperties.weight = !isnan(fontProperties.weight)
+ ? fontProperties.weight
+ : defaultFontProperties.weight;
+ fontProperties.style = fontProperties.style != RCTFontStyleUndefined
+ ? fontProperties.style
+ : defaultFontProperties.style;
+ fontProperties.variant = fontProperties.variant != RCTFontVariantUndefined
+ ? fontProperties.variant
+ : defaultFontProperties.variant;
return fontProperties;
}
static UIFontWeight RCTGetFontWeight(UIFont *font) {
- NSDictionary *traits = [font.fontDescriptor objectForKey:UIFontDescriptorTraitsAttribute];
+ NSDictionary *traits =
+ [font.fontDescriptor objectForKey:UIFontDescriptorTraitsAttribute];
return [traits[UIFontWeightTrait] doubleValue];
}
static RCTFontStyle RCTGetFontStyle(UIFont *font) {
- NSDictionary *traits = [font.fontDescriptor objectForKey:UIFontDescriptorTraitsAttribute];
- UIFontDescriptorSymbolicTraits symbolicTraits = [traits[UIFontSymbolicTrait] unsignedIntValue];
+ NSDictionary *traits =
+ [font.fontDescriptor objectForKey:UIFontDescriptorTraitsAttribute];
+ UIFontDescriptorSymbolicTraits symbolicTraits =
+ [traits[UIFontSymbolicTrait] unsignedIntValue];
if (symbolicTraits & UIFontDescriptorTraitItalic) {
return RCTFontStyleItalic;
}
@@ -61,8 +76,7 @@
// and UIKit uses the same numerical notation, we have to use exact
// `UIFontWeight*` constants to make it work properly (because
// float values comparison is tricky).
- static UIFontWeight weights[] = {
- /* ~100 */ UIFontWeightUltraLight,
+ static UIFontWeight weights[] = {/* ~100 */ UIFontWeightUltraLight,
/* ~200 */ UIFontWeightThin,
/* ~300 */ UIFontWeightLight,
/* ~400 */ UIFontWeightRegular,
@@ -70,16 +84,18 @@
/* ~600 */ UIFontWeightSemibold,
/* ~700 */ UIFontWeightBold,
/* ~800 */ UIFontWeightHeavy,
- /* ~900 */ UIFontWeightBlack
- };
+ /* ~900 */ UIFontWeightBlack};
return weights[std::llround((fontWeight / 100) - 1)];
}
-static UIFont *RCTDefaultFontWithFontProperties(RCTFontProperties fontProperties) {
+static UIFont *RCTDefaultFontWithFontProperties(
+ RCTFontProperties fontProperties) {
static NSCache *fontCache;
static std::mutex fontCacheMutex;
- NSString *cacheKey = [NSString stringWithFormat:@"%.1f/%.2f", fontProperties.size, fontProperties.weight];
+ NSString *cacheKey = [NSString stringWithFormat:@"%.1f/%.2f",
+ fontProperties.size,
+ fontProperties.weight];
UIFont *font;
{
@@ -91,17 +107,21 @@
}
if (!font) {
- font = [UIFont systemFontOfSize:fontProperties.size
+ font = [UIFont
+ systemFontOfSize:fontProperties.size
weight:RCTUIFontWeightFromFloat(fontProperties.weight)];
if (fontProperties.variant == RCTFontStyleItalic) {
UIFontDescriptor *fontDescriptor = [font fontDescriptor];
- UIFontDescriptorSymbolicTraits symbolicTraits = fontDescriptor.symbolicTraits;
+ UIFontDescriptorSymbolicTraits symbolicTraits =
+ fontDescriptor.symbolicTraits;
symbolicTraits |= UIFontDescriptorTraitItalic;
- fontDescriptor = [fontDescriptor fontDescriptorWithSymbolicTraits:symbolicTraits];
- font = [UIFont fontWithDescriptor:fontDescriptor size:fontProperties.size];
+ fontDescriptor =
+ [fontDescriptor fontDescriptorWithSymbolicTraits:symbolicTraits];
+ font = [UIFont fontWithDescriptor:fontDescriptor
+ size:fontProperties.size];
}
{
@@ -117,7 +137,8 @@
RCTFontProperties defaultFontProperties = RCTDefaultFontProperties();
fontProperties = RCTResolveFontProperties(fontProperties);
- CGFloat effectiveFontSize = fontProperties.sizeMultiplier * fontProperties.size;
+ CGFloat effectiveFontSize =
+ fontProperties.sizeMultiplier * fontProperties.size;
UIFont *font;
if ([fontProperties.family isEqualToString:defaultFontProperties.family]) {
// Handle system font as special case. This ensures that we preserve
@@ -134,7 +155,9 @@
if (!font) {
// Failback to system font.
- font = [UIFont systemFontOfSize:effectiveFontSize weight:RCTUIFontWeightFromFloat(fontProperties.weight)];
+ font = [UIFont
+ systemFontOfSize:effectiveFontSize
+ weight:RCTUIFontWeightFromFloat(fontProperties.weight)];
}
} else {
// Get the closest font that matches the given weight for the fontFamily
@@ -147,15 +170,17 @@
}
CGFloat testWeight = RCTGetFontWeight(fontMatch);
- if (ABS(testWeight - fontProperties.weight) < ABS(closestWeight - fontProperties.weight)) {
+ if (ABS(testWeight - fontProperties.weight) <
+ ABS(closestWeight - fontProperties.weight)) {
font = fontMatch;
closestWeight = testWeight;
}
}
if (!font) {
- // If we still don't have a match at least return the first font in the fontFamily
- // This is to support built-in font Zapfino and other custom single font families like Impact
+ // If we still don't have a match at least return the first font in the
+ // fontFamily This is to support built-in font Zapfino and other custom
+ // single font families like Impact
font = [UIFont fontWithName:fontNames[0] size:effectiveFontSize];
}
}
@@ -165,7 +190,9 @@
if (fontProperties.variant != RCTFontVariantDefault) {
NSArray *fontFeatures = RCTFontFeatures(fontProperties.variant);
UIFontDescriptor *fontDescriptor =
- [font.fontDescriptor fontDescriptorByAddingAttributes:@{UIFontDescriptorFeatureSettingsAttribute: fontFeatures}];
+ [font.fontDescriptor fontDescriptorByAddingAttributes:@{
+ UIFontDescriptorFeatureSettingsAttribute : fontFeatures
+ }];
font = [UIFont fontWithDescriptor:fontDescriptor size:effectiveFontSize];
}

ReactCommon/fabric/textlayoutmanager/platform/ios/RCTTextLayoutManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,10 +7,10 @@
#import <UIKit/UIKit.h>
-#import <fabric/core/LayoutConstraints.h>
-#import <fabric/graphics/Geometry.h>
-#import <fabric/attributedstring/AttributedString.h>
-#import <fabric/attributedstring/ParagraphAttributes.h>
+#import <react/attributedstring/AttributedString.h>
+#import <react/attributedstring/ParagraphAttributes.h>
+#import <react/core/LayoutConstraints.h>
+#import <react/graphics/Geometry.h>
NS_ASSUME_NONNULL_BEGIN
@@ -19,14 +19,27 @@
*/
@interface RCTTextLayoutManager : NSObject
-- (facebook::react::Size)measureWithAttributedString:(facebook::react::AttributedString)attributedString
- paragraphAttributes:(facebook::react::ParagraphAttributes)paragraphAttributes
- layoutConstraints:(facebook::react::LayoutConstraints)layoutConstraints;
+- (facebook::react::Size)
+ measureWithAttributedString:
+ (facebook::react::AttributedString)attributedString
+ paragraphAttributes:
+ (facebook::react::ParagraphAttributes)paragraphAttributes
+ layoutConstraints:
+ (facebook::react::LayoutConstraints)layoutConstraints;
- (void)drawAttributedString:(facebook::react::AttributedString)attributedString
- paragraphAttributes:(facebook::react::ParagraphAttributes)paragraphAttributes
+ paragraphAttributes:
+ (facebook::react::ParagraphAttributes)paragraphAttributes
frame:(CGRect)frame;
+- (facebook::react::SharedEventEmitter)
+ getEventEmitterWithAttributeString:
+ (facebook::react::AttributedString)attributedString
+ paragraphAttributes:
+ (facebook::react::ParagraphAttributes)paragraphAttributes
+ frame:(CGRect)frame
+ atPoint:(CGPoint)point;
+
@end
NS_ASSUME_NONNULL_END

ReactCommon/fabric/textlayoutmanager/platform/ios/RCTTextLayoutManager.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -14,22 +14,29 @@
@implementation RCTTextLayoutManager
-static NSLineBreakMode RCTNSLineBreakModeFromWritingDirection(EllipsizeMode ellipsizeMode) {
+static NSLineBreakMode RCTNSLineBreakModeFromWritingDirection(
+ EllipsizeMode ellipsizeMode) {
switch (ellipsizeMode) {
- case EllipsizeMode::Clip: return NSLineBreakByClipping;
- case EllipsizeMode::Head: return NSLineBreakByTruncatingHead;
- case EllipsizeMode::Tail: return NSLineBreakByTruncatingTail;
- case EllipsizeMode::Middle: return NSLineBreakByTruncatingMiddle;
+ case EllipsizeMode::Clip:
+ return NSLineBreakByClipping;
+ case EllipsizeMode::Head:
+ return NSLineBreakByTruncatingHead;
+ case EllipsizeMode::Tail:
+ return NSLineBreakByTruncatingTail;
+ case EllipsizeMode::Middle:
+ return NSLineBreakByTruncatingMiddle;
}
}
-- (facebook::react::Size)measureWithAttributedString:(AttributedString)attributedString
+- (facebook::react::Size)
+ measureWithAttributedString:(AttributedString)attributedString
paragraphAttributes:(ParagraphAttributes)paragraphAttributes
- layoutConstraints:(LayoutConstraints)layoutConstraints
-{
- CGSize maximumSize = CGSize {layoutConstraints.maximumSize.width, layoutConstraints.maximumSize.height};
+ layoutConstraints:(LayoutConstraints)layoutConstraints {
+ CGSize maximumSize = CGSize{layoutConstraints.maximumSize.width,
+ layoutConstraints.maximumSize.height};
NSTextStorage *textStorage =
- [self _textStorageAndLayoutManagerWithAttributesString:RCTNSAttributedStringFromAttributedString(attributedString)
+ [self _textStorageAndLayoutManagerWithAttributesString:
+ RCTNSAttributedStringFromAttributedString(attributedString)
paragraphAttributes:paragraphAttributes
size:maximumSize];
@@ -39,20 +46,18 @@
CGSize size = [layoutManager usedRectForTextContainer:textContainer].size;
- size = (CGSize){
- MIN(size.width, maximumSize.width),
- MIN(size.height, maximumSize.height)
- };
+ size = (CGSize){MIN(size.width, maximumSize.width),
+ MIN(size.height, maximumSize.height)};
- return facebook::react::Size {size.width, size.height};
+ return facebook::react::Size{size.width, size.height};
}
- (void)drawAttributedString:(AttributedString)attributedString
paragraphAttributes:(ParagraphAttributes)paragraphAttributes
- frame:(CGRect)frame
-{
+ frame:(CGRect)frame {
NSTextStorage *textStorage =
- [self _textStorageAndLayoutManagerWithAttributesString:RCTNSAttributedStringFromAttributedString(attributedString)
+ [self _textStorageAndLayoutManagerWithAttributesString:
+ RCTNSAttributedStringFromAttributedString(attributedString)
paragraphAttributes:paragraphAttributes
size:frame.size];
NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
@@ -63,15 +68,19 @@
[layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:frame.origin];
}
-- (NSTextStorage *)_textStorageAndLayoutManagerWithAttributesString:(NSAttributedString *)attributedString
- paragraphAttributes:(ParagraphAttributes)paragraphAttributes
- size:(CGSize)size
-{
+- (NSTextStorage *)
+ _textStorageAndLayoutManagerWithAttributesString:
+ (NSAttributedString *)attributedString
+ paragraphAttributes:
+ (ParagraphAttributes)paragraphAttributes
+ size:(CGSize)size {
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:size];
textContainer.lineFragmentPadding = 0.0; // Note, the default value is 5.
- textContainer.lineBreakMode =
- paragraphAttributes.maximumNumberOfLines > 0 ? RCTNSLineBreakModeFromWritingDirection(paragraphAttributes.ellipsizeMode) : NSLineBreakByClipping;
+ textContainer.lineBreakMode = paragraphAttributes.maximumNumberOfLines > 0
+ ? RCTNSLineBreakModeFromWritingDirection(
+ paragraphAttributes.ellipsizeMode)
+ : NSLineBreakByClipping;
textContainer.maximumNumberOfLines = paragraphAttributes.maximumNumberOfLines;
NSLayoutManager *layoutManager = [NSLayoutManager new];
@@ -83,8 +92,12 @@
[textStorage addLayoutManager:layoutManager];
if (paragraphAttributes.adjustsFontSizeToFit) {
- CGFloat minimumFontSize = !isnan(paragraphAttributes.minimumFontSize) ? paragraphAttributes.minimumFontSize : 4.0;
- CGFloat maximumFontSize = !isnan(paragraphAttributes.maximumFontSize) ? paragraphAttributes.maximumFontSize : 96.0;
+ CGFloat minimumFontSize = !isnan(paragraphAttributes.minimumFontSize)
+ ? paragraphAttributes.minimumFontSize
+ : 4.0;
+ CGFloat maximumFontSize = !isnan(paragraphAttributes.maximumFontSize)
+ ? paragraphAttributes.maximumFontSize
+ : 96.0;
[textStorage scaleFontSizeToFitSize:size
minimumFontSize:minimumFontSize
maximumFontSize:maximumFontSize];
@@ -93,4 +106,38 @@
return textStorage;
}
+- (SharedEventEmitter)
+ getEventEmitterWithAttributeString:(AttributedString)attributedString
+ paragraphAttributes:(ParagraphAttributes)paragraphAttributes
+ frame:(CGRect)frame
+ atPoint:(CGPoint)point {
+ NSTextStorage *textStorage =
+ [self _textStorageAndLayoutManagerWithAttributesString:
+ RCTNSAttributedStringFromAttributedString(attributedString)
+ paragraphAttributes:paragraphAttributes
+ size:frame.size];
+ NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
+ NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
+
+ CGFloat fraction;
+ NSUInteger characterIndex =
+ [layoutManager characterIndexForPoint:point
+ inTextContainer:textContainer
+ fractionOfDistanceBetweenInsertionPoints:&fraction];
+
+ // If the point is not before (fraction == 0.0) the first character and not
+ // after (fraction == 1.0) the last character, then the attribute is valid.
+ if (textStorage.length > 0 && (fraction > 0 || characterIndex > 0) &&
+ (fraction < 1 || characterIndex < textStorage.length - 1)) {
+ RCTWeakEventEmitterWrapper *eventEmitterWrapper =
+ (RCTWeakEventEmitterWrapper *)[textStorage
+ attribute:RCTAttributedStringEventEmitterKey
+ atIndex:characterIndex
+ effectiveRange:NULL];
+ return eventEmitterWrapper.eventEmitter;
+ }
+
+ return nil;
+}
+
@end

ReactCommon/fabric/textlayoutmanager/platform/ios/RCTTextPrimitivesConversions.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,64 +7,88 @@
#import <UIKit/UIKit.h>
-#include <fabric/textlayoutmanager/RCTFontProperties.h>
-#include <fabric/textlayoutmanager/RCTFontUtils.h>
+#include <react/textlayoutmanager/RCTFontProperties.h>
+#include <react/textlayoutmanager/RCTFontUtils.h>
using namespace facebook::react;
-inline static NSTextAlignment RCTNSTextAlignmentFromTextAlignment(TextAlignment textAlignment) {
+inline static NSTextAlignment RCTNSTextAlignmentFromTextAlignment(
+ TextAlignment textAlignment) {
switch (textAlignment) {
- case TextAlignment::Natural: return NSTextAlignmentNatural;
- case TextAlignment::Left: return NSTextAlignmentLeft;
- case TextAlignment::Right: return NSTextAlignmentRight;
- case TextAlignment::Center: return NSTextAlignmentCenter;
- case TextAlignment::Justified: return NSTextAlignmentJustified;
+ case TextAlignment::Natural:
+ return NSTextAlignmentNatural;
+ case TextAlignment::Left:
+ return NSTextAlignmentLeft;
+ case TextAlignment::Right:
+ return NSTextAlignmentRight;
+ case TextAlignment::Center:
+ return NSTextAlignmentCenter;
+ case TextAlignment::Justified:
+ return NSTextAlignmentJustified;
}
}
-inline static NSWritingDirection RCTNSWritingDirectionFromWritingDirection(WritingDirection writingDirection) {
+inline static NSWritingDirection RCTNSWritingDirectionFromWritingDirection(
+ WritingDirection writingDirection) {
switch (writingDirection) {
- case WritingDirection::Natural: return NSWritingDirectionNatural;
- case WritingDirection::LeftToRight: return NSWritingDirectionLeftToRight;
- case WritingDirection::RightToLeft: return NSWritingDirectionRightToLeft;
+ case WritingDirection::Natural:
+ return NSWritingDirectionNatural;
+ case WritingDirection::LeftToRight:
+ return NSWritingDirectionLeftToRight;
+ case WritingDirection::RightToLeft:
+ return NSWritingDirectionRightToLeft;
}
}
inline static RCTFontStyle RCTFontStyleFromFontStyle(FontStyle fontStyle) {
switch (fontStyle) {
- case FontStyle::Normal: return RCTFontStyleNormal;
- case FontStyle::Italic: return RCTFontStyleItalic;
- case FontStyle::Oblique: return RCTFontStyleOblique;
+ case FontStyle::Normal:
+ return RCTFontStyleNormal;
+ case FontStyle::Italic:
+ return RCTFontStyleItalic;
+ case FontStyle::Oblique:
+ return RCTFontStyleOblique;
}
}
-inline static RCTFontVariant RCTFontVariantFromFontVariant(FontVariant fontVariant) {
+inline static RCTFontVariant RCTFontVariantFromFontVariant(
+ FontVariant fontVariant) {
return (RCTFontVariant)fontVariant;
}
-inline static NSUnderlineStyle RCTNSUnderlineStyleFromStyleAndPattern(TextDecorationLineStyle textDecorationLineStyle, TextDecorationLinePattern textDecorationLinePattern) {
+inline static NSUnderlineStyle RCTNSUnderlineStyleFromStyleAndPattern(
+ TextDecorationLineStyle textDecorationLineStyle,
+ TextDecorationLinePattern textDecorationLinePattern) {
NSUnderlineStyle style = NSUnderlineStyleNone;
switch (textDecorationLineStyle) {
case TextDecorationLineStyle::Single:
- style = NSUnderlineStyle(style | NSUnderlineStyleSingle); break;
+ style = NSUnderlineStyle(style | NSUnderlineStyleSingle);
+ break;
case TextDecorationLineStyle::Thick:
- style = NSUnderlineStyle(style | NSUnderlineStyleThick); break;
+ style = NSUnderlineStyle(style | NSUnderlineStyleThick);
+ break;
case TextDecorationLineStyle::Double:
- style = NSUnderlineStyle(style | NSUnderlineStyleDouble); break;
+ style = NSUnderlineStyle(style | NSUnderlineStyleDouble);
+ break;
}
switch (textDecorationLinePattern) {
case TextDecorationLinePattern::Solid:
- style = NSUnderlineStyle(style | NSUnderlinePatternSolid); break;
+ style = NSUnderlineStyle(style | NSUnderlinePatternSolid);
+ break;
case TextDecorationLinePattern::Dash:
- style = NSUnderlineStyle(style | NSUnderlinePatternDash); break;
+ style = NSUnderlineStyle(style | NSUnderlinePatternDash);
+ break;
case TextDecorationLinePattern::Dot:
- style = NSUnderlineStyle(style | NSUnderlinePatternDot); break;
+ style = NSUnderlineStyle(style | NSUnderlinePatternDot);
+ break;
case TextDecorationLinePattern::DashDot:
- style = NSUnderlineStyle(style | NSUnderlinePatternDashDot); break;
+ style = NSUnderlineStyle(style | NSUnderlinePatternDashDot);
+ break;
case TextDecorationLinePattern::DashDotDot:
- style = NSUnderlineStyle(style | NSUnderlinePatternDashDotDot); break;
+ style = NSUnderlineStyle(style | NSUnderlinePatternDashDotDot);
+ break;
}
return style;

ReactCommon/fabric/textlayoutmanager/platform/ios/TextLayoutManager.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,9 +9,10 @@
#include <memory>
-#include <fabric/attributedstring/AttributedString.h>
-#include <fabric/attributedstring/ParagraphAttributes.h>
-#include <fabric/core/LayoutConstraints.h>
+#include <react/attributedstring/AttributedString.h>
+#include <react/attributedstring/ParagraphAttributes.h>
+#include <react/core/LayoutConstraints.h>
+#include <react/uimanager/ContextContainer.h>
namespace facebook {
namespace react {
@@ -24,8 +25,8 @@
* Cross platform facade for iOS-specific RCTTTextLayoutManager.
*/
class TextLayoutManager {
-public:
- TextLayoutManager();
+ public:
+ TextLayoutManager(const SharedContextContainer &contextContainer);
~TextLayoutManager();
/*
@@ -34,8 +35,7 @@
Size measure(
AttributedString attributedString,
ParagraphAttributes paragraphAttributes,
- LayoutConstraints layoutConstraints
- ) const;
+ LayoutConstraints layoutConstraints) const;
/*
* Returns an opaque pointer to platform-specific TextLayoutManager.
@@ -43,7 +43,7 @@
*/
void *getNativeTextLayoutManager() const;
-private:
+ private:
void *self_;
};

ReactCommon/fabric/textlayoutmanager/platform/ios/TextLayoutManager.mm

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -12,7 +12,8 @@
namespace facebook {
namespace react {
-TextLayoutManager::TextLayoutManager() {
+TextLayoutManager::TextLayoutManager(
+ const SharedContextContainer &contextContainer) {
self_ = (__bridge_retained void *)[RCTTextLayoutManager new];
}
@@ -28,9 +29,9 @@
Size TextLayoutManager::measure(
AttributedString attributedString,
ParagraphAttributes paragraphAttributes,
- LayoutConstraints layoutConstraints
-) const {
- RCTTextLayoutManager *textLayoutManager = (__bridge RCTTextLayoutManager *)self_;
+ LayoutConstraints layoutConstraints) const {
+ RCTTextLayoutManager *textLayoutManager =
+ (__bridge RCTTextLayoutManager *)self_;
return [textLayoutManager measureWithAttributedString:attributedString
paragraphAttributes:paragraphAttributes
layoutConstraints:layoutConstraints];

ReactCommon/fabric/textlayoutmanager/tests/TextLayoutManagerTest.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,7 +9,7 @@
#include <gtest/gtest.h>
-#include <fabric/textlayoutmanager/TextLayoutManager.h>
+#include <react/textlayoutmanager/TextLayoutManager.h>
using namespace facebook::react;

ReactCommon/fabric/uimanager/BUCK

@@ -1,4 +1,4 @@
-load("//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags")
+load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags")
load(
"//tools/build_defs/oss:rn_defs.bzl",
"ANDROID",
@@ -28,7 +28,7 @@
[
("", "*.h"),
],
- prefix = "fabric/uimanager",
+ prefix = "react/uimanager",
),
compiler_flags = [
"-fexceptions",
@@ -38,26 +38,28 @@
],
fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
- fbobjc_tests = [
- ":tests",
- ],
force_static = True,
macosx_tests_override = [],
platforms = (ANDROID, APPLE),
preprocessor_flags = [
"-DLOG_TAG=\"ReactNative\"",
- "-DWITH_FBSYSTRACE=1",
+ # Systraces are temporary disabled.
+ # "-DWITH_FBSYSTRACE=1",
],
- tests = [],
+ tests = [":tests"],
visibility = ["PUBLIC"],
deps = [
"xplat//fbsystrace:fbsystrace",
"xplat//folly:headers_only",
"xplat//folly:memory",
"xplat//folly:molly",
+ "xplat//jsi:JSIDynamic",
+ "xplat//jsi:jsi",
"xplat//third-party/glog:glog",
+ react_native_xplat_target("config:config"),
react_native_xplat_target("fabric/components/root:root"),
react_native_xplat_target("fabric/components/view:view"),
+ react_native_xplat_target("fabric/mounting:mounting"),
react_native_xplat_target("fabric/core:core"),
react_native_xplat_target("fabric/debug:debug"),
react_native_xplat_target("fabric/events:events"),
@@ -75,10 +77,18 @@
"-Wall",
],
contacts = ["oncall+react_native@xmail.facebook.com"],
- platforms = APPLE,
+ fbandroid_use_instrumentation_test = True,
+ platforms = (ANDROID, APPLE),
deps = [
"xplat//folly:molly",
"xplat//third-party/gmock:gtest",
":uimanager",
+ react_native_xplat_target("config:config"),
+ react_native_xplat_target("fabric/components/activityindicator:activityindicator"),
+ react_native_xplat_target("fabric/components/image:image"),
+ react_native_xplat_target("fabric/components/root:root"),
+ react_native_xplat_target("fabric/components/scrollview:scrollview"),
+ react_native_xplat_target("fabric/components/text:text"),
+ react_native_xplat_target("fabric/components/view:view"),
],
)

ReactCommon/fabric/uimanager/ComponentDescriptorFactory.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -9,9 +9,9 @@
#include <memory>
-#include <fabric/core/ComponentDescriptor.h>
-#include <fabric/events/EventDispatcher.h>
-#include <fabric/uimanager/ContextContainer.h>
+#include <react/core/ComponentDescriptor.h>
+#include <react/events/EventDispatcher.h>
+#include <react/uimanager/ContextContainer.h>
#include "ComponentDescriptorRegistry.h"
@@ -23,11 +23,12 @@
* Each app must provide an implementation of the static class method which
* should register its specific set of supported components.
*/
-class ComponentDescriptorFactory {
+using ComponentRegistryFactory =
+ std::function<SharedComponentDescriptorRegistry(
+ const SharedEventDispatcher &eventDispatcher,
+ const SharedContextContainer &contextContainer)>;
-public:
- static SharedComponentDescriptorRegistry buildRegistry(const SharedEventDispatcher &eventDispatcher, const SharedContextContainer &contextContainer);
-};
+ComponentRegistryFactory getDefaultComponentRegistryFactory();
} // namespace react
} // namespace facebook

ReactCommon/fabric/uimanager/ComponentDescriptorRegistry.cpp

@@ -1,14 +1,18 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
#include "ComponentDescriptorRegistry.h"
+#include <react/core/ShadowNodeFragment.h>
+#include <react/uimanager/primitives.h>
+
namespace facebook {
namespace react {
-void ComponentDescriptorRegistry::registerComponentDescriptor(SharedComponentDescriptor componentDescriptor) {
+void ComponentDescriptorRegistry::registerComponentDescriptor(
+ SharedComponentDescriptor componentDescriptor) {
ComponentHandle componentHandle = componentDescriptor->getComponentHandle();
_registryByHandle[componentHandle] = componentDescriptor;
@@ -16,13 +20,106 @@
_registryByName[componentName] = componentDescriptor;
}
-const SharedComponentDescriptor ComponentDescriptorRegistry::operator[](const SharedShadowNode &shadowNode) const {
+const SharedComponentDescriptor ComponentDescriptorRegistry::operator[](
+ const SharedShadowNode &shadowNode) const {
ComponentHandle componentHandle = shadowNode->getComponentHandle();
return _registryByHandle.at(componentHandle);
}
-const SharedComponentDescriptor ComponentDescriptorRegistry::operator[](const ComponentName &componentName) const {
- return _registryByName.at(componentName);
+const SharedComponentDescriptor ComponentDescriptorRegistry::operator[](
+ const ComponentName &componentName) const {
+ auto it = _registryByName.find(componentName);
+ if (it == _registryByName.end()) {
+ throw std::invalid_argument(
+ ("Unable to find componentDescriptor for " + componentName).c_str());
+ }
+ return it->second;
+}
+
+static const std::string componentNameByReactViewName(std::string viewName) {
+ // We need this function only for the transition period;
+ // eventually, all names will be unified.
+
+ std::string rctPrefix("RCT");
+ if (std::mismatch(rctPrefix.begin(), rctPrefix.end(), viewName.begin())
+ .first == rctPrefix.end()) {
+ // If `viewName` has "RCT" prefix, remove it.
+ viewName.erase(0, rctPrefix.length());
+ }
+
+ // Fabric uses slightly new names for Text components because of differences
+ // in semantic.
+ if (viewName == "Text") {
+ return "Paragraph";
+ }
+ if (viewName == "VirtualText") {
+ return "Text";
+ }
+
+ if (viewName == "ImageView") {
+ return "Image";
+ }
+
+ if (viewName == "AndroidHorizontalScrollView") {
+ return "ScrollView";
+ }
+
+ if (viewName == "RKShimmeringView") {
+ return "ShimmeringView";
+ }
+
+ if (viewName == "AndroidProgressBar") {
+ return "ActivityIndicatorView";
+ }
+
+ // We need this temporarly for testing purposes until we have proper
+ // implementation of core components.
+ if (viewName == "SinglelineTextInputView" ||
+ viewName == "MultilineTextInputView" || viewName == "AndroidTextInput" ||
+ viewName == "RefreshControl" || viewName == "AndroidSwipeRefreshLayout" ||
+ viewName == "SafeAreaView" || viewName == "ScrollContentView" ||
+ viewName == "AndroidHorizontalScrollContentView" // Android
+ ) {
+ return "View";
+ }
+
+ return viewName;
+}
+
+const ComponentDescriptor &ComponentDescriptorRegistry::at(
+ ComponentName componentName) const {
+ auto unifiedComponentName = componentNameByReactViewName(componentName);
+
+ auto it = _registryByName.find(unifiedComponentName);
+ if (it == _registryByName.end()) {
+ throw std::invalid_argument(
+ ("Unable to find componentDescriptor for " + unifiedComponentName)
+ .c_str());
+ }
+ return *it->second;
+}
+
+const ComponentDescriptor &ComponentDescriptorRegistry::at(
+ ComponentHandle componentHandle) const {
+ return *_registryByHandle.at(componentHandle);
+}
+
+SharedShadowNode ComponentDescriptorRegistry::createNode(
+ Tag tag,
+ const std::string &viewName,
+ Tag rootTag,
+ const folly::dynamic &props,
+ const SharedEventTarget &eventTarget) const {
+ ComponentName componentName = componentNameByReactViewName(viewName);
+ const SharedComponentDescriptor &componentDescriptor = (*this)[componentName];
+
+ SharedShadowNode shadowNode = componentDescriptor->createShadowNode(
+ {.tag = tag,
+ .rootTag = rootTag,
+ .eventEmitter =
+ componentDescriptor->createEventEmitter(std::move(eventTarget), tag),
+ .props = componentDescriptor->cloneProps(nullptr, RawProps(props))});
+ return shadowNode;
}
} // namespace react

ReactCommon/fabric/uimanager/ComponentDescriptorRegistry.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -7,28 +7,41 @@
#include <memory>
-#include <fabric/core/ComponentDescriptor.h>
+#include <react/core/ComponentDescriptor.h>
namespace facebook {
namespace react {
class ComponentDescriptorRegistry;
-using SharedComponentDescriptorRegistry = std::shared_ptr<const ComponentDescriptorRegistry>;
+using SharedComponentDescriptorRegistry =
+ std::shared_ptr<const ComponentDescriptorRegistry>;
/*
* Registry of particular `ComponentDescriptor`s.
*/
class ComponentDescriptorRegistry {
-
-public:
- void registerComponentDescriptor(SharedComponentDescriptor componentDescriptor);
-
- const SharedComponentDescriptor operator[](const SharedShadowNode &shadowNode) const;
- const SharedComponentDescriptor operator[](const ComponentName &componentName) const;
-
-private:
- std::unordered_map<ComponentHandle, SharedComponentDescriptor> _registryByHandle;
+ public:
+ void registerComponentDescriptor(
+ SharedComponentDescriptor componentDescriptor);
+
+ const ComponentDescriptor &at(ComponentName componentName) const;
+ const ComponentDescriptor &at(ComponentHandle componentHandle) const;
+
+ const SharedComponentDescriptor operator[](
+ const SharedShadowNode &shadowNode) const;
+ const SharedComponentDescriptor operator[](
+ const ComponentName &componentName) const;
+ SharedShadowNode createNode(
+ Tag tag,
+ const std::string &viewName,
+ Tag rootTag,
+ const folly::dynamic &props,
+ const SharedEventTarget &eventTarget) const;
+
+ private:
+ std::unordered_map<ComponentHandle, SharedComponentDescriptor>
+ _registryByHandle;
std::unordered_map<ComponentName, SharedComponentDescriptor> _registryByName;
};

ReactCommon/fabric/uimanager/ContextContainer.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -7,9 +7,11 @@
#include <memory>
#include <mutex>
+#include <string>
#include <typeindex>
#include <typeinfo>
#include <unordered_map>
+#include <utility>
namespace facebook {
namespace react {
@@ -23,40 +25,41 @@
* Instance types must be copyable.
*/
class ContextContainer final {
-
-public:
+ public:
/*
- * Registers an instance of the particular type `T` in the container.
- * If `key` parameter is specified, the instance is registered
- * by `{type, key}` pair.
+ * Registers an instance of the particular type `T` in the container
+ * using the provided `key`. Only one instance can be registered per key.
+ *
+ * Convention is to use the plain base class name for the key, so for
+ * example if the type `T` is `std::shared_ptr<const ReactNativeConfig>`,
+ * then one would use `"ReactNativeConfig"` for the `key`, even if the
+ * instance is actually a `shared_ptr` of derived class
+ *`EmptyReactNativeConfig`.
*/
- template<typename T>
- void registerInstance(const T &instance, const std::string &key = "") {
+ template <typename T>
+ void registerInstance(const T &instance, const std::string &key) {
std::lock_guard<std::mutex> lock(mutex_);
- instances_.insert({
- {std::type_index(typeid(T)), key},
- std::make_shared<T>(instance)
- });
+ const auto res = instances_.insert({key, std::make_shared<T>(instance)});
+ if (res.second == false) {
+ LOG(FATAL) << "ContextContainer already had instance for key '" << key
+ << "'";
+ }
}
/*
- * Returns a previously registered instance of the particular type `T`.
- * If `key` parameter is specified, the lookup will be performed
- * by {type, key} pair.
+ * Returns a previously registered instance of the particular type `T`
+ * for `key`.
*/
- template<typename T>
- T getInstance(const std::string &key = "") const {
+ template <typename T>
+ T getInstance(const std::string &key) const {
std::lock_guard<std::mutex> lock(mutex_);
- return *std::static_pointer_cast<T>(instances_.at({std::type_index(typeid(T)), key}));
+ return *std::static_pointer_cast<T>(instances_.at(key));
}
-private:
- std::unordered_map<
- std::pair<std::type_index, std::string>,
- std::shared_ptr<void>
- > instances_;
+ private:
+ std::unordered_map<std::string, std::shared_ptr<void>> instances_;
mutable std::mutex mutex_;
};

ReactCommon/fabric/uimanager/Differentiator.cpp

@@ -1,207 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#include "Differentiator.h"
-
-namespace facebook {
-namespace react {
-
-static void calculateMutationInstructions(
- TreeMutationInstructionList &instructions,
- SharedShadowNode parentNode,
- const SharedShadowNodeList &oldChildNodes,
- const SharedShadowNodeList &newChildNodes
-) {
- // The current version of the algorithm is otimized for simplicity,
- // not for performance of optimal result.
-
- // TODO(shergin): Consider to use Minimal Edit Distance algorithm to produce
- // optimal set of instructions and improve mounting performance.
- // https://en.wikipedia.org/wiki/Edit_distance
- // https://www.geeksforgeeks.org/dynamic-programming-set-5-edit-distance/
-
- if (oldChildNodes == newChildNodes) {
- return;
- }
-
- if (oldChildNodes.size() == 0 && newChildNodes.size() == 0) {
- return;
- }
-
- std::unordered_map<Tag, SharedShadowNode> insertedNodes;
- int index = 0;
-
- TreeMutationInstructionList createInstructions = {};
- TreeMutationInstructionList deleteInstructions = {};
- TreeMutationInstructionList insertInstructions = {};
- TreeMutationInstructionList removeInstructions = {};
- TreeMutationInstructionList replaceInstructions = {};
- TreeMutationInstructionList downwardInstructions = {};
- TreeMutationInstructionList destructionDownwardInstructions = {};
-
- // Stage 1: Collectings Updates
- for (index = 0; index < oldChildNodes.size() && index < newChildNodes.size(); index++) {
- const auto &oldChildNode = oldChildNodes.at(index);
- const auto &newChildNode = newChildNodes.at(index);
-
- if (oldChildNode->getTag() != newChildNode->getTag()) {
- // Totally different nodes, updating is impossible.
- break;
- }
-
- if (*oldChildNode != *newChildNode) {
- replaceInstructions.push_back(
- TreeMutationInstruction::Replace(
- parentNode,
- oldChildNode,
- newChildNode,
- index
- )
- );
- }
-
- calculateMutationInstructions(
- *(newChildNode->getChildren().size() ? &downwardInstructions : &destructionDownwardInstructions),
- oldChildNode,
- oldChildNode->getChildren(),
- newChildNode->getChildren()
- );
- }
-
- int lastIndexAfterFirstStage = index;
-
- // Stage 2: Collectings Insertions
- for (; index < newChildNodes.size(); index++) {
- const auto &newChildNode = newChildNodes.at(index);
-
- insertInstructions.push_back(
- TreeMutationInstruction::Insert(
- parentNode,
- newChildNode,
- index
- )
- );
-
- insertedNodes.insert({newChildNode->getTag(), newChildNode});
- }
-
- // Stage 3: Collectings Deletions and Removals
- for (index = lastIndexAfterFirstStage; index < oldChildNodes.size(); index++) {
- const auto &oldChildNode = oldChildNodes.at(index);
-
- // Even if the old node was (re)inserted, we have to generate `remove`
- // instruction.
- removeInstructions.push_back(
- TreeMutationInstruction::Remove(
- parentNode,
- oldChildNode,
- index
- )
- );
-
- const auto &it = insertedNodes.find(oldChildNode->getTag());
-
- if (it == insertedNodes.end()) {
- // The old node was *not* (re)inserted.
- // We have to generate `delete` instruction and apply the algorithm
- // recursively.
- deleteInstructions.push_back(
- TreeMutationInstruction::Delete(
- oldChildNode
- )
- );
-
- // We also have to call the algorithm recursively to clean up the entire
- // subtree starting from the removed node.
- calculateMutationInstructions(
- destructionDownwardInstructions,
- oldChildNode,
- oldChildNode->getChildren(),
- {}
- );
- } else {
- // The old node *was* (re)inserted.
- // We have to call the algorithm recursively if the inserted node
- // is *not* the same as removed one.
- const auto &newChildNode = it->second;
- if (newChildNode != oldChildNode) {
- calculateMutationInstructions(
- *(newChildNode->getChildren().size() ? &downwardInstructions : &destructionDownwardInstructions),
- newChildNode,
- oldChildNode->getChildren(),
- newChildNode->getChildren()
- );
- }
-
- // In any case we have to remove the node from `insertedNodes` as
- // indication that the node was actually removed (which means that
- // the node existed before), hence we don't have to generate
- // `create` instruction.
- insertedNodes.erase(it);
- }
- }
-
- // Stage 4: Collectings Creations
- for (index = lastIndexAfterFirstStage; index < newChildNodes.size(); index++) {
- const auto &newChildNode = newChildNodes.at(index);
-
- if (insertedNodes.find(newChildNode->getTag()) == insertedNodes.end()) {
- // The new node was (re)inserted, so there is no need to create it.
- continue;
- }
-
- createInstructions.push_back(
- TreeMutationInstruction::Create(
- newChildNode
- )
- );
-
- calculateMutationInstructions(
- downwardInstructions,
- newChildNode,
- {},
- newChildNode->getChildren()
- );
- }
-
- // All instructions in an optimal order:
- instructions.insert(instructions.end(), destructionDownwardInstructions.begin(), destructionDownwardInstructions.end());
- instructions.insert(instructions.end(), replaceInstructions.begin(), replaceInstructions.end());
- instructions.insert(instructions.end(), removeInstructions.rbegin(), removeInstructions.rend());
- instructions.insert(instructions.end(), createInstructions.begin(), createInstructions.end());
- instructions.insert(instructions.end(), downwardInstructions.begin(), downwardInstructions.end());
- instructions.insert(instructions.end(), insertInstructions.begin(), insertInstructions.end());
- instructions.insert(instructions.end(), deleteInstructions.begin(), deleteInstructions.end());
-}
-
-void calculateMutationInstructions(
- TreeMutationInstructionList &instructions,
- const SharedShadowNode &oldRootShadowNode,
- const SharedShadowNode &newRootShadowNode
-) {
- // Root shadow nodes must have same tag.
- assert(oldRootShadowNode->getTag() == newRootShadowNode->getTag());
-
- if (*oldRootShadowNode != *newRootShadowNode) {
- instructions.push_back(
- TreeMutationInstruction::Replace(
- nullptr,
- oldRootShadowNode,
- newRootShadowNode,
- -1
- )
- );
- }
-
- calculateMutationInstructions(
- instructions,
- oldRootShadowNode,
- oldRootShadowNode->getChildren(),
- newRootShadowNode->getChildren()
- );
-}
-
-} // namespace react
-} // namespace facebook

ReactCommon/fabric/uimanager/Differentiator.h

@@ -1,26 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#pragma once
-
-#include <fabric/core/ShadowNode.h>
-#include <fabric/uimanager/TreeMutationInstruction.h>
-
-namespace facebook {
-namespace react {
-
-/*
- * Calculates set of mutation instuctions which describe how the old
- * ShadowNode tree can be transformed to the new ShadowNode tree.
- * The set of instuctions might be and might not be optimal.
- */
-void calculateMutationInstructions(
- TreeMutationInstructionList &instructions,
- const SharedShadowNode &oldNode,
- const SharedShadowNode &newNode
-);
-
-} // namespace react
-} // namespace facebook

ReactCommon/fabric/uimanager/FabricUIManager.cpp

@@ -1,257 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#include "FabricUIManager.h"
-
-#include <glog/logging.h>
-
-#include <fabric/components/view/ViewComponentDescriptor.h>
-#include <fabric/components/view/ViewProps.h>
-#include <fabric/components/view/ViewShadowNode.h>
-#include <fabric/core/componentDescriptor.h>
-#include <fabric/core/LayoutContext.h>
-#include <fabric/core/ShadowNodeFragment.h>
-#include <fabric/debug/DebugStringConvertible.h>
-#include <fabric/debug/DebugStringConvertibleItem.h>
-
-namespace facebook {
-namespace react {
-
-// TODO: Kill this flag and remove debug logging.
-const bool isLoggingEnabled = false;
-
-static const RawProps rawPropsFromDynamic(const folly::dynamic object) {
- // TODO: Convert this to something smarter, probably returning `std::iterator`.
- RawProps result;
-
- if (object.isNull()) {
- return result;
- }
-
- assert(object.isObject());
-
- for (const auto &pair : object.items()) {
- assert(pair.first.isString());
- result[pair.first.asString()] = pair.second;
- }
-
- return result;
-}
-
-static const std::string componentNameByReactViewName(std::string viewName) {
- // We need this function only for the transition period;
- // eventually, all names will be unified.
-
- std::string rctPrefix("RCT");
- if (std::mismatch(rctPrefix.begin(), rctPrefix.end(), viewName.begin()).first == rctPrefix.end()) {
- // If `viewName` has "RCT" prefix, remove it.
- viewName.erase(0, rctPrefix.length());
- }
-
- // Fabric uses slightly new names for Text components because of differences
- // in semantic.
- if (viewName == "Text") {
- return "Paragraph";
- }
- if (viewName == "VirtualText") {
- return "Text";
- }
-
- if (viewName == "ImageView") {
- return "Image";
- }
-
- // We need this temporarly for testing purposes until we have proper
- // implementation of core components.
- if (
- viewName == "SinglelineTextInputView" ||
- viewName == "MultilineTextInputView" ||
- viewName == "RefreshControl" ||
- viewName == "SafeAreaView" ||
- viewName == "ScrollContentView"
- ) {
- return "View";
- }
-
- return viewName;
-}
-
-FabricUIManager::FabricUIManager(SharedComponentDescriptorRegistry componentDescriptorRegistry) {
- componentDescriptorRegistry_ = componentDescriptorRegistry;
-}
-
-FabricUIManager::~FabricUIManager() {
- if (eventHandler_) {
- releaseEventHandlerFunction_(eventHandler_);
- }
-}
-
-void FabricUIManager::setDelegate(UIManagerDelegate *delegate) {
- delegate_ = delegate;
-}
-
-UIManagerDelegate *FabricUIManager::getDelegate() {
- return delegate_;
-}
-
-void FabricUIManager::setDispatchEventToEmptyTargetFunction(std::function<DispatchEventToEmptyTargetFunction> dispatchEventFunction) {
- dispatchEventToEmptyTargetFunction_ = dispatchEventFunction;
-}
-
-void FabricUIManager::setDispatchEventToTargetFunction(std::function<DispatchEventToTargetFunction> dispatchEventFunction) {
- dispatchEventToTargetFunction_ = dispatchEventFunction;
-}
-
-void FabricUIManager::setReleaseEventHandlerFunction(std::function<ReleaseEventHandlerFunction> releaseEventHandlerFunction) {
- releaseEventHandlerFunction_ = releaseEventHandlerFunction;
-}
-
-void FabricUIManager::setReleaseEventTargetFunction(std::function<ReleaseEventTargetFunction> releaseEventTargetFunction) {
- releaseEventTargetFunction_ = releaseEventTargetFunction;
-}
-
-void FabricUIManager::dispatchEventToEmptyTarget(const std::string &type, const folly::dynamic &payload) const {
- dispatchEventToEmptyTargetFunction_(
- eventHandler_,
- const_cast<std::string &>(type),
- const_cast<folly::dynamic &>(payload)
- );
-}
-
-void FabricUIManager::dispatchEventToTarget(const EventTarget &eventTarget, const std::string &type, const folly::dynamic &payload) const {
- dispatchEventToTargetFunction_(
- eventHandler_,
- eventTarget,
- const_cast<std::string &>(type),
- const_cast<folly::dynamic &>(payload)
- );
-}
-
-void FabricUIManager::releaseEventTarget(const EventTarget &eventTarget) const {
- releaseEventTargetFunction_(eventTarget);
-}
-
-SharedShadowNode FabricUIManager::createNode(int tag, std::string viewName, int rootTag, folly::dynamic props, EventTarget eventTarget) {
- isLoggingEnabled && LOG(INFO) << "FabricUIManager::createNode(tag: " << tag << ", name: " << viewName << ", rootTag: " << rootTag << ", props: " << props << ")";
-
- ComponentName componentName = componentNameByReactViewName(viewName);
- const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)[componentName];
- RawProps rawProps = rawPropsFromDynamic(props);
-
- SharedShadowNode shadowNode =
- componentDescriptor->createShadowNode({
- .tag = tag,
- .rootTag = rootTag,
- .eventEmitter = componentDescriptor->createEventEmitter(eventTarget, tag),
- .props = componentDescriptor->cloneProps(nullptr, rawProps)
- });
-
- isLoggingEnabled && LOG(INFO) << "FabricUIManager::createNode() -> " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false});
-
- if (delegate_) {
- delegate_->uiManagerDidCreateShadowNode(shadowNode);
- }
-
- return shadowNode;
-}
-
-SharedShadowNode FabricUIManager::cloneNode(const SharedShadowNode &shadowNode) {
- isLoggingEnabled && LOG(INFO) << "FabricUIManager::cloneNode(shadowNode: " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ")";
- const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)[shadowNode];
-
- SharedShadowNode clonedShadowNode =
- componentDescriptor->cloneShadowNode(*shadowNode, {});
-
- isLoggingEnabled && LOG(INFO) << "FabricUIManager::cloneNode() -> " << clonedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false});
- return clonedShadowNode;
-}
-
-SharedShadowNode FabricUIManager::cloneNodeWithNewChildren(const SharedShadowNode &shadowNode) {
- isLoggingEnabled && LOG(INFO) << "FabricUIManager::cloneNodeWithNewChildren(shadowNode: " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ")";
- // Assuming semantic: Cloning with same props but empty children.
- const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)[shadowNode];
-
- SharedShadowNode clonedShadowNode =
- componentDescriptor->cloneShadowNode(
- *shadowNode,
- {
- .children = ShadowNode::emptySharedShadowNodeSharedList()
- }
- );
-
- isLoggingEnabled && LOG(INFO) << "FabricUIManager::cloneNodeWithNewChildren() -> " << clonedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false});
- return clonedShadowNode;
-}
-
-SharedShadowNode FabricUIManager::cloneNodeWithNewProps(const SharedShadowNode &shadowNode, folly::dynamic props) {
- isLoggingEnabled && LOG(INFO) << "FabricUIManager::cloneNodeWithNewProps(shadowNode: " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ", props: " << props << ")";
- // Assuming semantic: Cloning with same children and specified props.
- const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)[shadowNode];
- RawProps rawProps = rawPropsFromDynamic(props);
-
- SharedShadowNode clonedShadowNode =
- componentDescriptor->cloneShadowNode(
- *shadowNode,
- {
- .props = componentDescriptor->cloneProps(shadowNode->getProps(), rawProps)
- }
- );
-
- isLoggingEnabled && LOG(INFO) << "FabricUIManager::cloneNodeWithNewProps() -> " << clonedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false});
- return clonedShadowNode;
-}
-
-SharedShadowNode FabricUIManager::cloneNodeWithNewChildrenAndProps(const SharedShadowNode &shadowNode, folly::dynamic props) {
- isLoggingEnabled && LOG(INFO) << "FabricUIManager::cloneNodeWithNewChildrenAndProps(shadowNode: " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ", props: " << props << ")";
- // Assuming semantic: Cloning with empty children and specified props.
- const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)[shadowNode];
- RawProps rawProps = rawPropsFromDynamic(props);
-
- SharedShadowNode clonedShadowNode =
- componentDescriptor->cloneShadowNode(
- *shadowNode,
- {
- .props = componentDescriptor->cloneProps(shadowNode->getProps(), rawProps),
- .children = ShadowNode::emptySharedShadowNodeSharedList()
- }
- );
-
- isLoggingEnabled && LOG(INFO) << "FabricUIManager::cloneNodeWithNewChildrenAndProps() -> " << clonedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false});
- return clonedShadowNode;
-}
-
-void FabricUIManager::appendChild(const SharedShadowNode &parentShadowNode, const SharedShadowNode &childShadowNode) {
- isLoggingEnabled && LOG(INFO) << "FabricUIManager::appendChild(parentShadowNode: " << parentShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ", childShadowNode: " << childShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ")";
- const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)[parentShadowNode];
- componentDescriptor->appendChild(parentShadowNode, childShadowNode);
-}
-
-SharedShadowNodeUnsharedList FabricUIManager::createChildSet(int rootTag) {
- isLoggingEnabled && LOG(INFO) << "FabricUIManager::createChildSet(rootTag: " << rootTag << ")";
- return std::make_shared<SharedShadowNodeList>(SharedShadowNodeList({}));
-}
-
-void FabricUIManager::appendChildToSet(const SharedShadowNodeUnsharedList &shadowNodeList, const SharedShadowNode &shadowNode) {
- isLoggingEnabled && LOG(INFO) << "FabricUIManager::appendChildToSet(shadowNodeList: " << shadowNodeList << ", shadowNode: " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ")";
- shadowNodeList->push_back(shadowNode);
-}
-
-void FabricUIManager::completeRoot(int rootTag, const SharedShadowNodeUnsharedList &children) {
- isLoggingEnabled && LOG(INFO) << "FabricUIManager::completeRoot(rootTag: " << rootTag << ", shadowNodeList: " << children << ")";
-
- if (delegate_) {
- delegate_->uiManagerDidFinishTransaction(rootTag, children);
- }
-}
-
-void FabricUIManager::registerEventHandler(const EventHandler &eventHandler) {
- isLoggingEnabled && LOG(INFO) << "FabricUIManager::registerEventHandler(eventHandler: " << eventHandler << ")";
- eventHandler_ = eventHandler;
-}
-
-} // namespace react
-} // namespace facebook

ReactCommon/fabric/uimanager/FabricUIManager.h

@@ -1,83 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#pragma once
-
-#include <memory>
-
-#include <folly/dynamic.h>
-
-#include <fabric/core/ShadowNode.h>
-#include <fabric/uimanager/ComponentDescriptorRegistry.h>
-#include <fabric/uimanager/UIManagerDelegate.h>
-
-namespace facebook {
-namespace react {
-
-using DispatchEventToEmptyTargetFunction = void (EventHandler eventHandler, std::string type, folly::dynamic payload);
-using DispatchEventToTargetFunction = void (EventHandler eventHandler, EventTarget eventTarget, std::string type, folly::dynamic payload);
-using ReleaseEventHandlerFunction = void (EventHandler eventHandler);
-using ReleaseEventTargetFunction = void (EventTarget eventTarget);
-
-class FabricUIManager {
-public:
-
-#pragma mark - Native-facing Interface
-
- FabricUIManager(SharedComponentDescriptorRegistry componentDescriptorRegistry);
- ~FabricUIManager();
-
- /*
- * Sets and gets the UIManager's delegate.
- * The delegate is stored as a raw pointer, so the owner must null
- * the pointer before being destroyed.
- */
- void setDelegate(UIManagerDelegate *delegate);
- UIManagerDelegate *getDelegate();
-
-#pragma mark - Callback Functions
-
- /*
- * Registers callback functions.
- */
- void setDispatchEventToEmptyTargetFunction(std::function<DispatchEventToEmptyTargetFunction> dispatchEventFunction);
- void setDispatchEventToTargetFunction(std::function<DispatchEventToTargetFunction> dispatchEventFunction);
- void setReleaseEventHandlerFunction(std::function<ReleaseEventHandlerFunction> releaseEventHandlerFunction);
- void setReleaseEventTargetFunction(std::function<ReleaseEventTargetFunction> releaseEventTargetFunction);
-
-#pragma mark - Native-facing Interface
-
- void dispatchEventToEmptyTarget(const std::string &type, const folly::dynamic &payload) const;
- void dispatchEventToTarget(const EventTarget &eventTarget, const std::string &type, const folly::dynamic &payload) const;
- void releaseEventTarget(const EventTarget &eventTarget) const;
-
-#pragma mark - JavaScript/React-facing Interface
-
- SharedShadowNode createNode(Tag reactTag, std::string viewName, Tag rootTag, folly::dynamic props, EventTarget eventTarget);
- SharedShadowNode cloneNode(const SharedShadowNode &node);
- SharedShadowNode cloneNodeWithNewChildren(const SharedShadowNode &node);
- SharedShadowNode cloneNodeWithNewProps(const SharedShadowNode &node, folly::dynamic props);
- SharedShadowNode cloneNodeWithNewChildrenAndProps(const SharedShadowNode &node, folly::dynamic newProps);
- void appendChild(const SharedShadowNode &parentNode, const SharedShadowNode &childNode);
- SharedShadowNodeUnsharedList createChildSet(Tag rootTag);
- void appendChildToSet(const SharedShadowNodeUnsharedList &childSet, const SharedShadowNode &childNode);
- void completeRoot(Tag rootTag, const SharedShadowNodeUnsharedList &childSet);
- void registerEventHandler(const EventHandler &eventHandler);
-
-private:
-
- SharedComponentDescriptorRegistry componentDescriptorRegistry_;
- UIManagerDelegate *delegate_;
- EventHandler eventHandler_;
- std::function<DispatchEventToEmptyTargetFunction> dispatchEventToEmptyTargetFunction_;
- std::function<DispatchEventToTargetFunction> dispatchEventToTargetFunction_;
- std::function<ReleaseEventHandlerFunction> releaseEventHandlerFunction_;
- std::function<ReleaseEventTargetFunction> releaseEventTargetFunction_;
-};
-
-} // namespace react
-} // namespace facebook

ReactCommon/fabric/uimanager/primitives.h

@@ -0,0 +1,92 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#pragma once
+
+#include <folly/dynamic.h>
+#include <jsi/JSIDynamic.h>
+#include <jsi/jsi.h>
+#include <react/core/ShadowNode.h>
+
+namespace facebook {
+namespace react {
+
+using RuntimeExecutor = std::function<void(
+ std::function<void(facebook::jsi::Runtime &runtime)> &&callback)>;
+
+struct EventHandlerWrapper : public EventHandler {
+ EventHandlerWrapper(jsi::Function eventHandler)
+ : callback(std::move(eventHandler)) {}
+
+ jsi::Function callback;
+};
+
+struct ShadowNodeWrapper : public jsi::HostObject {
+ ShadowNodeWrapper(SharedShadowNode shadowNode)
+ : shadowNode(std::move(shadowNode)) {}
+
+ SharedShadowNode shadowNode;
+};
+
+struct ShadowNodeListWrapper : public jsi::HostObject {
+ ShadowNodeListWrapper(SharedShadowNodeUnsharedList shadowNodeList)
+ : shadowNodeList(shadowNodeList) {}
+
+ SharedShadowNodeUnsharedList shadowNodeList;
+};
+
+inline static SharedShadowNode shadowNodeFromValue(
+ jsi::Runtime &runtime,
+ const jsi::Value &value) {
+ return value.getObject(runtime)
+ .getHostObject<ShadowNodeWrapper>(runtime)
+ ->shadowNode;
+}
+
+inline static jsi::Value valueFromShadowNode(
+ jsi::Runtime &runtime,
+ const SharedShadowNode &shadowNode) {
+ return jsi::Object::createFromHostObject(
+ runtime, std::make_shared<ShadowNodeWrapper>(shadowNode));
+}
+
+inline static SharedShadowNodeUnsharedList shadowNodeListFromValue(
+ jsi::Runtime &runtime,
+ const jsi::Value &value) {
+ return value.getObject(runtime)
+ .getHostObject<ShadowNodeListWrapper>(runtime)
+ ->shadowNodeList;
+}
+
+inline static jsi::Value valueFromShadowNodeList(
+ jsi::Runtime &runtime,
+ const SharedShadowNodeUnsharedList &shadowNodeList) {
+ return jsi::Object::createFromHostObject(
+ runtime, std::make_unique<ShadowNodeListWrapper>(shadowNodeList));
+}
+
+inline static SharedEventTarget eventTargetFromValue(
+ jsi::Runtime &runtime,
+ const jsi::Value &eventTargetValue,
+ const jsi::Value &tagValue) {
+ return std::make_shared<EventTarget>(
+ runtime, eventTargetValue, tagValue.getNumber());
+}
+
+inline static Tag tagFromValue(jsi::Runtime &runtime, const jsi::Value &value) {
+ return (Tag)value.getNumber();
+}
+
+inline static SurfaceId surfaceIdFromValue(
+ jsi::Runtime &runtime,
+ const jsi::Value &value) {
+ return (SurfaceId)value.getNumber();
+}
+
+inline static ComponentName componentNameFromValue(
+ jsi::Runtime &runtime,
+ const jsi::Value &value) {
+ return value.getString(runtime).utf8(runtime);
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/uimanager/Scheduler.cpp

@@ -1,61 +1,193 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
#include "Scheduler.h"
-#include <fabric/core/LayoutContext.h>
-#include <fabric/uimanager/ComponentDescriptorRegistry.h>
-#include <fabric/uimanager/FabricUIManager.h>
+#include <jsi/jsi.h>
-#include "ComponentDescriptorFactory.h"
-#include "Differentiator.h"
+#include <react/core/LayoutContext.h>
+#include <react/debug/SystraceSection.h>
+#include <react/uimanager/ComponentDescriptorRegistry.h>
+#include <react/uimanager/TimeUtils.h>
+#include <react/uimanager/UIManager.h>
+#include <react/uimanager/UIManagerBinding.h>
+#include <react/uimanager/UITemplateProcessor.h>
namespace facebook {
namespace react {
-Scheduler::Scheduler(const SharedContextContainer &contextContainer):
- contextContainer_(contextContainer) {
- const auto &eventDispatcher = std::make_shared<SchedulerEventDispatcher>();
- const auto &componentDescriptorRegistry = ComponentDescriptorFactory::buildRegistry(eventDispatcher, contextContainer);
-
- uiManager_ = std::make_shared<FabricUIManager>(componentDescriptorRegistry);
- uiManager_->setDelegate(this);
-
- eventDispatcher->setUIManager(uiManager_);
- eventDispatcher_ = eventDispatcher;
+Scheduler::Scheduler(
+ const SharedContextContainer &contextContainer,
+ ComponentRegistryFactory buildRegistryFunction) {
+ const auto asynchronousEventBeatFactory =
+ contextContainer->getInstance<EventBeatFactory>("asynchronous");
+ const auto synchronousEventBeatFactory =
+ contextContainer->getInstance<EventBeatFactory>("synchronous");
+
+ runtimeExecutor_ =
+ contextContainer->getInstance<RuntimeExecutor>("runtime-executor");
+
+ reactNativeConfig_ =
+ contextContainer->getInstance<std::shared_ptr<const ReactNativeConfig>>(
+ "ReactNativeConfig");
+
+ auto uiManager = std::make_unique<UIManager>();
+ auto &uiManagerRef = *uiManager;
+ uiManagerBinding_ = std::make_shared<UIManagerBinding>(std::move(uiManager));
+
+ auto eventPipe = [uiManagerBinding = uiManagerBinding_.get()](
+ jsi::Runtime &runtime,
+ const EventTarget *eventTarget,
+ const std::string &type,
+ const ValueFactory &payloadFactory) {
+ uiManagerBinding->dispatchEvent(runtime, eventTarget, type, payloadFactory);
+ };
+
+ auto eventDispatcher = std::make_shared<EventDispatcher>(
+ eventPipe, synchronousEventBeatFactory, asynchronousEventBeatFactory);
+
+ componentDescriptorRegistry_ =
+ buildRegistryFunction(eventDispatcher, contextContainer);
+
+ uiManagerRef.setDelegate(this);
+ uiManagerRef.setShadowTreeRegistry(&shadowTreeRegistry_);
+ uiManagerRef.setComponentDescriptorRegistry(componentDescriptorRegistry_);
+
+ runtimeExecutor_([=](jsi::Runtime &runtime) {
+ UIManagerBinding::install(runtime, uiManagerBinding_);
+ });
}
Scheduler::~Scheduler() {
- uiManager_->setDelegate(nullptr);
- eventDispatcher_->setUIManager(nullptr);
+ uiManagerBinding_->invalidate();
}
-void Scheduler::registerRootTag(Tag rootTag) {
- const auto &shadowTree = std::make_shared<ShadowTree>(rootTag);
+void Scheduler::startSurface(
+ SurfaceId surfaceId,
+ const std::string &moduleName,
+ const folly::dynamic &initialProps,
+ const LayoutConstraints &layoutConstraints,
+ const LayoutContext &layoutContext) const {
+ SystraceSection s("Scheduler::startSurface");
+
+ auto shadowTree =
+ std::make_unique<ShadowTree>(surfaceId, layoutConstraints, layoutContext);
shadowTree->setDelegate(this);
- shadowTreeRegistry_.insert({rootTag, shadowTree});
-}
-void Scheduler::unregisterRootTag(Tag rootTag) {
- const auto &iterator = shadowTreeRegistry_.find(rootTag);
- const auto &shadowTree = iterator->second;
- assert(shadowTree);
- shadowTree->setDelegate(nullptr);
- shadowTreeRegistry_.erase(iterator);
-}
+ shadowTreeRegistry_.add(std::move(shadowTree));
-Size Scheduler::measure(const Tag &rootTag, const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const {
- const auto &shadowTree = shadowTreeRegistry_.at(rootTag);
- assert(shadowTree);
- return shadowTree->measure(layoutConstraints, layoutContext);
+#ifndef ANDROID
+ runtimeExecutor_([=](jsi::Runtime &runtime) {
+ uiManagerBinding_->startSurface(
+ runtime, surfaceId, moduleName, initialProps);
+ });
+#endif
+}
+
+void Scheduler::renderTemplateToSurface(
+ SurfaceId surfaceId,
+ const std::string &uiTemplate) {
+ SystraceSection s("Scheduler::renderTemplateToSurface");
+ long commitStartTime = getTime();
+
+ try {
+ if (uiTemplate.size() == 0) {
+ return;
+ }
+ NativeModuleRegistry nMR;
+ auto tree = UITemplateProcessor::buildShadowTree(
+ uiTemplate,
+ surfaceId,
+ folly::dynamic::object(),
+ *componentDescriptorRegistry_,
+ nMR,
+ reactNativeConfig_);
+
+ shadowTreeRegistry_.visit(surfaceId, [=](const ShadowTree &shadowTree) {
+ return shadowTree.tryCommit(
+ [&](const SharedRootShadowNode &oldRootShadowNode) {
+ return std::make_shared<RootShadowNode>(
+ *oldRootShadowNode,
+ ShadowNodeFragment{.children =
+ std::make_shared<SharedShadowNodeList>(
+ SharedShadowNodeList{tree})});
+ },
+ commitStartTime);
+ });
+ } catch (const std::exception &e) {
+ LOG(ERROR) << " >>>> EXCEPTION <<< rendering uiTemplate in "
+ << "Scheduler::renderTemplateToSurface: " << e.what();
+ }
}
-void Scheduler::constraintLayout(const Tag &rootTag, const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) {
- const auto &shadowTree = shadowTreeRegistry_.at(rootTag);
- assert(shadowTree);
- return shadowTree->constraintLayout(layoutConstraints, layoutContext);
+void Scheduler::stopSurface(SurfaceId surfaceId) const {
+ SystraceSection s("Scheduler::stopSurface");
+
+ long commitStartTime = getTime();
+ shadowTreeRegistry_.visit(
+ surfaceId, [commitStartTime](const ShadowTree &shadowTree) {
+ // As part of stopping the Surface, we have to commit an empty tree.
+ return shadowTree.tryCommit(
+ [&](const SharedRootShadowNode &oldRootShadowNode) {
+ return std::make_shared<RootShadowNode>(
+ *oldRootShadowNode,
+ ShadowNodeFragment{
+ .children =
+ ShadowNode::emptySharedShadowNodeSharedList()});
+ },
+ commitStartTime);
+ });
+
+ auto shadowTree = shadowTreeRegistry_.remove(surfaceId);
+ shadowTree->setDelegate(nullptr);
+
+#ifndef ANDROID
+ runtimeExecutor_([=](jsi::Runtime &runtime) {
+ uiManagerBinding_->stopSurface(runtime, surfaceId);
+ });
+#endif
+}
+
+Size Scheduler::measureSurface(
+ SurfaceId surfaceId,
+ const LayoutConstraints &layoutConstraints,
+ const LayoutContext &layoutContext) const {
+ SystraceSection s("Scheduler::measureSurface");
+
+ long commitStartTime = getTime();
+
+ Size size;
+ shadowTreeRegistry_.visit(surfaceId, [&](const ShadowTree &shadowTree) {
+ shadowTree.tryCommit(
+ [&](const SharedRootShadowNode &oldRootShadowNode) {
+ auto rootShadowNode =
+ oldRootShadowNode->clone(layoutConstraints, layoutContext);
+ rootShadowNode->layout();
+ size = rootShadowNode->getLayoutMetrics().frame.size;
+ return nullptr;
+ },
+ commitStartTime);
+ });
+ return size;
+}
+
+void Scheduler::constraintSurfaceLayout(
+ SurfaceId surfaceId,
+ const LayoutConstraints &layoutConstraints,
+ const LayoutContext &layoutContext) const {
+ SystraceSection s("Scheduler::constraintSurfaceLayout");
+
+ long commitStartTime = getTime();
+
+ shadowTreeRegistry_.visit(surfaceId, [&](const ShadowTree &shadowTree) {
+ shadowTree.commit(
+ [&](const SharedRootShadowNode &oldRootShadowNode) {
+ return oldRootShadowNode->clone(layoutConstraints, layoutContext);
+ },
+ commitStartTime);
+ });
}
#pragma mark - Delegate
@@ -70,32 +202,54 @@
#pragma mark - ShadowTreeDelegate
-void Scheduler::shadowTreeDidCommit(const SharedShadowTree &shadowTree, const TreeMutationInstructionList &instructions) {
+void Scheduler::shadowTreeDidCommit(
+ const ShadowTree &shadowTree,
+ const ShadowViewMutationList &mutations,
+ long commitStartTime,
+ long layoutTime) const {
+ SystraceSection s("Scheduler::shadowTreeDidCommit");
+
if (delegate_) {
- delegate_->schedulerDidComputeMutationInstructions(shadowTree->getRootTag(), instructions);
+ delegate_->schedulerDidFinishTransaction(
+ shadowTree.getSurfaceId(), mutations, commitStartTime, layoutTime);
}
}
#pragma mark - UIManagerDelegate
-void Scheduler::uiManagerDidFinishTransaction(Tag rootTag, const SharedShadowNodeUnsharedList &rootChildNodes) {
- const auto &iterator = shadowTreeRegistry_.find(rootTag);
- const auto &shadowTree = iterator->second;
- assert(shadowTree);
- return shadowTree->complete(rootChildNodes);
-}
+void Scheduler::uiManagerDidFinishTransaction(
+ SurfaceId surfaceId,
+ const SharedShadowNodeUnsharedList &rootChildNodes,
+ long startCommitTime) {
+ SystraceSection s("Scheduler::uiManagerDidFinishTransaction");
+
+ shadowTreeRegistry_.visit(surfaceId, [&](const ShadowTree &shadowTree) {
+ shadowTree.commit(
+ [&](const SharedRootShadowNode &oldRootShadowNode) {
+ return std::make_shared<RootShadowNode>(
+ *oldRootShadowNode,
+ ShadowNodeFragment{.children = rootChildNodes});
+ },
+ startCommitTime);
+ });
+}
+
+void Scheduler::uiManagerDidCreateShadowNode(
+ const SharedShadowNode &shadowNode) {
+ SystraceSection s("Scheduler::uiManagerDidCreateShadowNode");
-void Scheduler::uiManagerDidCreateShadowNode(const SharedShadowNode &shadowNode) {
if (delegate_) {
- delegate_->schedulerDidRequestPreliminaryViewAllocation(shadowNode->getComponentName());
+ auto layoutableShadowNode =
+ dynamic_cast<const LayoutableShadowNode *>(shadowNode.get());
+ auto isLayoutable = layoutableShadowNode != nullptr;
+
+ delegate_->schedulerDidRequestPreliminaryViewAllocation(
+ shadowNode->getRootTag(),
+ shadowNode->getComponentName(),
+ isLayoutable,
+ shadowNode->getComponentHandle());
}
}
-#pragma mark - Deprecated
-
-std::shared_ptr<FabricUIManager> Scheduler::getUIManager_DO_NOT_USE() {
- return uiManager_;
-}
-
} // namespace react
} // namespace facebook

ReactCommon/fabric/uimanager/SchedulerDelegate.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -7,9 +7,9 @@
#include <memory>
-#include <fabric/core/ReactPrimitives.h>
-#include <fabric/core/ShadowNode.h>
-#include <fabric/uimanager/TreeMutationInstruction.h>
+#include <react/core/ReactPrimitives.h>
+#include <react/core/ShadowNode.h>
+#include <react/mounting/ShadowViewMutation.h>
namespace facebook {
namespace react {
@@ -18,21 +18,28 @@
* Abstract class for Scheduler's delegate.
*/
class SchedulerDelegate {
-public:
-
- virtual ~SchedulerDelegate() = default;
-
+ public:
/*
* Called right after Scheduler computed (and laid out) a new updated version
- * of the tree and calculated a set of mutation instructions which are
- * suffisient to construct a new one.
+ * of the tree and calculated a set of mutations which are suffisient
+ * to construct a new one.
*/
- virtual void schedulerDidComputeMutationInstructions(Tag rootTag, const TreeMutationInstructionList &instructions) = 0;
+ virtual void schedulerDidFinishTransaction(
+ Tag rootTag,
+ const ShadowViewMutationList &mutations,
+ const long commitStartTime,
+ const long layoutTime) = 0;
/*
* Called right after a new ShadowNode was created.
*/
- virtual void schedulerDidRequestPreliminaryViewAllocation(ComponentName componentName) = 0;
+ virtual void schedulerDidRequestPreliminaryViewAllocation(
+ SurfaceId surfaceId,
+ ComponentName componentName,
+ bool isLayoutable,
+ ComponentHandle componentHandle) = 0;
+
+ virtual ~SchedulerDelegate() noexcept = default;
};
} // namespace react

ReactCommon/fabric/uimanager/SchedulerEventDispatcher.cpp

@@ -1,51 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#include "SchedulerEventDispatcher.h"
-
-namespace facebook {
-namespace react {
-
-// TODO(T29874519): Get rid of "top" prefix once and for all.
-/*
- * Capitalizes the first letter of the event type and adds "top" prefix
- * (e.g. "layout" becames "topLayout").
- */
-static std::string normalizeEventType(const std::string &type) {
- std::string prefixedType = type;
- prefixedType[0] = toupper(prefixedType[0]);
- prefixedType.insert(0, "top");
- return prefixedType;
-}
-
-void SchedulerEventDispatcher::setUIManager(std::shared_ptr<const FabricUIManager> uiManager) const {
- uiManager_ = uiManager;
-}
-
-void SchedulerEventDispatcher::dispatchEvent(
- const EventTarget &eventTarget,
- const std::string &type,
- const folly::dynamic &payload,
- const EventPriority &priority
-) const {
- if (!uiManager_) {
- return;
- }
- // TODO: Schedule the event based on priority.
- uiManager_->dispatchEventToTarget(eventTarget, normalizeEventType(type), payload);
-}
-
-void SchedulerEventDispatcher::releaseEventTarget(const EventTarget &eventTarget) const {
- if (!uiManager_) {
- return;
- }
- // TODO(shergin): This needs to move to the destructor of EventEmitter. For now we'll leak.
- // uiManager_->releaseEventTarget(eventTarget);
-}
-
-} // namespace react
-} // namespace facebook

ReactCommon/fabric/uimanager/SchedulerEventDispatcher.h

@@ -1,51 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#pragma once
-
-#include <fabric/events/EventDispatcher.h>
-#include <fabric/events/primitives.h>
-#include <fabric/uimanager/FabricUIManager.h>
-#include <folly/dynamic.h>
-
-namespace facebook {
-namespace react {
-
-class SchedulerEventDispatcher;
-
-using SharedSchedulerEventDispatcher = std::shared_ptr<const SchedulerEventDispatcher>;
-
-/*
- * Concrete EventDispatcher.
- */
-class SchedulerEventDispatcher final:
- public EventDispatcher {
-
-public:
-
- void setUIManager(std::shared_ptr<const FabricUIManager> uiManager) const;
-
-#pragma mark - EventDispatcher
-
- void dispatchEvent(
- const EventTarget &eventTarget,
- const std::string &type,
- const folly::dynamic &payload,
- const EventPriority &priority
- ) const override;
-
-
- void releaseEventTarget(const EventTarget &eventTarget) const override;
-
-private:
-
- // TODO: consider using std::weak_ptr<> instead for better memory management.
- mutable std::shared_ptr<const FabricUIManager> uiManager_;
-};
-
-} // namespace react
-} // namespace facebook

ReactCommon/fabric/uimanager/Scheduler.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -6,40 +6,66 @@
#pragma once
#include <memory>
+#include <mutex>
-#include <fabric/core/ComponentDescriptor.h>
-#include <fabric/core/LayoutConstraints.h>
-#include <fabric/uimanager/ContextContainer.h>
-#include <fabric/uimanager/SchedulerDelegate.h>
-#include <fabric/uimanager/SchedulerEventDispatcher.h>
-#include <fabric/uimanager/UIManagerDelegate.h>
-#include <fabric/uimanager/ShadowTree.h>
-#include <fabric/uimanager/ShadowTreeDelegate.h>
+#include <react/config/ReactNativeConfig.h>
+#include <react/core/ComponentDescriptor.h>
+#include <react/core/LayoutConstraints.h>
+#include <react/uimanager/ComponentDescriptorFactory.h>
+#include <react/uimanager/ComponentDescriptorRegistry.h>
+#include <react/uimanager/ContextContainer.h>
+#include <react/uimanager/SchedulerDelegate.h>
+#include <react/uimanager/ShadowTree.h>
+#include <react/uimanager/ShadowTreeDelegate.h>
+#include <react/uimanager/ShadowTreeRegistry.h>
+#include <react/uimanager/UIManagerBinding.h>
+#include <react/uimanager/UIManagerDelegate.h>
+#include <react/uimanager/primitives.h>
namespace facebook {
namespace react {
-class FabricUIManager;
-
/*
* Scheduler coordinates Shadow Tree updates and event flows.
*/
-class Scheduler final:
- public UIManagerDelegate,
- public ShadowTreeDelegate {
-
-public:
-
- Scheduler(const SharedContextContainer &contextContainer);
+class Scheduler final : public UIManagerDelegate, public ShadowTreeDelegate {
+ public:
+ Scheduler(
+ const SharedContextContainer &contextContainer,
+ ComponentRegistryFactory buildRegistryFunction);
~Scheduler();
-#pragma mark - Shadow Tree Management
+#pragma mark - Surface Management
- void registerRootTag(Tag rootTag);
- void unregisterRootTag(Tag rootTag);
+ void startSurface(
+ SurfaceId surfaceId,
+ const std::string &moduleName,
+ const folly::dynamic &initialProps,
+ const LayoutConstraints &layoutConstraints = {},
+ const LayoutContext &layoutContext = {}) const;
+
+ void renderTemplateToSurface(
+ SurfaceId surfaceId,
+ const std::string &uiTemplate);
+
+ void stopSurface(SurfaceId surfaceId) const;
+
+ Size measureSurface(
+ SurfaceId surfaceId,
+ const LayoutConstraints &layoutConstraints,
+ const LayoutContext &layoutContext) const;
- Size measure(const Tag &rootTag, const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const;
- void constraintLayout(const Tag &rootTag, const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext);
+ /*
+ * Applies given `layoutConstraints` and `layoutContext` to a Surface.
+ * The user interface will be relaid out as a result. The operation will be
+ * performed synchronously (including mounting) if the method is called
+ * on the main thread.
+ * Can be called from any thread.
+ */
+ void constraintSurfaceLayout(
+ SurfaceId surfaceId,
+ const LayoutConstraints &layoutConstraints,
+ const LayoutContext &layoutContext) const;
#pragma mark - Delegate
@@ -53,27 +79,28 @@
#pragma mark - UIManagerDelegate
- void uiManagerDidFinishTransaction(Tag rootTag, const SharedShadowNodeUnsharedList &rootChildNodes) override;
- void uiManagerDidCreateShadowNode(const SharedShadowNode &shadowNode) override;
+ void uiManagerDidFinishTransaction(
+ SurfaceId surfaceId,
+ const SharedShadowNodeUnsharedList &rootChildNodes,
+ long startCommitTime) override;
+ void uiManagerDidCreateShadowNode(
+ const SharedShadowNode &shadowNode) override;
#pragma mark - ShadowTreeDelegate
- void shadowTreeDidCommit(const SharedShadowTree &shadowTree, const TreeMutationInstructionList &instructions) override;
-
-#pragma mark - Deprecated
-
- /*
- * UIManager instance must be temporarily exposed for registration purposes.
- */
- std::shared_ptr<FabricUIManager> getUIManager_DO_NOT_USE();
-
-private:
+ void shadowTreeDidCommit(
+ const ShadowTree &shadowTree,
+ const ShadowViewMutationList &mutations,
+ long commitStartTime,
+ long layoutTime) const override;
+ private:
SchedulerDelegate *delegate_;
- std::shared_ptr<FabricUIManager> uiManager_;
- std::unordered_map<Tag, SharedShadowTree> shadowTreeRegistry_;
- SharedSchedulerEventDispatcher eventDispatcher_;
- SharedContextContainer contextContainer_;
+ SharedComponentDescriptorRegistry componentDescriptorRegistry_;
+ ShadowTreeRegistry shadowTreeRegistry_;
+ RuntimeExecutor runtimeExecutor_;
+ std::shared_ptr<UIManagerBinding> uiManagerBinding_;
+ std::shared_ptr<const ReactNativeConfig> reactNativeConfig_;
};
} // namespace react

ReactCommon/fabric/uimanager/ShadowTree.cpp

@@ -1,165 +1,248 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
#include "ShadowTree.h"
-#include <fabric/core/LayoutContext.h>
-#include <fabric/core/LayoutPrimitives.h>
+#include <react/core/LayoutContext.h>
+#include <react/core/LayoutPrimitives.h>
+#include <react/debug/SystraceSection.h>
+#include <react/mounting/Differentiator.h>
+#include <react/mounting/ShadowViewMutation.h>
+#include <react/uimanager/TimeUtils.h>
#include "ShadowTreeDelegate.h"
-#include "Differentiator.h"
-#include "TreeMutationInstruction.h"
namespace facebook {
namespace react {
-ShadowTree::ShadowTree(Tag rootTag):
- rootTag_(rootTag) {
+static void updateMountedFlag(
+ const SharedShadowNodeList &oldChildren,
+ const SharedShadowNodeList &newChildren) {
+ // This is a simplified version of Diffing algorithm that only updates
+ // `mounted` flag on `ShadowNode`s. The algorithm sets "mounted" flag before
+ // "unmounted" to allow `ShadowNode` detect a situation where the node was
+ // remounted.
+
+ if (&oldChildren == &newChildren) {
+ // Lists are identical, nothing to do.
+ return;
+ }
+
+ if (oldChildren.size() == 0 && newChildren.size() == 0) {
+ // Both lists are empty, nothing to do.
+ return;
+ }
+
+ int index;
+
+ // Stage 1: Mount and unmount "updated" children.
+ for (index = 0; index < oldChildren.size() && index < newChildren.size();
+ index++) {
+ const auto &oldChild = oldChildren[index];
+ const auto &newChild = newChildren[index];
+
+ if (oldChild == newChild) {
+ // Nodes are identical, skipping the subtree.
+ continue;
+ }
+
+ if (oldChild->getTag() != newChild->getTag()) {
+ // Totally different nodes, updating is impossible.
+ break;
+ }
+
+ newChild->setMounted(true);
+ oldChild->setMounted(false);
+
+ updateMountedFlag(oldChild->getChildren(), newChild->getChildren());
+ }
+
+ int lastIndexAfterFirstStage = index;
+
+ // State 2: Mount new children.
+ for (index = lastIndexAfterFirstStage; index < newChildren.size(); index++) {
+ const auto &newChild = newChildren[index];
+ newChild->setMounted(true);
+ updateMountedFlag({}, newChild->getChildren());
+ }
+
+ // State 3: Unmount old children.
+ for (index = lastIndexAfterFirstStage; index < oldChildren.size(); index++) {
+ const auto &oldChild = oldChildren[index];
+ oldChild->setMounted(false);
+ updateMountedFlag(oldChild->getChildren(), {});
+ }
+}
+
+ShadowTree::ShadowTree(
+ SurfaceId surfaceId,
+ const LayoutConstraints &layoutConstraints,
+ const LayoutContext &layoutContext)
+ : surfaceId_(surfaceId) {
+ const auto noopEventEmitter = std::make_shared<const ViewEventEmitter>(
+ nullptr, -1, std::shared_ptr<const EventDispatcher>());
+
+ const auto props = std::make_shared<const RootProps>(
+ *RootShadowNode::defaultSharedProps(), layoutConstraints, layoutContext);
- const auto noopEventEmitter = std::make_shared<const ViewEventEmitter>(nullptr, rootTag, nullptr);
rootShadowNode_ = std::make_shared<RootShadowNode>(
- ShadowNodeFragment {
- .tag = rootTag,
- .rootTag = rootTag,
- .props = RootShadowNode::defaultSharedProps(),
+ ShadowNodeFragment{
+ .tag = surfaceId,
+ .rootTag = surfaceId,
+ .props = props,
.eventEmitter = noopEventEmitter,
- .children = ShadowNode::emptySharedShadowNodeSharedList(),
},
- nullptr
- );
+ nullptr);
}
-Tag ShadowTree::getRootTag() const {
- return rootTag_;
+ShadowTree::~ShadowTree() {
+ commit(
+ [](const SharedRootShadowNode &oldRootShadowNode) {
+ return std::make_shared<RootShadowNode>(
+ *oldRootShadowNode,
+ ShadowNodeFragment{
+ .children = ShadowNode::emptySharedShadowNodeSharedList()});
+ },
+ getTime());
}
-#pragma mark - Layout
-
-Size ShadowTree::measure(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const {
- auto newRootShadowNode = cloneRootShadowNode(layoutConstraints, layoutContext);
- newRootShadowNode->layout();
- return newRootShadowNode->getLayoutMetrics().frame.size;
+Tag ShadowTree::getSurfaceId() const {
+ return surfaceId_;
}
-void ShadowTree::constraintLayout(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) {
- auto newRootShadowNode = cloneRootShadowNode(layoutConstraints, layoutContext);
- complete(newRootShadowNode);
-}
+void ShadowTree::commit(
+ ShadowTreeCommitTransaction transaction,
+ long commitStartTime,
+ int *revision) const {
+ SystraceSection s("ShadowTree::commit");
-#pragma mark - Commiting
+ int attempts = 0;
-UnsharedRootShadowNode ShadowTree::cloneRootShadowNode(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const {
- auto oldRootShadowNode = rootShadowNode_;
- const auto &props = std::make_shared<const RootProps>(*oldRootShadowNode->getProps(), layoutConstraints, layoutContext);
- auto newRootShadowNode =
- std::make_shared<RootShadowNode>(*oldRootShadowNode, ShadowNodeFragment {.props = props});
- return newRootShadowNode;
+ while (true) {
+ attempts++;
+ if (tryCommit(transaction, commitStartTime, revision)) {
+ return;
+ }
+
+ // After multiple attempts, we failed to commit the transaction.
+ // Something internally went terribly wrong.
+ assert(attempts < 1024);
+ }
}
-void ShadowTree::complete(const SharedShadowNodeUnsharedList &rootChildNodes) {
- auto oldRootShadowNode = rootShadowNode_;
- auto newRootShadowNode =
- std::make_shared<RootShadowNode>(
- *oldRootShadowNode,
- ShadowNodeFragment {
- .children = SharedShadowNodeSharedList(rootChildNodes)
+bool ShadowTree::tryCommit(
+ ShadowTreeCommitTransaction transaction,
+ long commitStartTime,
+ int *revision) const {
+ SystraceSection s("ShadowTree::tryCommit");
+
+ SharedRootShadowNode oldRootShadowNode;
+
+ {
+ // Reading `rootShadowNode_` in shared manner.
+ std::shared_lock<folly::SharedMutex> lock(commitMutex_);
+ oldRootShadowNode = rootShadowNode_;
}
- );
- complete(newRootShadowNode);
-}
+ UnsharedRootShadowNode newRootShadowNode = transaction(oldRootShadowNode);
-void ShadowTree::complete(UnsharedRootShadowNode newRootShadowNode) {
- SharedRootShadowNode oldRootShadowNode = rootShadowNode_;
+ if (!newRootShadowNode) {
+ return false;
+ }
+ long layoutTime = getTime();
newRootShadowNode->layout();
-
+ layoutTime = getTime() - layoutTime;
newRootShadowNode->sealRecursive();
- TreeMutationInstructionList instructions = TreeMutationInstructionList();
+ auto mutations =
+ calculateShadowViewMutations(*oldRootShadowNode, *newRootShadowNode);
- calculateMutationInstructions(
- instructions,
- oldRootShadowNode,
- newRootShadowNode
- );
+ {
+ // Updating `rootShadowNode_` in unique manner if it hasn't changed.
+ std::unique_lock<folly::SharedMutex> lock(commitMutex_);
- if (commit(oldRootShadowNode, newRootShadowNode)) {
- emitLayoutEvents(instructions);
+ if (rootShadowNode_ != oldRootShadowNode) {
+ return false;
+ }
- if (delegate_) {
- delegate_->shadowTreeDidCommit(shared_from_this(), instructions);
+ rootShadowNode_ = newRootShadowNode;
+
+ {
+ std::lock_guard<std::mutex> dispatchLock(EventEmitter::DispatchMutex());
+
+ updateMountedFlag(
+ oldRootShadowNode->getChildren(), newRootShadowNode->getChildren());
+ }
+
+ revision_++;
+
+ // Returning last revision if requested.
+ if (revision) {
+ *revision = revision_;
}
}
-}
-bool ShadowTree::commit(const SharedRootShadowNode &oldRootShadowNode, const SharedRootShadowNode &newRootShadowNode) {
- std::lock_guard<std::mutex> lock(commitMutex_);
+ emitLayoutEvents(mutations);
- if (oldRootShadowNode != rootShadowNode_) {
- return false;
+ if (delegate_) {
+ delegate_->shadowTreeDidCommit(
+ *this, mutations, commitStartTime, layoutTime);
}
- rootShadowNode_ = newRootShadowNode;
return true;
}
-void ShadowTree::emitLayoutEvents(const TreeMutationInstructionList &instructions) {
- for (const auto &instruction : instructions) {
- const auto &type = instruction.getType();
-
- // Only `Insertion` and `Replacement` instructions can affect layout metrics.
- if (
- type == TreeMutationInstruction::Insertion ||
- type == TreeMutationInstruction::Replacement
- ) {
- const auto &newShadowNode = instruction.getNewChildNode();
- const auto &eventEmitter = newShadowNode->getEventEmitter();
- const auto &viewEventEmitter = std::dynamic_pointer_cast<const ViewEventEmitter>(eventEmitter);
-
- // Checking if particular shadow node supports `onLayout` event (part of `ViewEventEmitter`).
- if (viewEventEmitter) {
- // Now we know that both (old and new) shadow nodes must be `LayoutableShadowNode` subclasses.
- assert(std::dynamic_pointer_cast<const LayoutableShadowNode>(newShadowNode));
-
- // Checking if the `onLayout` event was requested for the particular Shadow Node.
- const auto &viewProps = std::dynamic_pointer_cast<const ViewProps>(newShadowNode->getProps());
- if (viewProps && !viewProps->onLayout) {
+void ShadowTree::emitLayoutEvents(
+ const ShadowViewMutationList &mutations) const {
+ SystraceSection s("ShadowTree::emitLayoutEvents");
+
+ for (const auto &mutation : mutations) {
+ // Only `Insert` and `Update` mutations can affect layout metrics.
+ if (mutation.type != ShadowViewMutation::Insert &&
+ mutation.type != ShadowViewMutation::Update) {
continue;
}
- // TODO(T29661055): Consider using `std::reinterpret_pointer_cast`.
- const auto &newLayoutableShadowNode =
- std::dynamic_pointer_cast<const LayoutableShadowNode>(newShadowNode);
-
- // In case if we have `oldShadowNode`, we have to check that layout metrics have changed.
- if (type == TreeMutationInstruction::Replacement) {
- const auto &oldShadowNode = instruction.getOldChildNode();
- assert(std::dynamic_pointer_cast<const LayoutableShadowNode>(oldShadowNode));
- // TODO(T29661055): Consider using `std::reinterpret_pointer_cast`.
- const auto &oldLayoutableShadowNode =
- std::dynamic_pointer_cast<const LayoutableShadowNode>(oldShadowNode);
-
- if (oldLayoutableShadowNode->getLayoutMetrics() == newLayoutableShadowNode->getLayoutMetrics()) {
+ const auto viewEventEmitter =
+ std::dynamic_pointer_cast<const ViewEventEmitter>(
+ mutation.newChildShadowView.eventEmitter);
+
+ // Checking if particular shadow node supports `onLayout` event (part of
+ // `ViewEventEmitter`).
+ if (!viewEventEmitter) {
continue;
}
- }
- viewEventEmitter->onLayout(newLayoutableShadowNode->getLayoutMetrics());
+ // Checking if the `onLayout` event was requested for the particular Shadow
+ // Node.
+ const auto viewProps = std::dynamic_pointer_cast<const ViewProps>(
+ mutation.newChildShadowView.props);
+ if (viewProps && !viewProps->onLayout) {
+ continue;
}
+
+ // In case if we have `oldChildShadowView`, checking that layout metrics
+ // have changed.
+ if (mutation.type != ShadowViewMutation::Update &&
+ mutation.oldChildShadowView.layoutMetrics ==
+ mutation.newChildShadowView.layoutMetrics) {
+ continue;
}
+
+ viewEventEmitter->onLayout(mutation.newChildShadowView.layoutMetrics);
}
}
#pragma mark - Delegate
-void ShadowTree::setDelegate(ShadowTreeDelegate *delegate) {
+void ShadowTree::setDelegate(ShadowTreeDelegate const *delegate) {
delegate_ = delegate;
}
-ShadowTreeDelegate *ShadowTree::getDelegate() const {
+ShadowTreeDelegate const *ShadowTree::getDelegate() const {
return delegate_;
}

ReactCommon/fabric/uimanager/ShadowTreeDelegate.h

@@ -1,11 +1,11 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
#pragma once
-#include <fabric/uimanager/TreeMutationInstruction.h>
+#include <react/mounting/ShadowViewMutation.h>
namespace facebook {
namespace react {
@@ -16,12 +16,17 @@
* Abstract class for ShadowTree's delegate.
*/
class ShadowTreeDelegate {
-public:
-
+ public:
/*
* Called right after Shadow Tree commit a new state of the the tree.
*/
- virtual void shadowTreeDidCommit(const std::shared_ptr<ShadowTree> &shadowTree, const TreeMutationInstructionList &instructions) = 0;
+ virtual void shadowTreeDidCommit(
+ const ShadowTree &shadowTree,
+ const ShadowViewMutationList &mutations,
+ long commitStartTime,
+ long layoutTime) const = 0;
+
+ virtual ~ShadowTreeDelegate() noexcept = default;
};
} // namespace react

ReactCommon/fabric/uimanager/ShadowTree.h

@@ -1,67 +1,67 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
#pragma once
+#include <folly/SharedMutex.h>
#include <memory>
-#include <mutex>
+#include <shared_mutex>
-#include <fabric/components/root/RootShadowNode.h>
-#include <fabric/core/LayoutConstraints.h>
-#include <fabric/core/ReactPrimitives.h>
-#include <fabric/core/ShadowNode.h>
-#include <fabric/uimanager/ShadowTreeDelegate.h>
+#include <react/components/root/RootShadowNode.h>
+#include <react/core/LayoutConstraints.h>
+#include <react/core/ReactPrimitives.h>
+#include <react/core/ShadowNode.h>
+#include <react/mounting/ShadowViewMutation.h>
+#include <react/uimanager/ShadowTreeDelegate.h>
namespace facebook {
namespace react {
-class ShadowTree;
-
-using SharedShadowTree = std::shared_ptr<ShadowTree>;
+using ShadowTreeCommitTransaction = std::function<UnsharedRootShadowNode(
+ const SharedRootShadowNode &oldRootShadowNode)>;
/*
* Represents the shadow tree and its lifecycle.
*/
-class ShadowTree final:
- public std::enable_shared_from_this<ShadowTree> {
-
-public:
-
- /*
- * Creates a new shadow tree instance with given `rootTag`.
- */
- ShadowTree(Tag rootTag);
-
+class ShadowTree final {
+ public:
/*
- * Returns the rootTag associated with the shadow tree (the tag of the
- * root shadow node).
+ * Creates a new shadow tree instance.
*/
- Tag getRootTag() const;
+ ShadowTree(
+ SurfaceId surfaceId,
+ const LayoutConstraints &layoutConstraints,
+ const LayoutContext &layoutContext);
-#pragma mark - Layout
+ ~ShadowTree();
/*
- * Measures the shadow tree with given `layoutConstraints` and `layoutContext`.
- * Can be called from any thread, side-effect-less.
+ * Returns the `SurfaceId` associated with the shadow tree.
*/
- Size measure(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const;
+ SurfaceId getSurfaceId() const;
/*
- * Applies given `layoutConstraints` and `layoutContext` and commit
- * the new shadow tree.
- * Can be called from any thread.
+ * Performs commit calling `transaction` function with a `oldRootShadowNode`
+ * and expecting a `newRootShadowNode` as a return value.
+ * The `transaction` function can abort commit returning `nullptr`.
+ * If a `revision` pointer is not null, the method will store there a
+ * contiguous revision number of the successfully performed transaction.
+ * Returns `true` if the operation finished successfully.
*/
- void constraintLayout(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext);
-
-#pragma mark - Application
+ bool tryCommit(
+ ShadowTreeCommitTransaction transaction,
+ long commitStartTime,
+ int *revision = nullptr) const;
/*
- * Create a new shadow tree with given `rootChildNodes` and commit.
- * Can be called from any thread.
+ * Calls `tryCommit` in a loop until it finishes successfully.
*/
- void complete(const SharedShadowNodeUnsharedList &rootChildNodes);
+ void commit(
+ ShadowTreeCommitTransaction transaction,
+ long commitStartTime,
+ int *revision = nullptr) const;
#pragma mark - Delegate
@@ -70,20 +70,22 @@
* The delegate is stored as a raw pointer, so the owner must null
* the pointer before being destroyed.
*/
- void setDelegate(ShadowTreeDelegate *delegate);
- ShadowTreeDelegate *getDelegate() const;
-
-private:
+ void setDelegate(ShadowTreeDelegate const *delegate);
+ ShadowTreeDelegate const *getDelegate() const;
- UnsharedRootShadowNode cloneRootShadowNode(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const;
- void complete(UnsharedRootShadowNode newRootShadowNode);
- bool commit(const SharedRootShadowNode &oldRootShadowNode, const SharedRootShadowNode &newRootShadowNode);
- void emitLayoutEvents(const TreeMutationInstructionList &instructions);
-
- const Tag rootTag_;
- SharedRootShadowNode rootShadowNode_;
- ShadowTreeDelegate *delegate_;
- mutable std::mutex commitMutex_;
+ private:
+ UnsharedRootShadowNode cloneRootShadowNode(
+ const SharedRootShadowNode &oldRootShadowNode,
+ const LayoutConstraints &layoutConstraints,
+ const LayoutContext &layoutContext) const;
+
+ void emitLayoutEvents(const ShadowViewMutationList &mutations) const;
+
+ const SurfaceId surfaceId_;
+ mutable folly::SharedMutex commitMutex_;
+ mutable SharedRootShadowNode rootShadowNode_; // Protected by `commitMutex_`.
+ mutable int revision_{1}; // Protected by `commitMutex_`.
+ ShadowTreeDelegate const *delegate_;
};
} // namespace react

ReactCommon/fabric/uimanager/ShadowTreeRegistry.cpp

@@ -0,0 +1,43 @@
+// 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.
+
+#include "ShadowTreeRegistry.h"
+
+namespace facebook {
+namespace react {
+
+void ShadowTreeRegistry::add(std::unique_ptr<ShadowTree> &&shadowTree) const {
+ std::unique_lock<folly::SharedMutex> lock(mutex_);
+
+ registry_.emplace(shadowTree->getSurfaceId(), std::move(shadowTree));
+}
+
+std::unique_ptr<ShadowTree> ShadowTreeRegistry::remove(
+ SurfaceId surfaceId) const {
+ std::unique_lock<folly::SharedMutex> lock(mutex_);
+
+ auto iterator = registry_.find(surfaceId);
+ auto shadowTree = std::unique_ptr<ShadowTree>(iterator->second.release());
+ registry_.erase(iterator);
+ return shadowTree;
+}
+
+bool ShadowTreeRegistry::visit(
+ SurfaceId surfaceId,
+ std::function<void(const ShadowTree &shadowTree)> callback) const {
+ std::shared_lock<folly::SharedMutex> lock(mutex_);
+
+ auto iterator = registry_.find(surfaceId);
+
+ if (iterator == registry_.end()) {
+ return false;
+ }
+
+ callback(*iterator->second);
+ return true;
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/uimanager/ShadowTreeRegistry.h

@@ -0,0 +1,58 @@
+// 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.
+
+#pragma once
+
+#include <folly/SharedMutex.h>
+#include <shared_mutex>
+
+#include <react/core/ReactPrimitives.h>
+#include <react/uimanager/ShadowTree.h>
+
+namespace facebook {
+namespace react {
+
+/*
+ * Owning registry of `ShadowTree`s.
+ */
+class ShadowTreeRegistry final {
+ public:
+ ShadowTreeRegistry() = default;
+
+ /*
+ * Adds a `ShadowTree` instance to the registry.
+ * The ownership of the instance is also transferred to the registry.
+ * Can be called from any thread.
+ */
+ void add(std::unique_ptr<ShadowTree> &&shadowTree) const;
+
+ /*
+ * Removes a `ShadowTree` instance with given `surfaceId` from the registry
+ * and returns it as a result.
+ * The ownership of the instance is also transferred to the caller.
+ * Can be called from any thread.
+ */
+ std::unique_ptr<ShadowTree> remove(SurfaceId surfaceId) const;
+
+ /*
+ * Finds a `ShadowTree` instance with a given `surfaceId` in the registry and
+ * synchronously calls the `callback` with a reference to the instance while
+ * the mutex is being acquired.
+ * Returns `true` if the registry has `ShadowTree` instance with corresponding
+ * `surfaceId`, otherwise returns `false` without calling the `callback`.
+ * Can be called from any thread.
+ */
+ bool visit(
+ SurfaceId surfaceId,
+ std::function<void(const ShadowTree &shadowTree)> callback) const;
+
+ private:
+ mutable folly::SharedMutex mutex_;
+ mutable std::unordered_map<SurfaceId, std::unique_ptr<ShadowTree>>
+ registry_; // Protected by `mutex_`.
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/uimanager/tests/FabricUIManagerTest.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,11 +7,11 @@
#include <memory>
-#include <fabric/uimanager/FabricUIManager.h>
#include <gtest/gtest.h>
+#include <react/uimanager/UIManager.h>
using namespace facebook::react;
-TEST(FabricUIManagerTest, testSomething) {
+TEST(UIManagerTest, testSomething) {
// TODO
}

ReactCommon/fabric/uimanager/tests/UITemplateProcessorTest.cpp

@@ -0,0 +1,179 @@
+/**
+ * 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.
+ */
+
+#include <exception>
+
+#include <gtest/gtest.h>
+#include <react/uimanager/ComponentDescriptorFactory.h>
+#include <react/uimanager/UITemplateProcessor.h>
+
+using namespace facebook::react;
+
+#include <react/components/activityindicator/ActivityIndicatorViewComponentDescriptor.h>
+#include <react/components/image/ImageComponentDescriptor.h>
+#include <react/components/scrollview/ScrollViewComponentDescriptor.h>
+#include <react/components/text/ParagraphComponentDescriptor.h>
+#include <react/components/text/RawTextComponentDescriptor.h>
+#include <react/components/text/TextComponentDescriptor.h>
+#include <react/components/view/ViewComponentDescriptor.h>
+#include <react/config/ReactNativeConfig.h>
+#include <react/uimanager/ComponentDescriptorFactory.h>
+#include <react/uimanager/ComponentDescriptorRegistry.h>
+#include <react/uimanager/ContextContainer.h>
+
+namespace facebook {
+namespace react {
+
+// TODO (T29441913): Codegen this app-specific implementation.
+ComponentRegistryFactory getDefaultComponentRegistryFactory() {
+ return [](const SharedEventDispatcher &eventDispatcher,
+ const SharedContextContainer &contextContainer) {
+ auto registry = std::make_shared<ComponentDescriptorRegistry>();
+ registry->registerComponentDescriptor(
+ std::make_shared<ViewComponentDescriptor>(eventDispatcher));
+ registry->registerComponentDescriptor(
+ std::make_shared<ImageComponentDescriptor>(
+ eventDispatcher, contextContainer));
+ registry->registerComponentDescriptor(
+ std::make_shared<ScrollViewComponentDescriptor>(eventDispatcher));
+ registry->registerComponentDescriptor(
+ std::make_shared<ParagraphComponentDescriptor>(
+ eventDispatcher, contextContainer));
+ registry->registerComponentDescriptor(
+ std::make_shared<TextComponentDescriptor>(eventDispatcher));
+ registry->registerComponentDescriptor(
+ std::make_shared<RawTextComponentDescriptor>(eventDispatcher));
+ registry->registerComponentDescriptor(
+ std::make_shared<ActivityIndicatorViewComponentDescriptor>(
+ eventDispatcher));
+ return registry;
+ };
+}
+
+bool mockSimpleTestValue_;
+
+NativeModuleRegistry buildNativeModuleRegistry();
+
+NativeModuleRegistry buildNativeModuleRegistry() {
+ NativeModuleRegistry nMR;
+ nMR.registerModule(
+ "MobileConfig",
+ [&](const std::string &methodName, const folly::dynamic &args) {
+ return mockSimpleTestValue_;
+ });
+ return nMR;
+}
+
+class MockReactNativeConfig : public ReactNativeConfig {
+ public:
+ MockReactNativeConfig() {}
+ bool getBool(const std::string &param) const override {
+ return mockSimpleTestValue_;
+ }
+
+ std::string getString(const std::string &param) const override {
+ return "";
+ }
+
+ int64_t getInt64(const std::string &param) const override {
+ return 0;
+ }
+
+ double getDouble(const std::string &param) const override {
+ return 0.0;
+ }
+};
+
+std::shared_ptr<const ReactNativeConfig> mockReactNativeConfig_ =
+ std::make_shared<const MockReactNativeConfig>();
+
+} // namespace react
+} // namespace facebook
+
+TEST(UITemplateProcessorTest, testSimpleBytecode) {
+ auto surfaceId = 11;
+ auto componentDescriptorRegistry =
+ getDefaultComponentRegistryFactory()(nullptr, nullptr);
+ auto nativeModuleRegistry = buildNativeModuleRegistry();
+
+ auto bytecode = R"delim({"version":0.1,"commands":[
+ ["createNode",2,"RCTView",-1,{"opacity": 0.5, "testId": "root"}],
+ ["createNode",4,"RCTView",2,{"testId": "child"}],
+ ["returnRoot",2]
+ ]})delim";
+
+ mockSimpleTestValue_ = true;
+
+ auto root1 = UITemplateProcessor::buildShadowTree(
+ bytecode,
+ surfaceId,
+ folly::dynamic::object(),
+ *componentDescriptorRegistry,
+ nativeModuleRegistry,
+ mockReactNativeConfig_);
+#ifndef NDEBUG
+ LOG(INFO) << std::endl << root1->getDebugDescription();
+#endif
+ auto props1 = std::dynamic_pointer_cast<const ViewProps>(root1->getProps());
+ ASSERT_NEAR(props1->opacity, 0.5, 0.001);
+ ASSERT_STREQ(props1->testId.c_str(), "root");
+ auto children1 = root1->getChildren();
+ ASSERT_EQ(children1.size(), 1);
+ auto child_props1 =
+ std::dynamic_pointer_cast<const ViewProps>(children1.at(0)->getProps());
+ ASSERT_STREQ(child_props1->testId.c_str(), "child");
+}
+
+TEST(UITemplateProcessorTest, testConditionalBytecode) {
+ auto surfaceId = 11;
+ auto componentDescriptorRegistry =
+ getDefaultComponentRegistryFactory()(nullptr, nullptr);
+ auto nativeModuleRegistry = buildNativeModuleRegistry();
+
+ auto bytecode = R"delim({"version":0.1,"commands":[
+ ["createNode",2,"RCTView",-1,{"testId": "root"}],
+ ["loadNativeBool",1,"MobileConfig","getBool",["qe:simple_test"]],
+ ["conditional",1,
+ [["createNode",4,"RCTView",2,{"testId": "cond_true"}]],
+ [["createNode",4,"RCTView",2,{"testId": "cond_false"}]]
+ ],
+ ["returnRoot",2]
+ ]})delim";
+
+ mockSimpleTestValue_ = true;
+
+ auto root1 = UITemplateProcessor::buildShadowTree(
+ bytecode,
+ surfaceId,
+ folly::dynamic::object(),
+ *componentDescriptorRegistry,
+ nativeModuleRegistry,
+ mockReactNativeConfig_);
+#ifndef NDEBUG
+ LOG(INFO) << std::endl << root1->getDebugDescription();
+#endif
+ auto props1 = std::dynamic_pointer_cast<const ViewProps>(root1->getProps());
+ ASSERT_STREQ(props1->testId.c_str(), "root");
+ auto children1 = root1->getChildren();
+ ASSERT_EQ(children1.size(), 1);
+ auto child_props1 =
+ std::dynamic_pointer_cast<const ViewProps>(children1.at(0)->getProps());
+ ASSERT_STREQ(child_props1->testId.c_str(), "cond_true");
+
+ mockSimpleTestValue_ = false;
+
+ auto root2 = UITemplateProcessor::buildShadowTree(
+ bytecode,
+ surfaceId,
+ folly::dynamic::object(),
+ *componentDescriptorRegistry,
+ nativeModuleRegistry,
+ mockReactNativeConfig_);
+ auto child_props2 = std::dynamic_pointer_cast<const ViewProps>(
+ root2->getChildren().at(0)->getProps());
+ ASSERT_STREQ(child_props2->testId.c_str(), "cond_false");
+}

ReactCommon/fabric/uimanager/TimeUtils.h

@@ -0,0 +1,30 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#pragma once
+
+namespace facebook {
+namespace react {
+
+inline static long getTime() {
+#ifdef ANDROID
+ static const int64_t NANOSECONDS_IN_SECOND = 1000000000LL;
+ static const int64_t NANOSECONDS_IN_MILLISECOND = 1000000LL;
+
+ // Since SystemClock.uptimeMillis() is commonly used for performance
+ // measurement in Java and uptimeMillis() internally uses
+ // clock_gettime(CLOCK_MONOTONIC), we use the same API here. We need that to
+ // make sure we use the same time system on both JS and Java sides. Links to
+ // the source code:
+ // https://android.googlesource.com/platform/frameworks/native/+/jb-mr1-release/libs/utils/SystemClock.cpp
+ // https://android.googlesource.com/platform/system/core/+/master/libutils/Timers.cpp
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ int64_t nano = now.tv_sec * NANOSECONDS_IN_SECOND + now.tv_nsec;
+ return nano / (double)NANOSECONDS_IN_MILLISECOND;
+#else
+ return 0l;
+#endif
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/uimanager/TreeMutationInstruction.cpp

@@ -1,203 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#include "TreeMutationInstruction.h"
-
-#include <fabric/debug/DebugStringConvertibleItem.h>
-
-namespace facebook {
-namespace react {
-
-const TreeMutationInstruction TreeMutationInstruction::Create(
- SharedShadowNode node
-) {
- assert(node);
-
- return TreeMutationInstruction(
- Creation,
- nullptr,
- nullptr,
- node,
- -1
- );
-}
-
-const TreeMutationInstruction TreeMutationInstruction::Delete(
- SharedShadowNode node
-) {
- assert(node);
-
- return TreeMutationInstruction(
- Deletion,
- nullptr,
- node,
- nullptr,
- -1
- );
-}
-
-const TreeMutationInstruction TreeMutationInstruction::Insert(
- SharedShadowNode parentNode,
- SharedShadowNode childNode,
- int index
-) {
- assert(parentNode);
- assert(childNode);
- assert(index != -1);
-
- return TreeMutationInstruction(
- Insertion,
- parentNode,
- nullptr,
- childNode,
- index
- );
-}
-
-const TreeMutationInstruction TreeMutationInstruction::Remove(
- SharedShadowNode parentNode,
- SharedShadowNode childNode,
- int index
-) {
- assert(parentNode);
- assert(childNode);
- assert(index != -1);
-
- return TreeMutationInstruction(
- Removal,
- parentNode,
- childNode,
- nullptr,
- index
- );
-}
-
-const TreeMutationInstruction TreeMutationInstruction::Replace(
- SharedShadowNode parentNode,
- SharedShadowNode oldChildNode,
- SharedShadowNode newChildNode,
- int index
-) {
- assert(oldChildNode);
- assert(newChildNode);
-
- return TreeMutationInstruction(
- Replacement,
- parentNode,
- oldChildNode,
- newChildNode,
- index
- );
-}
-
-TreeMutationInstruction::TreeMutationInstruction(
- Type type,
- SharedShadowNode parentNode,
- SharedShadowNode oldChildNode,
- SharedShadowNode newChildNode,
- int index
-):
- type_(type),
- parentNode_(parentNode),
- oldChildNode_(oldChildNode),
- newChildNode_(newChildNode),
- index_(index) {};
-
-#pragma mark - Getters
-
-TreeMutationInstruction::Type TreeMutationInstruction::getType() const {
- return type_;
-}
-
-SharedShadowNode TreeMutationInstruction::getParentNode() const {
- assert(parentNode_);
- return parentNode_;
-}
-
-SharedShadowNode TreeMutationInstruction::getOldChildNode() const {
- assert(oldChildNode_);
- return oldChildNode_;
-}
-
-SharedShadowNode TreeMutationInstruction::getNewChildNode() const {
- assert(newChildNode_);
- return newChildNode_;
-}
-
-int TreeMutationInstruction::getIndex() const {
- assert(index_ != -1);
- return index_;
-}
-
-#pragma mark - DebugStringConvertible
-
-std::string TreeMutationInstruction::getDebugName() const {
- switch (type_) {
- case Creation:
- return "Create";
- case Deletion:
- return "Delete";
- case Insertion:
- return "Insert";
- case Removal:
- return "Remove";
- case Replacement:
- return "Replace";
- }
-};
-
-std::string TreeMutationInstruction::getDebugValue() const {
- switch (type_) {
- case Creation:
- return "[*" + folly::to<std::string>(newChildNode_->getTag()) + "]";
- case Deletion:
- return "[~" + folly::to<std::string>(oldChildNode_->getTag()) + "]";
- case Insertion:
- return "[" + folly::to<std::string>(newChildNode_->getTag()) + "->" + folly::to<std::string>(parentNode_->getTag()) + "]";
- case Removal:
- return "[" + folly::to<std::string>(oldChildNode_->getTag()) + "<~" + folly::to<std::string>(parentNode_->getTag()) + "]";
- case Replacement:
- return "[=" + folly::to<std::string>(oldChildNode_->getTag()) + "]";
- }
-};
-
-SharedDebugStringConvertibleList TreeMutationInstruction::getDebugProps() const {
- DebugStringConvertibleOptions options = {.maximumDepth = 1, .format = false};
-
- switch (type_) {
- case Creation:
- return SharedDebugStringConvertibleList {
- std::make_shared<DebugStringConvertibleItem>("node", newChildNode_->getDebugDescription(options)),
- };
- case Deletion:
- return SharedDebugStringConvertibleList {
- std::make_shared<DebugStringConvertibleItem>("node", oldChildNode_->getDebugDescription(options)),
- };
- case Insertion:
- return SharedDebugStringConvertibleList {
- std::make_shared<DebugStringConvertibleItem>("parentNode", parentNode_->getDebugDescription(options)),
- std::make_shared<DebugStringConvertibleItem>("childNode", newChildNode_->getDebugDescription(options)),
- std::make_shared<DebugStringConvertibleItem>("index", folly::to<std::string>(index_))
- };
- case Removal:
- return SharedDebugStringConvertibleList {
- std::make_shared<DebugStringConvertibleItem>("parentNode", parentNode_->getDebugDescription(options)),
- std::make_shared<DebugStringConvertibleItem>("childNode", oldChildNode_->getDebugDescription(options)),
- std::make_shared<DebugStringConvertibleItem>("index", folly::to<std::string>(index_))
- };
- case Replacement:
- return SharedDebugStringConvertibleList {
- std::make_shared<DebugStringConvertibleItem>("parentNode", parentNode_ ? parentNode_->getDebugDescription(options) : "nullptr"),
- std::make_shared<DebugStringConvertibleItem>("oldChildNode", oldChildNode_->getDebugDescription(options)),
- std::make_shared<DebugStringConvertibleItem>("newChildNode", newChildNode_->getDebugDescription(options)),
- std::make_shared<DebugStringConvertibleItem>("index", folly::to<std::string>(index_))
- };
- }
-}
-
-} // namespace react
-} // namespace facebook

ReactCommon/fabric/uimanager/TreeMutationInstruction.h

@@ -1,119 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#pragma once
-
-#include <vector>
-
-#include <fabric/core/ShadowNode.h>
-#include <fabric/debug/DebugStringConvertible.h>
-
-namespace facebook {
-namespace react {
-
-class TreeMutationInstruction;
-
-using TreeMutationInstructionList = std::vector<TreeMutationInstruction>;
-
-/*
- * Describes single native views tree mutation instruction which may contain
- * pointers to an old shadow node, a new shadow node, a parent shadow node and
- * final index of inserted or updated node.
- * The relationship between native view instances and shadow node instances is
- * defined by `tag` value.
- * Use static methods to instantiate mutation instructions of different types.
- */
-class TreeMutationInstruction:
- public DebugStringConvertible {
-public:
-
-#pragma mark - Designated Initializers
-
- /*
- * Creates and returns an *Creation* instruction.
- */
- static const TreeMutationInstruction Create(
- SharedShadowNode node
- );
-
- /*
- * Creates and returns an *Deletion* instruction.
- */
- static const TreeMutationInstruction Delete(
- SharedShadowNode node
- );
-
- /*
- * Creates and returns an *Insertion* instruction.
- */
- static const TreeMutationInstruction Insert(
- SharedShadowNode parentNode,
- SharedShadowNode childNode,
- int index
- );
-
- /*
- * Creates and returns a *Removal* instruction.
- */
- static const TreeMutationInstruction Remove(
- SharedShadowNode parentNode,
- SharedShadowNode childNode,
- int index
- );
-
- /*
- * Creates and returns an *Replacement* instruction.
- */
- static const TreeMutationInstruction Replace(
- SharedShadowNode parentNode,
- SharedShadowNode oldChildNode,
- SharedShadowNode newChildNode,
- int index
- );
-
-#pragma mark - Type
-
- enum Type {
- Creation,
- Deletion,
- Insertion,
- Removal,
- Replacement
- };
-
-#pragma mark - Getters
-
- Type getType() const;
- SharedShadowNode getParentNode() const;
- SharedShadowNode getOldChildNode() const;
- SharedShadowNode getNewChildNode() const;
- int getIndex() const;
-
-#pragma mark - DebugStringConvertible
-
- std::string getDebugName() const override;
- std::string getDebugValue() const override;
- SharedDebugStringConvertibleList getDebugProps() const override;
-
-private:
- TreeMutationInstruction(
- Type type,
- SharedShadowNode parentNode,
- SharedShadowNode oldChildNode,
- SharedShadowNode newChildNode,
- int index
- );
-
- Type type_ {Creation};
- SharedShadowNode parentNode_ {nullptr};
- SharedShadowNode oldChildNode_ {nullptr};
- SharedShadowNode newChildNode_ {nullptr};
- int index_ {-1};
-};
-
-} // namespace react
-} // namespace facebook

ReactCommon/fabric/uimanager/UIManagerBinding.cpp

@@ -0,0 +1,338 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#include "UIManagerBinding.h"
+
+#include <react/debug/SystraceSection.h>
+
+#include <jsi/JSIDynamic.h>
+
+namespace facebook {
+namespace react {
+
+static jsi::Object getModule(
+ jsi::Runtime &runtime,
+ const std::string &moduleName) {
+ auto batchedBridge =
+ runtime.global().getPropertyAsObject(runtime, "__fbBatchedBridge");
+ auto getCallableModule =
+ batchedBridge.getPropertyAsFunction(runtime, "getCallableModule");
+ auto module = getCallableModule
+ .callWithThis(
+ runtime,
+ batchedBridge,
+ {jsi::String::createFromUtf8(runtime, moduleName)})
+ .asObject(runtime);
+ return module;
+}
+
+void UIManagerBinding::install(
+ jsi::Runtime &runtime,
+ std::shared_ptr<UIManagerBinding> uiManagerBinding) {
+ auto uiManagerModuleName = "nativeFabricUIManager";
+ auto object = jsi::Object::createFromHostObject(runtime, uiManagerBinding);
+ runtime.global().setProperty(runtime, uiManagerModuleName, std::move(object));
+}
+
+UIManagerBinding::UIManagerBinding(std::unique_ptr<UIManager> uiManager)
+ : uiManager_(std::move(uiManager)) {}
+
+void UIManagerBinding::startSurface(
+ jsi::Runtime &runtime,
+ SurfaceId surfaceId,
+ const std::string &moduleName,
+ const folly::dynamic &initalProps) const {
+ folly::dynamic parameters = folly::dynamic::object();
+ parameters["rootTag"] = surfaceId;
+ parameters["initialProps"] = initalProps;
+
+ auto module = getModule(runtime, "AppRegistry");
+ auto method = module.getPropertyAsFunction(runtime, "runApplication");
+
+ method.callWithThis(
+ runtime,
+ module,
+ {jsi::String::createFromUtf8(runtime, moduleName),
+ jsi::valueFromDynamic(runtime, parameters)});
+}
+
+void UIManagerBinding::stopSurface(jsi::Runtime &runtime, SurfaceId surfaceId)
+ const {
+ auto module = getModule(runtime, "ReactFabric");
+ auto method = module.getPropertyAsFunction(runtime, "unmountComponentAtNode");
+
+ method.callWithThis(runtime, module, {jsi::Value{surfaceId}});
+}
+
+void UIManagerBinding::dispatchEvent(
+ jsi::Runtime &runtime,
+ const EventTarget *eventTarget,
+ const std::string &type,
+ const ValueFactory &payloadFactory) const {
+ SystraceSection s("UIManagerBinding::dispatchEvent");
+
+ auto payload = payloadFactory(runtime);
+
+ auto instanceHandle = eventTarget
+ ? [&]() {
+ auto instanceHandle = eventTarget->getInstanceHandle(runtime);
+ if (instanceHandle.isUndefined()) {
+ return jsi::Value::null();
+ }
+
+ // Mixing `target` into `payload`.
+ assert(payload.isObject());
+ payload.asObject(runtime).setProperty(runtime, "target", eventTarget->getTag());
+ return instanceHandle;
+ }()
+ : jsi::Value::null();
+
+ auto &eventHandlerWrapper =
+ static_cast<const EventHandlerWrapper &>(*eventHandler_);
+
+ eventHandlerWrapper.callback.call(
+ runtime,
+ {std::move(instanceHandle),
+ jsi::String::createFromUtf8(runtime, type),
+ std::move(payload)});
+}
+
+void UIManagerBinding::invalidate() const {
+ uiManager_->setShadowTreeRegistry(nullptr);
+ uiManager_->setDelegate(nullptr);
+}
+
+jsi::Value UIManagerBinding::get(
+ jsi::Runtime &runtime,
+ const jsi::PropNameID &name) {
+ auto methodName = name.utf8(runtime);
+ auto &uiManager = *uiManager_;
+
+ // Semantic: Creates a new node with given pieces.
+ if (methodName == "createNode") {
+ return jsi::Function::createFromHostFunction(
+ runtime,
+ name,
+ 5,
+ [&uiManager](
+ jsi::Runtime &runtime,
+ const jsi::Value &thisValue,
+ const jsi::Value *arguments,
+ size_t count) -> jsi::Value {
+ return valueFromShadowNode(
+ runtime,
+ uiManager.createNode(
+ tagFromValue(runtime, arguments[0]),
+ componentNameFromValue(runtime, arguments[1]),
+ surfaceIdFromValue(runtime, arguments[2]),
+ RawProps(runtime, arguments[3]),
+ eventTargetFromValue(runtime, arguments[4], arguments[0])));
+ });
+ }
+
+ // Semantic: Clones the node with *same* props and *same* children.
+ if (methodName == "cloneNode") {
+ return jsi::Function::createFromHostFunction(
+ runtime,
+ name,
+ 1,
+ [&uiManager](
+ jsi::Runtime &runtime,
+ const jsi::Value &thisValue,
+ const jsi::Value *arguments,
+ size_t count) -> jsi::Value {
+ return valueFromShadowNode(
+ runtime,
+ uiManager.cloneNode(shadowNodeFromValue(runtime, arguments[0])));
+ });
+ }
+
+ // Semantic: Clones the node with *same* props and *empty* children.
+ if (methodName == "cloneNodeWithNewChildren") {
+ return jsi::Function::createFromHostFunction(
+ runtime,
+ name,
+ 1,
+ [&uiManager](
+ jsi::Runtime &runtime,
+ const jsi::Value &thisValue,
+ const jsi::Value *arguments,
+ size_t count) -> jsi::Value {
+ return valueFromShadowNode(
+ runtime,
+ uiManager.cloneNode(
+ shadowNodeFromValue(runtime, arguments[0]),
+ ShadowNode::emptySharedShadowNodeSharedList()));
+ });
+ }
+
+ // Semantic: Clones the node with *given* props and *same* children.
+ if (methodName == "cloneNodeWithNewProps") {
+ return jsi::Function::createFromHostFunction(
+ runtime,
+ name,
+ 2,
+ [&uiManager](
+ jsi::Runtime &runtime,
+ const jsi::Value &thisValue,
+ const jsi::Value *arguments,
+ size_t count) -> jsi::Value {
+ const auto &rawProps = RawProps(runtime, arguments[1]);
+ return valueFromShadowNode(
+ runtime,
+ uiManager.cloneNode(
+ shadowNodeFromValue(runtime, arguments[0]),
+ nullptr,
+ &rawProps));
+ });
+ }
+
+ // Semantic: Clones the node with *given* props and *empty* children.
+ if (methodName == "cloneNodeWithNewChildrenAndProps") {
+ return jsi::Function::createFromHostFunction(
+ runtime,
+ name,
+ 2,
+ [&uiManager](
+ jsi::Runtime &runtime,
+ const jsi::Value &thisValue,
+ const jsi::Value *arguments,
+ size_t count) -> jsi::Value {
+ const auto &rawProps = RawProps(runtime, arguments[1]);
+ return valueFromShadowNode(
+ runtime,
+ uiManager.cloneNode(
+ shadowNodeFromValue(runtime, arguments[0]),
+ ShadowNode::emptySharedShadowNodeSharedList(),
+ &rawProps));
+ });
+ }
+
+ if (methodName == "appendChild") {
+ return jsi::Function::createFromHostFunction(
+ runtime,
+ name,
+ 2,
+ [&uiManager](
+ jsi::Runtime &runtime,
+ const jsi::Value &thisValue,
+ const jsi::Value *arguments,
+ size_t count) -> jsi::Value {
+ uiManager.appendChild(
+ shadowNodeFromValue(runtime, arguments[0]),
+ shadowNodeFromValue(runtime, arguments[1]));
+ return jsi::Value::undefined();
+ });
+ }
+
+ if (methodName == "createChildSet") {
+ return jsi::Function::createFromHostFunction(
+ runtime,
+ name,
+ 1,
+ [](jsi::Runtime &runtime,
+ const jsi::Value &thisValue,
+ const jsi::Value *arguments,
+ size_t count) -> jsi::Value {
+ auto shadowNodeList =
+ std::make_shared<SharedShadowNodeList>(SharedShadowNodeList({}));
+ return valueFromShadowNodeList(runtime, shadowNodeList);
+ });
+ }
+
+ if (methodName == "appendChildToSet") {
+ return jsi::Function::createFromHostFunction(
+ runtime,
+ name,
+ 2,
+ [](jsi::Runtime &runtime,
+ const jsi::Value &thisValue,
+ const jsi::Value *arguments,
+ size_t count) -> jsi::Value {
+ auto shadowNodeList = shadowNodeListFromValue(runtime, arguments[0]);
+ auto shadowNode = shadowNodeFromValue(runtime, arguments[1]);
+ shadowNodeList->push_back(shadowNode);
+ return jsi::Value::undefined();
+ });
+ }
+
+ if (methodName == "completeRoot") {
+ return jsi::Function::createFromHostFunction(
+ runtime,
+ name,
+ 2,
+ [&uiManager](
+ jsi::Runtime &runtime,
+ const jsi::Value &thisValue,
+ const jsi::Value *arguments,
+ size_t count) -> jsi::Value {
+ uiManager.completeSurface(
+ surfaceIdFromValue(runtime, arguments[0]),
+ shadowNodeListFromValue(runtime, arguments[1]));
+ return jsi::Value::undefined();
+ });
+ }
+
+ if (methodName == "registerEventHandler") {
+ return jsi::Function::createFromHostFunction(
+ runtime,
+ name,
+ 1,
+ [this](
+ jsi::Runtime &runtime,
+ const jsi::Value &thisValue,
+ const jsi::Value *arguments,
+ size_t count) -> jsi::Value {
+ auto eventHandler =
+ arguments[0].getObject(runtime).getFunction(runtime);
+ eventHandler_ =
+ std::make_unique<EventHandlerWrapper>(std::move(eventHandler));
+ return jsi::Value::undefined();
+ });
+ }
+
+ if (methodName == "getRelativeLayoutMetrics") {
+ return jsi::Function::createFromHostFunction(
+ runtime,
+ name,
+ 2,
+ [&uiManager](
+ jsi::Runtime &runtime,
+ const jsi::Value &thisValue,
+ const jsi::Value *arguments,
+ size_t count) -> jsi::Value {
+ auto layoutMetrics = uiManager.getRelativeLayoutMetrics(
+ *shadowNodeFromValue(runtime, arguments[0]),
+ shadowNodeFromValue(runtime, arguments[1]).get());
+ auto frame = layoutMetrics.frame;
+ auto result = jsi::Object(runtime);
+ result.setProperty(runtime, "left", frame.origin.x);
+ result.setProperty(runtime, "top", frame.origin.y);
+ result.setProperty(runtime, "width", frame.size.width);
+ result.setProperty(runtime, "height", frame.size.height);
+ return result;
+ });
+ }
+
+ if (methodName == "setNativeProps") {
+ return jsi::Function::createFromHostFunction(
+ runtime,
+ name,
+ 2,
+ [&uiManager](
+ jsi::Runtime &runtime,
+ const jsi::Value &thisValue,
+ const jsi::Value *arguments,
+ size_t count) -> jsi::Value {
+ uiManager.setNativeProps(
+ shadowNodeFromValue(runtime, arguments[0]),
+ RawProps(runtime, arguments[1]));
+
+ return jsi::Value::undefined();
+ });
+ }
+
+ return jsi::Value::undefined();
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/uimanager/UIManagerBinding.h

@@ -0,0 +1,74 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#pragma once
+
+#include <folly/dynamic.h>
+#include <jsi/jsi.h>
+#include <react/uimanager/UIManager.h>
+#include <react/uimanager/primitives.h>
+
+namespace facebook {
+namespace react {
+
+/*
+ * Exposes UIManager to JavaScript realm.
+ */
+class UIManagerBinding : public jsi::HostObject {
+ public:
+ /*
+ * Installs UIManagerBinding into JavaSctipt runtime.
+ * Thread synchronization must be enforced externally.
+ */
+ static void install(
+ jsi::Runtime &runtime,
+ std::shared_ptr<UIManagerBinding> uiManagerBinding);
+
+ UIManagerBinding(std::unique_ptr<UIManager> uiManager);
+
+ /*
+ * Starts React Native Surface with given id, moduleName, and props.
+ * Thread synchronization must be enforced externally.
+ */
+ void startSurface(
+ jsi::Runtime &runtime,
+ SurfaceId surfaceId,
+ const std::string &moduleName,
+ const folly::dynamic &initalProps) const;
+
+ /*
+ * Stops React Native Surface with given id.
+ * Thread synchronization must be enforced externally.
+ */
+ void stopSurface(jsi::Runtime &runtime, SurfaceId surfaceId) const;
+
+ /*
+ * Delivers raw event data to JavaScript.
+ * Thread synchronization must be enforced externally.
+ */
+ void dispatchEvent(
+ jsi::Runtime &runtime,
+ const EventTarget *eventTarget,
+ const std::string &type,
+ const ValueFactory &payloadFactory) const;
+
+ /*
+ * Invalidates the binding and underlying UIManager.
+ * Allows to save some resources and prevents UIManager's delegate to be
+ * called.
+ * Calling public methods of this class after calling this method is UB.
+ * Can be called on any thread.
+ */
+ void invalidate() const;
+
+ /*
+ * `jsi::HostObject` specific overloads.
+ */
+ jsi::Value get(jsi::Runtime &runtime, const jsi::PropNameID &name) override;
+
+ private:
+ std::unique_ptr<UIManager> uiManager_;
+ std::unique_ptr<const EventHandler> eventHandler_;
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/uimanager/UIManager.cpp

@@ -0,0 +1,150 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#include "UIManager.h"
+
+#include <react/core/ShadowNodeFragment.h>
+#include <react/debug/SystraceSection.h>
+#include <react/uimanager/TimeUtils.h>
+
+namespace facebook {
+namespace react {
+
+SharedShadowNode UIManager::createNode(
+ Tag tag,
+ const ComponentName &name,
+ SurfaceId surfaceId,
+ const RawProps &rawProps,
+ SharedEventTarget eventTarget) const {
+ SystraceSection s("UIManager::createNode");
+
+ auto &componentDescriptor = componentDescriptorRegistry_->at(name);
+
+ auto shadowNode = componentDescriptor.createShadowNode(
+ {.tag = tag,
+ .rootTag = surfaceId,
+ .eventEmitter =
+ componentDescriptor.createEventEmitter(std::move(eventTarget), tag),
+ .props = componentDescriptor.cloneProps(nullptr, rawProps)});
+
+ if (delegate_) {
+ delegate_->uiManagerDidCreateShadowNode(shadowNode);
+ }
+
+ return std::const_pointer_cast<ShadowNode>(shadowNode);
+}
+
+SharedShadowNode UIManager::cloneNode(
+ const SharedShadowNode &shadowNode,
+ const SharedShadowNodeSharedList &children,
+ const RawProps *rawProps) const {
+ SystraceSection s("UIManager::cloneNode");
+
+ auto &componentDescriptor =
+ componentDescriptorRegistry_->at(shadowNode->getComponentHandle());
+
+ auto clonedShadowNode = componentDescriptor.cloneShadowNode(
+ *shadowNode,
+ {
+ .props = rawProps ? componentDescriptor.cloneProps(
+ shadowNode->getProps(), *rawProps)
+ : ShadowNodeFragment::nullSharedProps(),
+ .children = children,
+ });
+
+ return std::const_pointer_cast<ShadowNode>(clonedShadowNode);
+}
+
+void UIManager::appendChild(
+ const SharedShadowNode &parentShadowNode,
+ const SharedShadowNode &childShadowNode) const {
+ SystraceSection s("UIManager::appendChild");
+
+ auto &componentDescriptor =
+ componentDescriptorRegistry_->at(parentShadowNode->getComponentHandle());
+ componentDescriptor.appendChild(parentShadowNode, childShadowNode);
+}
+
+void UIManager::completeSurface(
+ SurfaceId surfaceId,
+ const SharedShadowNodeUnsharedList &rootChildren) const {
+ SystraceSection s("UIManager::completeSurface");
+
+ if (delegate_) {
+ delegate_->uiManagerDidFinishTransaction(
+ surfaceId, rootChildren, getTime());
+ }
+}
+
+void UIManager::setNativeProps(
+ const SharedShadowNode &shadowNode,
+ const RawProps &rawProps) const {
+ SystraceSection s("UIManager::setNativeProps");
+
+ long startCommitTime = getTime();
+
+ auto &componentDescriptor =
+ componentDescriptorRegistry_->at(shadowNode->getComponentHandle());
+ auto props = componentDescriptor.cloneProps(shadowNode->getProps(), rawProps);
+ auto newShadowNode = shadowNode->clone(ShadowNodeFragment{.props = props});
+
+ shadowTreeRegistry_->visit(
+ shadowNode->getRootTag(), [&](const ShadowTree &shadowTree) {
+ shadowTree.tryCommit(
+ [&](const SharedRootShadowNode &oldRootShadowNode) {
+ return oldRootShadowNode->clone(shadowNode, newShadowNode);
+ },
+ startCommitTime);
+ });
+}
+
+LayoutMetrics UIManager::getRelativeLayoutMetrics(
+ const ShadowNode &shadowNode,
+ const ShadowNode *ancestorShadowNode) const {
+ SystraceSection s("UIManager::getRelativeLayoutMetrics");
+
+ long startCommitTime = getTime();
+
+ if (!ancestorShadowNode) {
+ shadowTreeRegistry_->visit(
+ shadowNode.getRootTag(), [&](const ShadowTree &shadowTree) {
+ shadowTree.tryCommit(
+ [&](const SharedRootShadowNode &oldRootShadowNode) {
+ ancestorShadowNode = oldRootShadowNode.get();
+ return nullptr;
+ },
+ startCommitTime);
+ });
+ }
+
+ auto layoutableShadowNode =
+ dynamic_cast<const LayoutableShadowNode *>(&shadowNode);
+ auto layoutableAncestorShadowNode =
+ dynamic_cast<const LayoutableShadowNode *>(ancestorShadowNode);
+
+ if (!layoutableShadowNode || !layoutableAncestorShadowNode) {
+ return EmptyLayoutMetrics;
+ }
+
+ return layoutableShadowNode->getRelativeLayoutMetrics(
+ *layoutableAncestorShadowNode);
+}
+
+void UIManager::setShadowTreeRegistry(ShadowTreeRegistry *shadowTreeRegistry) {
+ shadowTreeRegistry_ = shadowTreeRegistry;
+}
+
+void UIManager::setComponentDescriptorRegistry(
+ const SharedComponentDescriptorRegistry &componentDescriptorRegistry) {
+ componentDescriptorRegistry_ = componentDescriptorRegistry;
+}
+
+void UIManager::setDelegate(UIManagerDelegate *delegate) {
+ delegate_ = delegate;
+}
+
+UIManagerDelegate *UIManager::getDelegate() {
+ return delegate_;
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/uimanager/UIManagerDelegate.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015-present, Facebook, Inc.
+ * 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.
@@ -7,8 +7,8 @@
#pragma once
-#include <fabric/core/ShadowNode.h>
-#include <fabric/core/ReactPrimitives.h>
+#include <react/core/ReactPrimitives.h>
+#include <react/core/ShadowNode.h>
namespace facebook {
namespace react {
@@ -17,20 +17,25 @@
* Abstract class for UIManager's delegate.
*/
class UIManagerDelegate {
-public:
-
+ public:
/*
* Called right after the new/updated Shadow Node tree is constructed.
* The tree is not layed out and not sealed at this time.
*/
- virtual void uiManagerDidFinishTransaction(Tag rootTag, const SharedShadowNodeUnsharedList &rootChildNodes) = 0;
+ virtual void uiManagerDidFinishTransaction(
+ SurfaceId surfaceId,
+ const SharedShadowNodeUnsharedList &rootChildNodes,
+ long startCommitTime) = 0;
/*
* Called each time when UIManager constructs a new Shadow Node. Receiver
* maight use this to preluminary optimistically allocate a new native view
* instances.
*/
- virtual void uiManagerDidCreateShadowNode(const SharedShadowNode &shadowNode) = 0;
+ virtual void uiManagerDidCreateShadowNode(
+ const SharedShadowNode &shadowNode) = 0;
+
+ virtual ~UIManagerDelegate() noexcept = default;
};
} // namespace react

ReactCommon/fabric/uimanager/UIManager.h

@@ -0,0 +1,74 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#pragma once
+
+#include <folly/Optional.h>
+#include <folly/dynamic.h>
+#include <jsi/jsi.h>
+
+#include <react/core/ShadowNode.h>
+#include <react/uimanager/ComponentDescriptorRegistry.h>
+#include <react/uimanager/ShadowTreeRegistry.h>
+#include <react/uimanager/UIManagerDelegate.h>
+
+namespace facebook {
+namespace react {
+
+class UIManager {
+ public:
+ void setShadowTreeRegistry(ShadowTreeRegistry *shadowTreeRegistry);
+
+ void setComponentDescriptorRegistry(
+ const SharedComponentDescriptorRegistry &componentDescriptorRegistry);
+
+ /*
+ * Sets and gets the UIManager's delegate.
+ * The delegate is stored as a raw pointer, so the owner must null
+ * the pointer before being destroyed.
+ */
+ void setDelegate(UIManagerDelegate *delegate);
+ UIManagerDelegate *getDelegate();
+
+ private:
+ friend class UIManagerBinding;
+
+ SharedShadowNode createNode(
+ Tag tag,
+ const std::string &name,
+ SurfaceId surfaceId,
+ const RawProps &props,
+ SharedEventTarget eventTarget) const;
+
+ SharedShadowNode cloneNode(
+ const SharedShadowNode &shadowNode,
+ const SharedShadowNodeSharedList &children = nullptr,
+ const RawProps *rawProps = nullptr) const;
+
+ void appendChild(
+ const SharedShadowNode &parentShadowNode,
+ const SharedShadowNode &childShadowNode) const;
+
+ void completeSurface(
+ SurfaceId surfaceId,
+ const SharedShadowNodeUnsharedList &rootChildren) const;
+
+ void setNativeProps(
+ const SharedShadowNode &shadowNode,
+ const RawProps &rawProps) const;
+
+ /*
+ * Returns layout metrics of given `shadowNode` relative to
+ * `ancestorShadowNode` (relative to the root node in case if provided
+ * `ancestorShadowNode` is nullptr).
+ */
+ LayoutMetrics getRelativeLayoutMetrics(
+ const ShadowNode &shadowNode,
+ const ShadowNode *ancestorShadowNode) const;
+
+ ShadowTreeRegistry *shadowTreeRegistry_;
+ SharedComponentDescriptorRegistry componentDescriptorRegistry_;
+ UIManagerDelegate *delegate_;
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/uimanager/UITemplateProcessor.cpp

@@ -0,0 +1,151 @@
+/**
+ * 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.
+ */
+
+#include "UITemplateProcessor.h"
+
+#include <folly/json.h>
+#include <glog/logging.h>
+#include <react/components/view/ViewComponentDescriptor.h>
+#include <react/components/view/ViewProps.h>
+#include <react/components/view/ViewShadowNode.h>
+#include <react/core/ComponentDescriptor.h>
+#include <react/core/LayoutContext.h>
+#include <react/core/ShadowNodeFragment.h>
+#include <react/debug/DebugStringConvertible.h>
+#include <react/debug/DebugStringConvertibleItem.h>
+
+namespace facebook {
+namespace react {
+
+bool constexpr DEBUG_FLY = false;
+
+struct RBCContext {
+ const Tag rootTag;
+ const std::vector<SharedShadowNode> &nodes;
+ const std::vector<folly::dynamic> &registers;
+ const ComponentDescriptorRegistry &componentDescriptorRegistry;
+ const NativeModuleRegistry &nativeModuleRegistry;
+};
+
+// TODO: use RBCContext instead of all the separate arguments.
+SharedShadowNode UITemplateProcessor::runCommand(
+ const folly::dynamic &command,
+ Tag rootTag,
+ std::vector<SharedShadowNode> &nodes,
+ std::vector<folly::dynamic> &registers,
+ const ComponentDescriptorRegistry &componentDescriptorRegistry,
+ const NativeModuleRegistry &nativeModuleRegistry,
+ const std::shared_ptr<const ReactNativeConfig> reactNativeConfig) {
+ const std::string &opcode = command[0].asString();
+ const int tagOffset = 420000;
+ // TODO: change to integer codes and a switch statement
+ if (opcode == "createNode") {
+ int tag = command[1].asInt();
+ const auto &type = command[2].asString();
+ const auto parentTag = command[3].asInt();
+ const auto &props = command[4];
+ nodes[tag] = componentDescriptorRegistry.createNode(
+ tag + tagOffset, type, rootTag, props, nullptr);
+ if (parentTag > -1) { // parentTag == -1 indicates root node
+ auto parentShadowNode = nodes[parentTag];
+ const SharedComponentDescriptor &componentDescriptor =
+ componentDescriptorRegistry[parentShadowNode];
+ componentDescriptor->appendChild(parentShadowNode, nodes[tag]);
+ }
+ } else if (opcode == "returnRoot") {
+ LOG(INFO)
+ << "(stop) UITemplateProcessor inject serialized 'server rendered' view tree";
+ return nodes[command[1].asInt()];
+ } else if (opcode == "loadNativeBool") {
+ int registerNumber = command[1].asInt();
+ std::string param = command[4][0].asString();
+ registers[registerNumber] = reactNativeConfig->getBool(param);
+ } else if (opcode == "conditional") {
+ int registerNumber = command[1].asInt();
+ auto conditionDynamic = registers[registerNumber];
+ if (conditionDynamic.isNull()) {
+ // TODO: provide original command or command line?
+ auto err = std::runtime_error(
+ "register " + command[1].asString() + " wasn't loaded before access");
+ throw err;
+ } else if (conditionDynamic.type() != folly::dynamic::BOOL) {
+ // TODO: provide original command or command line?
+ auto err = std::runtime_error(
+ "register " + command[1].asString() + " had type '" +
+ conditionDynamic.typeName() +
+ "' but needs to be 'boolean' for conditionals");
+ throw err;
+ }
+ const auto &nextCommands =
+ conditionDynamic.asBool() ? command[2] : command[3];
+ for (const auto &nextCommand : nextCommands) {
+ runCommand(
+ nextCommand,
+ rootTag,
+ nodes,
+ registers,
+ componentDescriptorRegistry,
+ nativeModuleRegistry,
+ reactNativeConfig);
+ }
+ } else {
+ throw std::runtime_error("Unsupported opcode: " + command[0].asString());
+ }
+ return nullptr;
+}
+
+SharedShadowNode UITemplateProcessor::buildShadowTree(
+ const std::string &jsonStr,
+ Tag rootTag,
+ const folly::dynamic &params,
+ const ComponentDescriptorRegistry &componentDescriptorRegistry,
+ const NativeModuleRegistry &nativeModuleRegistry,
+ const std::shared_ptr<const ReactNativeConfig> reactNativeConfig) {
+ LOG(INFO)
+ << "(strt) UITemplateProcessor inject hardcoded 'server rendered' view tree";
+
+ std::string content = jsonStr;
+ for (const auto &param : params.items()) {
+ const auto &key = param.first.asString();
+ size_t start_pos = content.find(key);
+ if (start_pos != std::string::npos) {
+ content.replace(start_pos, key.length(), param.second.asString());
+ }
+ }
+ auto parsed = folly::parseJson(content);
+ auto commands = parsed["commands"];
+ std::vector<SharedShadowNode> nodes(commands.size() * 2);
+ std::vector<folly::dynamic> registers(32);
+ for (const auto &command : commands) {
+ try {
+ if (DEBUG_FLY) {
+ LOG(INFO) << "try to run command " << folly::toJson(command);
+ }
+ auto ret = runCommand(
+ command,
+ rootTag,
+ nodes,
+ registers,
+ componentDescriptorRegistry,
+ nativeModuleRegistry,
+ reactNativeConfig);
+ if (ret != nullptr) {
+ return ret;
+ }
+ } catch (const std::exception &e) {
+ LOG(ERROR) << " >>> Exception <<< running previous command '"
+ << folly::toJson(command) << "': '" << e.what() << "'";
+ }
+ }
+ LOG(ERROR) << "react ui template missing returnRoot command :(";
+ throw std::runtime_error(
+ "Missing returnRoot command in template content:\n" + content);
+ return SharedShadowNode{};
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/fabric/uimanager/UITemplateProcessor.h

@@ -0,0 +1,66 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include <folly/dynamic.h>
+
+#include <react/config/ReactNativeConfig.h>
+#include <react/core/ShadowNode.h>
+#include <react/uimanager/ComponentDescriptorRegistry.h>
+#include <react/uimanager/UIManagerDelegate.h>
+
+namespace facebook {
+namespace react {
+
+// Temporary NativeModuleRegistry definition
+using NativeModuleCallFn =
+ std::function<folly::dynamic(const std::string &, const folly::dynamic &)>;
+
+class NativeModuleRegistry {
+ public:
+ void registerModule(
+ const std::string &moduleName,
+ NativeModuleCallFn callFn) {
+ modules_.emplace(moduleName, callFn);
+ }
+
+ folly::dynamic call(
+ const std::string &moduleName,
+ const std::string &methodName,
+ const folly::dynamic &args) const {
+ return modules_.at(moduleName)(methodName, args);
+ }
+
+ private:
+ std::unordered_map<std::string, NativeModuleCallFn> modules_;
+};
+
+class UITemplateProcessor {
+ public:
+ static SharedShadowNode buildShadowTree(
+ const std::string &jsonStr,
+ int rootTag,
+ const folly::dynamic &params,
+ const ComponentDescriptorRegistry &componentDescriptorRegistry,
+ const NativeModuleRegistry &nativeModuleRegistry,
+ const std::shared_ptr<const ReactNativeConfig> reactNativeConfig);
+
+ private:
+ static SharedShadowNode runCommand(
+ const folly::dynamic &command,
+ Tag rootTag,
+ std::vector<SharedShadowNode> &nodes,
+ std::vector<folly::dynamic> &registers,
+ const ComponentDescriptorRegistry &componentDescriptorRegistry,
+ const NativeModuleRegistry &nativeModuleRegistry,
+ const std::shared_ptr<const ReactNativeConfig> reactNativeConfig);
+};
+} // namespace react
+} // namespace facebook

ReactCommon/jschelpers/Android.mk

@@ -1,27 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := jschelpers
-
-LOCAL_SRC_FILES := \
- JSCHelpers.cpp \
- Unicode.cpp \
- Value.cpp \
-
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/..
-LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
-
-LOCAL_CFLAGS := \
- -DLOG_TAG=\"ReactNative\"
-
-LOCAL_CFLAGS += -fexceptions -frtti
-
-LOCAL_SHARED_LIBRARIES := libfolly_json libjsc libglog
-
-include $(BUILD_STATIC_LIBRARY)
-
-$(call import-module,folly)
-$(call import-module,jsc)
-$(call import-module,glog)
-$(call import-module,privatedata)

ReactCommon/jschelpers/BUCK

@@ -1,73 +0,0 @@
-load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "ANDROID_JSC_INTERNAL_DEPS", "APPLE", "APPLE_JSC_INTERNAL_DEPS", "react_native_xplat_target", "rn_xplat_cxx_library")
-
-EXPORTED_HEADERS = [
- "JavaScriptCore.h",
- "JSCHelpers.h",
- "JSCWrapper.h",
- "noncopyable.h",
- "Unicode.h",
- "Value.h",
-]
-
-rn_xplat_cxx_library(
- name = "jscinternalhelpers",
- srcs = glob(
- ["*.cpp"],
- exclude = ["systemJSCWrapper.cpp"],
- ),
- headers = glob(
- ["*.h"],
- exclude = EXPORTED_HEADERS,
- ),
- header_namespace = "",
- exported_headers = dict([
- (
- "jschelpers/%s" % header,
- header,
- )
- for header in EXPORTED_HEADERS
- ]),
- compiler_flags = [
- "-Wall",
- "-fexceptions",
- "-frtti",
- "-fvisibility=hidden",
- "-std=c++1y",
- ],
- fbandroid_deps = ANDROID_JSC_INTERNAL_DEPS,
- fbobjc_deps = APPLE_JSC_INTERNAL_DEPS,
- force_static = True,
- platforms = (ANDROID, APPLE),
- visibility = [
- "PUBLIC",
- ],
- deps = [
- "xplat//folly:molly",
- "xplat//third-party/glog:glog",
- react_native_xplat_target("privatedata:privatedata"),
- ],
- exported_deps = [
- react_native_xplat_target("privatedata:privatedata"),
- ],
-)
-
-rn_xplat_cxx_library(
- name = "jschelpers",
- srcs = [],
- compiler_flags = [
- "-Wall",
- "-fexceptions",
- "-fvisibility=hidden",
- "-std=c++1y",
- ],
- fbobjc_frameworks = [
- "$SDKROOT/System/Library/Frameworks/JavaScriptCore.framework",
- ],
- fbobjc_srcs = ["systemJSCWrapper.cpp"],
- force_static = True,
- platforms = (ANDROID, APPLE),
- visibility = [
- "PUBLIC",
- ],
- deps = [":jscinternalhelpers"],
-)

ReactCommon/jschelpers/JavaScriptCore.h

@@ -1,212 +0,0 @@
-/**
- * Copyright (c) 2016-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#pragma once
-
-#include <jschelpers/JSCWrapper.h>
-
-#if defined(__APPLE__)
-
-// Use for methods that are taking JSContextRef as a first param
-#define __jsc_wrapper(method, ctx, ...) \
- (facebook::react::isCustomJSCPtr(ctx) ? \
- facebook::react::customJSCWrapper() : \
- facebook::react::systemJSCWrapper() \
- )->method(ctx, ## __VA_ARGS__)
-
-// Use for methods that don't take a JSContextRef as a first param. The wrapped version
-// of this method will require context as an additional param, but it will be dropped
-// before calling into the JSC method.
-#define __jsc_drop_ctx_wrapper(method, ctx, ...) \
- (facebook::react::isCustomJSCPtr(ctx) ? \
- facebook::react::customJSCWrapper() : \
- facebook::react::systemJSCWrapper() \
- )->method(__VA_ARGS__)
-
-// Use for methods were access to a JSContextRef is impractical. The first bool param
-// will be dropped before the JSC method is invoked.
-#define __jsc_ensure_bool(field) \
- static_assert(std::is_same<typename std::decay<decltype(field)>::type, bool>::value, "useCustomJSC must be bool");
-#define __jsc_bool_wrapper(method, useCustomJSC, ...) \
- ([]{ __jsc_ensure_bool(useCustomJSC) }, useCustomJSC ? \
- facebook::react::customJSCWrapper() : \
- facebook::react::systemJSCWrapper() \
- )->method(__VA_ARGS__)
-
-// Used for wrapping properties
-#define __jsc_prop_wrapper(prop, ctx) \
- (facebook::react::isCustomJSCPtr(ctx) ? \
- facebook::react::customJSCWrapper() : \
- facebook::react::systemJSCWrapper() \
- )->prop
-
-// Poison all regular versions of the JSC API in shared code. This prevents accidental
-// mixed usage of regular and custom JSC methods.
-// See https://gcc.gnu.org/onlinedocs/gcc-3.3/cpp/Pragmas.html for details
-#define jsc_pragma(x) _Pragma(#x)
-#ifndef NO_JSC_POISON
-#define jsc_poison(methods) jsc_pragma(GCC poison methods)
-#else
-#define jsc_poison(methods)
-#endif
-
-#else
-
-#define __jsc_wrapper(method, ctx, ...) method(ctx, ## __VA_ARGS__)
-#define __jsc_drop_ctx_wrapper(method, ctx, ...) ((void)ctx, method(__VA_ARGS__))
-#define __jsc_bool_wrapper(method, useCustomJSC, ...) \
- ((void)useCustomJSC, method(__VA_ARGS__))
-#define __jsc_prop_wrapper(prop, ctx) prop
-
-#define jsc_pragma(x)
-#define jsc_poison(methods)
-
-#endif
-
-// JSGlobalContext
-#define JSC_JSGlobalContextCreateInGroup(...) __jsc_bool_wrapper(JSGlobalContextCreateInGroup, __VA_ARGS__)
-#define JSC_JSGlobalContextRelease(...) __jsc_wrapper(JSGlobalContextRelease, __VA_ARGS__)
-#define JSC_JSGlobalContextSetName(...) __jsc_wrapper(JSGlobalContextSetName, __VA_ARGS__)
-
-jsc_poison(JSContextGroupCreate JSContextGroupRelease JSContextGroupRetain
- JSGlobalContextCreate JSGlobalContextCreateInGroup JSGlobalContextCopyName
- JSGlobalContextRelease JSGlobalContextRetain JSGlobalContextSetName)
-
-// JSContext
-#define JSC_JSContextGetGlobalContext(...) __jsc_wrapper(JSContextGetGlobalContext, __VA_ARGS__)
-#define JSC_JSContextGetGlobalObject(...) __jsc_wrapper(JSContextGetGlobalObject, __VA_ARGS__)
-#define JSC_FBJSContextStartGCTimers(...) __jsc_wrapper(FBJSContextStartGCTimers, __VA_ARGS__)
-
-jsc_poison(JSContextGetGlobalContext JSContextGetGlobalObject JSContextGetGroup FBJSContextStartGCTimers)
-
-// JSEvaluate
-#define JSC_JSEvaluateScript(...) __jsc_wrapper(JSEvaluateScript, __VA_ARGS__)
-#define JSC_JSEvaluateBytecodeBundle(...) __jsc_wrapper(JSEvaluateBytecodeBundle, __VA_ARGS__)
-
-jsc_poison(JSCheckScriptSyntax JSEvaluateScript JSEvaluateBytecodeBundle JSGarbageCollect)
-
-// JSString
-#define JSC_JSStringCreateWithCFString(...) __jsc_drop_ctx_wrapper(JSStringCreateWithCFString, __VA_ARGS__)
-#define JSC_JSStringCreateWithUTF8CString(...) __jsc_drop_ctx_wrapper(JSStringCreateWithUTF8CString, __VA_ARGS__)
-#define JSC_JSStringCreateWithUTF8CStringExpectAscii(...) __jsc_drop_ctx_wrapper(JSStringCreateWithUTF8CStringExpectAscii, __VA_ARGS__)
-#define JSC_JSStringCopyCFString(...) __jsc_drop_ctx_wrapper(JSStringCopyCFString, __VA_ARGS__)
-#define JSC_JSStringGetCharactersPtr(...) __jsc_drop_ctx_wrapper(JSStringGetCharactersPtr, __VA_ARGS__)
-#define JSC_JSStringGetLength(...) __jsc_drop_ctx_wrapper(JSStringGetLength, __VA_ARGS__)
-#define JSC_JSStringGetMaximumUTF8CStringSize(...) __jsc_drop_ctx_wrapper(JSStringGetMaximumUTF8CStringSize, __VA_ARGS__)
-#define JSC_JSStringIsEqualToUTF8CString(...) __jsc_drop_ctx_wrapper(JSStringIsEqualToUTF8CString, __VA_ARGS__)
-#define JSC_JSStringRelease(...) __jsc_drop_ctx_wrapper(JSStringRelease, __VA_ARGS__)
-#define JSC_JSStringRetain(...) __jsc_drop_ctx_wrapper(JSStringRetain, __VA_ARGS__)
-
-jsc_poison(JSStringCopyCFString JSStringCreateWithCharacters JSStringCreateWithCFString
- JSStringCreateWithUTF8CString JSStringCreateWithUTF8CStringExpectAscii
- JSStringGetCharactersPtr JSStringGetLength JSStringGetMaximumUTF8CStringSize
- JSStringGetUTF8CString JSStringIsEqual JSStringIsEqualToUTF8CString
- JSStringRelease JSStringRetain)
-
-// JSValueRef
-#define JSC_JSValueCreateJSONString(...) __jsc_wrapper(JSValueCreateJSONString, __VA_ARGS__)
-#define JSC_JSValueGetType(...) __jsc_wrapper(JSValueGetType, __VA_ARGS__)
-#define JSC_JSValueMakeFromJSONString(...) __jsc_wrapper(JSValueMakeFromJSONString, __VA_ARGS__)
-#define JSC_JSValueMakeBoolean(...) __jsc_wrapper(JSValueMakeBoolean, __VA_ARGS__)
-#define JSC_JSValueMakeNull(...) __jsc_wrapper(JSValueMakeNull, __VA_ARGS__)
-#define JSC_JSValueMakeNumber(...) __jsc_wrapper(JSValueMakeNumber, __VA_ARGS__)
-#define JSC_JSValueMakeString(...) __jsc_wrapper(JSValueMakeString, __VA_ARGS__)
-#define JSC_JSValueMakeUndefined(...) __jsc_wrapper(JSValueMakeUndefined, __VA_ARGS__)
-#define JSC_JSValueProtect(...) __jsc_wrapper(JSValueProtect, __VA_ARGS__)
-#define JSC_JSValueToBoolean(...) __jsc_wrapper(JSValueToBoolean, __VA_ARGS__)
-#define JSC_JSValueToNumber(...) __jsc_wrapper(JSValueToNumber, __VA_ARGS__)
-#define JSC_JSValueToObject(...) __jsc_wrapper(JSValueToObject, __VA_ARGS__)
-#define JSC_JSValueToStringCopy(...) __jsc_wrapper(JSValueToStringCopy, __VA_ARGS__)
-#define JSC_JSValueUnprotect(...) __jsc_wrapper(JSValueUnprotect, __VA_ARGS__)
-#define JSC_JSValueIsNull(...) __jsc_wrapper(JSValueIsNull, __VA_ARGS__)
-
-jsc_poison(JSValueCreateJSONString JSValueGetType JSValueGetTypedArrayType JSValueIsArray
- JSValueIsBoolean JSValueIsDate JSValueIsEqual JSValueIsInstanceOfConstructor
- JSValueIsNull JSValueIsNumber JSValueIsObject JSValueIsObjectOfClass
- JSValueIsStrictEqual JSValueIsString JSValueIsString JSValueIsUndefined
- JSValueMakeBoolean JSValueMakeFromJSONString JSValueMakeNull JSValueMakeNumber
- JSValueMakeString JSValueMakeUndefined JSValueProtect JSValueToBoolean
- JSValueToNumber JSValueToObject JSValueToStringCopy JSValueUnprotect)
-
-// JSClass
-#define JSC_JSClassCreate(...) __jsc_bool_wrapper(JSClassCreate, __VA_ARGS__)
-#define JSC_JSClassRetain(...) __jsc_bool_wrapper(JSClassRetain, __VA_ARGS__)
-#define JSC_JSClassRelease(...) __jsc_bool_wrapper(JSClassRelease, __VA_ARGS__)
-
-jsc_poison(JSClassCreate JSClassRelease JSClassRetain)
-
-// JSObject
-#define JSC_JSObjectCallAsConstructor(...) __jsc_wrapper(JSObjectCallAsConstructor, __VA_ARGS__)
-#define JSC_JSObjectCallAsFunction(...) __jsc_wrapper(JSObjectCallAsFunction, __VA_ARGS__)
-#define JSC_JSObjectGetPrivate(...) __jsc_bool_wrapper(JSObjectGetPrivate, __VA_ARGS__)
-#define JSC_JSObjectGetProperty(...) __jsc_wrapper(JSObjectGetProperty, __VA_ARGS__)
-#define JSC_JSObjectGetPropertyAtIndex(...) __jsc_wrapper(JSObjectGetPropertyAtIndex, __VA_ARGS__)
-#define JSC_JSObjectIsConstructor(...) __jsc_wrapper(JSObjectIsConstructor, __VA_ARGS__)
-#define JSC_JSObjectIsFunction(...) __jsc_wrapper(JSObjectIsFunction, __VA_ARGS__)
-#define JSC_JSObjectMake(...) __jsc_wrapper(JSObjectMake, __VA_ARGS__)
-#define JSC_JSObjectMakeArray(...) __jsc_wrapper(JSObjectMakeArray, __VA_ARGS__)
-#define JSC_JSObjectMakeDate(...) __jsc_wrapper(JSObjectMakeDate, __VA_ARGS__)
-#define JSC_JSObjectMakeError(...) __jsc_wrapper(JSObjectMakeError, __VA_ARGS__)
-#define JSC_JSObjectMakeFunctionWithCallback(...) __jsc_wrapper(JSObjectMakeFunctionWithCallback, __VA_ARGS__)
-#define JSC_JSObjectSetPrivate(...) __jsc_bool_wrapper(JSObjectSetPrivate, __VA_ARGS__)
-#define JSC_JSObjectSetProperty(...) __jsc_wrapper(JSObjectSetProperty, __VA_ARGS__)
-#define JSC_JSObjectSetPropertyAtIndex(...) __jsc_wrapper(JSObjectSetPropertyAtIndex, __VA_ARGS__)
-
-jsc_poison(JSObjectCallAsConstructor JSObjectCallAsFunction JSObjectDeleteProperty
- JSObjectGetPrivate JSObjectGetProperty JSObjectGetPropertyAtIndex
- JSObjectGetPrototype JSObjectHasProperty JSObjectIsConstructor
- JSObjectIsFunction JSObjectMake JSObjectMakeArray JSObjectMakeConstructor
- JSObjectMakeDate JSObjectMakeError JSObjectMakeFunction
- JSObjectMakeFunctionWithCallback JSObjectMakeRegExp JSObjectSetPrivate
- JSObjectSetPrototype JSObjectSetProperty JSObjectSetPropertyAtIndex)
-
-// JSPropertyNameArray
-#define JSC_JSObjectCopyPropertyNames(...) __jsc_wrapper(JSObjectCopyPropertyNames, __VA_ARGS__)
-#define JSC_JSPropertyNameArrayGetCount(...) __jsc_drop_ctx_wrapper(JSPropertyNameArrayGetCount, __VA_ARGS__)
-#define JSC_JSPropertyNameArrayGetNameAtIndex(...) __jsc_drop_ctx_wrapper(JSPropertyNameArrayGetNameAtIndex, __VA_ARGS__)
-#define JSC_JSPropertyNameArrayRelease(...) __jsc_drop_ctx_wrapper(JSPropertyNameArrayRelease, __VA_ARGS__)
-
-jsc_poison(JSObjectCopyPropertyNames JSPropertyNameAccumulatorAddName
- JSPropertyNameArrayGetCount JSPropertyNameArrayGetNameAtIndex
- JSPropertyNameArrayRelease JSPropertyNameArrayRetain)
-
-// JSTypedArray
-jsc_poison(JSObjectMakeArrayBufferWithBytesNoCopy JSObjectMakeTypedArray
- JSObjectMakeTypedArrayWithArrayBuffer
- JSObjectMakeTypedArrayWithArrayBufferAndOffset
- JSObjectMakeTypedArrayWithBytesNoCopy JSObjectGetTypedArrayByteLength
- JSObjectGetTypedArrayByteOffset JSObjectGetTypedArrayBytesPtr
- JSObjectGetTypedArrayBuffer JSObjectGetTypedArrayLength
- JSObjectGetArrayBufferBytesPtr JSObjectGetArrayBufferByteLength)
-
-// Sampling profiler
-#define JSC_JSSamplingProfilerEnabled(...) __jsc_drop_ctx_wrapper(JSSamplingProfilerEnabled, __VA_ARGS__)
-#define JSC_JSPokeSamplingProfiler(...) __jsc_wrapper(JSPokeSamplingProfiler, __VA_ARGS__)
-#define JSC_JSStartSamplingProfilingOnMainJSCThread(...) __jsc_wrapper(JSStartSamplingProfilingOnMainJSCThread, __VA_ARGS__)
-
-jsc_poison(JSSamplingProfilerEnabled JSPokeSamplingProfiler
- JSStartSamplingProfilingOnMainJSCThread)
-
-#define JSC_JSGlobalContextEnableDebugger(...) __jsc_wrapper(JSGlobalContextEnableDebugger, __VA_ARGS__)
-// no need to poison JSGlobalContextEnableDebugger because it's not defined for System JSC / standard SDK header
-// jsc_poison(JSGlobalContextEnableDebugger)
-
-#define JSC_JSGlobalContextDisableDebugger(...) __jsc_wrapper(JSGlobalContextDisableDebugger, __VA_ARGS__)
-// no need to poison JSGlobalContextDisableDebugger because it's not defined for System JSC / standard SDK header
-// jsc_poison(JSGlobalContextDisableDebugger)
-
-
-#define JSC_configureJSCForIOS(...) __jsc_bool_wrapper(configureJSCForIOS, __VA_ARGS__)
-
-jsc_poison(configureJSCForIOS)
-
-// Objective-C API
-#define JSC_JSContext(ctx) __jsc_prop_wrapper(JSContext, ctx)
-#define JSC_JSValue(ctx) __jsc_prop_wrapper(JSValue, ctx)
-
-#undef jsc_poison
-#undef jsc_pragma

ReactCommon/jschelpers/JSCHelpers.cpp

@@ -1,299 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#include "JSCHelpers.h"
-
-#ifdef WITH_FBSYSTRACE
-#include <fbsystrace.h>
-#endif
-
-#include <glog/logging.h>
-
-#if WITH_FBJSCEXTENSIONS
-#include <pthread.h>
-#endif
-
-#include "JavaScriptCore.h"
-#include "Value.h"
-#include <privatedata/PrivateDataBase.h>
-
-#if WITH_FBJSCEXTENSIONS
-#undef ASSERT
-#undef WTF_EXPORT_PRIVATE
-
-#include <JavaScriptCore/config.h>
-#include <wtf/WTFThreadData.h>
-
-#undef TRUE
-#undef FALSE
-#endif
-
-namespace facebook {
-namespace react {
-
-namespace {
-
-class JSFunctionPrivateData : public PrivateDataBase {
- public:
- explicit JSFunctionPrivateData(JSFunction&& function) : jsFunction_{std::move(function)} {}
-
- JSFunction& getJSFunction() {
- return jsFunction_;
- }
-
-private:
- JSFunction jsFunction_;
-};
-
-JSValueRef functionCaller(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef* exception) {
- const bool isCustomJSC = isCustomJSCPtr(ctx);
- auto* privateData = PrivateDataBase::cast<JSFunctionPrivateData>(
- JSC_JSObjectGetPrivate(isCustomJSC, function));
- return (privateData->getJSFunction())(ctx, thisObject, argumentCount, arguments);
-}
-
-JSClassRef createFuncClass(JSContextRef ctx) {
- JSClassDefinition definition = kJSClassDefinitionEmpty;
- definition.attributes |= kJSClassAttributeNoAutomaticPrototype;
-
- // Need to duplicate the two different finalizer blocks, since there's no way
- // for it to capture this static information.
- const bool isCustomJSC = isCustomJSCPtr(ctx);
- if (isCustomJSC) {
- definition.finalize = [](JSObjectRef object) {
- auto* privateData = PrivateDataBase::cast<JSFunctionPrivateData>(
- JSC_JSObjectGetPrivate(true, object));
- delete privateData;
- };
- } else {
- definition.finalize = [](JSObjectRef object) {
- auto* privateData = PrivateDataBase::cast<JSFunctionPrivateData>(
- JSC_JSObjectGetPrivate(false, object));
- delete privateData;
- };
- }
- definition.callAsFunction = exceptionWrapMethod<&functionCaller>();
-
- return JSC_JSClassCreate(isCustomJSC, &definition);
-}
-
-JSObjectRef makeFunction(
- JSContextRef ctx,
- JSStringRef name,
- JSFunction function) {
- static JSClassRef kClassDef = NULL, kCustomJSCClassDef = NULL;
- JSClassRef *classRef = isCustomJSCPtr(ctx) ? &kCustomJSCClassDef : &kClassDef;
- if (!*classRef) {
- *classRef = createFuncClass(ctx);
- }
-
- // dealloc in kClassDef.finalize
- JSFunctionPrivateData *functionDataPtr = new JSFunctionPrivateData(std::move(function));
- auto functionObject = Object(ctx, JSC_JSObjectMake(ctx, *classRef, functionDataPtr));
- functionObject.setProperty("name", Value(ctx, name));
- return functionObject;
-}
-
-}
-
-void JSException::buildMessage(JSContextRef ctx, JSValueRef exn, JSStringRef sourceURL, const char* errorMsg) {
- std::ostringstream msgBuilder;
- if (errorMsg && strlen(errorMsg) > 0) {
- msgBuilder << errorMsg << ": ";
- }
-
- Object exnObject = Value(ctx, exn).asObject();
- Value exnMessage = exnObject.getProperty("message");
- msgBuilder << (exnMessage.isString() ? exnMessage : (Value)exnObject).toString().str();
-
- // The null/empty-ness of source tells us if the JS came from a
- // file/resource, or was a constructed statement. The location
- // info will include that source, if any.
- std::string locationInfo = sourceURL != nullptr ? String::ref(ctx, sourceURL).str() : "";
- auto line = exnObject.getProperty("line");
- if (line != nullptr && line.isNumber()) {
- if (locationInfo.empty() && line.asInteger() != 1) {
- // If there is a non-trivial line number, but there was no
- // location info, we include a placeholder, and the line
- // number.
- locationInfo = folly::to<std::string>("<unknown file>:", line.asInteger());
- } else if (!locationInfo.empty()) {
- // If there is location info, we always include the line
- // number, regardless of its value.
- locationInfo += folly::to<std::string>(":", line.asInteger());
- }
- }
-
- if (!locationInfo.empty()) {
- msgBuilder << " (" << locationInfo << ")";
- }
-
- auto exceptionText = msgBuilder.str();
- LOG(ERROR) << "Got JS Exception: " << exceptionText;
- msg_ = std::move(exceptionText);
-
- Value jsStack = exnObject.getProperty("stack");
- if (jsStack.isString()) {
- auto stackText = jsStack.toString().str();
- LOG(ERROR) << "Got JS Stack: " << stackText;
- stack_ = std::move(stackText);
- }
-}
-
-namespace ExceptionHandling {
-
-PlatformErrorExtractor platformErrorExtractor;
-
-}
-
-JSObjectRef makeFunction(
- JSContextRef ctx,
- const char* name,
- JSFunction function) {
- return makeFunction(ctx, String(ctx, name), std::move(function));
-}
-
-void installGlobalFunction(
- JSGlobalContextRef ctx,
- const char* name,
- JSFunction function) {
- auto jsName = String(ctx, name);
- auto functionObj = makeFunction(ctx, jsName, std::move(function));
- Object::getGlobalObject(ctx).setProperty(jsName, Value(ctx, functionObj));
-}
-
-JSObjectRef makeFunction(
- JSGlobalContextRef ctx,
- const char* name,
- JSObjectCallAsFunctionCallback callback) {
- auto jsName = String(ctx, name);
- return JSC_JSObjectMakeFunctionWithCallback(ctx, jsName, callback);
-}
-
-void installGlobalFunction(
- JSGlobalContextRef ctx,
- const char* name,
- JSObjectCallAsFunctionCallback callback) {
- String jsName(ctx, name);
- JSObjectRef functionObj = JSC_JSObjectMakeFunctionWithCallback(
- ctx, jsName, callback);
- Object::getGlobalObject(ctx).setProperty(jsName, Value(ctx, functionObj));
-}
-
-void installGlobalProxy(
- JSGlobalContextRef ctx,
- const char* name,
- JSObjectGetPropertyCallback callback) {
- JSClassDefinition proxyClassDefintion = kJSClassDefinitionEmpty;
- proxyClassDefintion.attributes |= kJSClassAttributeNoAutomaticPrototype;
- proxyClassDefintion.getProperty = callback;
-
- const bool isCustomJSC = isCustomJSCPtr(ctx);
- JSClassRef proxyClass = JSC_JSClassCreate(isCustomJSC, &proxyClassDefintion);
- JSObjectRef proxyObj = JSC_JSObjectMake(ctx, proxyClass, nullptr);
- JSC_JSClassRelease(isCustomJSC, proxyClass);
-
- Object::getGlobalObject(ctx).setProperty(name, Value(ctx, proxyObj));
-}
-
-void removeGlobal(JSGlobalContextRef ctx, const char* name) {
- Object::getGlobalObject(ctx).setProperty(name, Value::makeUndefined(ctx));
-}
-
-JSValueRef evaluateScript(JSContextRef context, JSStringRef script, JSStringRef sourceURL) {
- JSValueRef exn, result;
- result = JSC_JSEvaluateScript(context, script, NULL, sourceURL, 0, &exn);
- if (result == nullptr) {
- throw JSException(context, exn, sourceURL);
- }
- return result;
-}
-
-#if WITH_FBJSCEXTENSIONS
-JSValueRef evaluateSourceCode(JSContextRef context, JSSourceCodeRef source, JSStringRef sourceURL) {
- JSValueRef exn, result;
- result = JSEvaluateSourceCode(context, source, NULL, &exn);
- if (result == nullptr) {
- throw JSException(context, exn, sourceURL);
- }
- return result;
-}
-#endif
-
-JSContextLock::JSContextLock(JSGlobalContextRef ctx) noexcept
-#if WITH_FBJSCEXTENSIONS
- : ctx_(ctx),
- globalLock_(PTHREAD_MUTEX_INITIALIZER)
- {
- WTFThreadData& threadData = wtfThreadData();
-
- // Code below is responsible for acquiring locks. It should execute
- // atomically, thus none of the functions invoked from now on are allowed to
- // throw an exception
- try {
- if (!threadData.isDebuggerThread()) {
- CHECK(0 == pthread_mutex_lock(&globalLock_));
- }
- JSLock(ctx_);
- } catch (...) {
- abort();
- }
-}
-#else
-{}
-#endif
-
-
-JSContextLock::~JSContextLock() noexcept {
- #if WITH_FBJSCEXTENSIONS
- WTFThreadData& threadData = wtfThreadData();
-
- JSUnlock(ctx_);
- if (!threadData.isDebuggerThread()) {
- CHECK(0 == pthread_mutex_unlock(&globalLock_));
- }
- #endif
-}
-
-
-JSValueRef translatePendingCppExceptionToJSError(JSContextRef ctx, const char *exceptionLocation) {
- try {
- throw;
- } catch (const std::bad_alloc& ex) {
- throw; // We probably shouldn't try to handle this in JS
- } catch (const std::exception& ex) {
- if (ExceptionHandling::platformErrorExtractor) {
- auto extractedEror = ExceptionHandling::platformErrorExtractor(ex, exceptionLocation);
- if (extractedEror.message.length() > 0) {
- return Value::makeError(ctx, extractedEror.message.c_str(), extractedEror.stack.c_str());
- }
- }
- auto msg = folly::to<std::string>("C++ exception in '", exceptionLocation, "'\n\n", ex.what());
- return Value::makeError(ctx, msg.c_str());
- } catch (const char* ex) {
- auto msg = folly::to<std::string>("C++ exception (thrown as a char*) in '", exceptionLocation, "'\n\n", ex);
- return Value::makeError(ctx, msg.c_str());
- } catch (...) {
- auto msg = folly::to<std::string>("Unknown C++ exception in '", exceptionLocation, "'");
- return Value::makeError(ctx, msg.c_str());
- }
-}
-
-JSValueRef translatePendingCppExceptionToJSError(JSContextRef ctx, JSObjectRef jsFunctionCause) {
- try {
- auto functionName = Object(ctx, jsFunctionCause).getProperty("name").toString().str();
- return translatePendingCppExceptionToJSError(ctx, functionName.c_str());
- } catch (...) {
- return Value::makeError(ctx, "Failed to translate native exception");
- }
-}
-
-} }

ReactCommon/jschelpers/JSCHelpers.h

@@ -1,149 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#pragma once
-
-#include <algorithm>
-#include <functional>
-#include <stdexcept>
-
-#include <jschelpers/JavaScriptCore.h>
-#include <jschelpers/Value.h>
-
-#ifndef RN_EXPORT
-#define RN_EXPORT __attribute__((visibility("default")))
-#endif
-
-namespace facebook {
-namespace react {
-
-class RN_EXPORT JSException : public std::exception {
-public:
- explicit JSException(const char* msg)
- : msg_(msg) {}
-
- explicit JSException(JSContextRef ctx, JSValueRef exn, const char* msg) {
- buildMessage(ctx, exn, nullptr, msg);
- }
-
- explicit JSException(JSContextRef ctx, JSValueRef exn, JSStringRef sourceURL) {
- buildMessage(ctx, exn, sourceURL, nullptr);
- }
-
- const std::string& getStack() const {
- return stack_;
- }
-
- virtual const char* what() const noexcept override {
- return msg_.c_str();
- }
-
-private:
- std::string msg_;
- std::string stack_;
-
- void buildMessage(JSContextRef ctx, JSValueRef exn, JSStringRef sourceURL, const char* errorMsg);
-};
-
-namespace ExceptionHandling {
- struct ExtractedEror {
- std::string message;
- // Stacktrace formatted like JS stack
- // method@filename[:line[:column]]
- std::string stack;
- };
- typedef ExtractedEror(*PlatformErrorExtractor)(const std::exception &ex, const char *context);
- extern PlatformErrorExtractor platformErrorExtractor;
-}
-
-using JSFunction = std::function<JSValueRef(JSContextRef, JSObjectRef, size_t, const JSValueRef[])>;
-
-JSObjectRef makeFunction(
- JSContextRef ctx,
- const char* name,
- JSFunction function);
-
-RN_EXPORT void installGlobalFunction(
- JSGlobalContextRef ctx,
- const char* name,
- JSFunction function);
-
-JSObjectRef makeFunction(
- JSGlobalContextRef ctx,
- const char* name,
- JSObjectCallAsFunctionCallback callback);
-
-RN_EXPORT void installGlobalFunction(
- JSGlobalContextRef ctx,
- const char* name,
- JSObjectCallAsFunctionCallback callback);
-
-void installGlobalProxy(
- JSGlobalContextRef ctx,
- const char* name,
- JSObjectGetPropertyCallback callback);
-
-void removeGlobal(JSGlobalContextRef ctx, const char* name);
-
-JSValueRef evaluateScript(
- JSContextRef ctx,
- JSStringRef script,
- JSStringRef sourceURL);
-
-#if WITH_FBJSCEXTENSIONS
-JSValueRef evaluateSourceCode(
- JSContextRef ctx,
- JSSourceCodeRef source,
- JSStringRef sourceURL);
-#endif
-
-/**
- * A lock for protecting accesses to the JSGlobalContext
- * This will be a no-op for most compilations, where #if WITH_FBJSCEXTENSIONS is false,
- * but avoids deadlocks in execution environments with advanced locking requirements,
- * particularly with uses of the pthread mutex lock
-**/
-class JSContextLock {
-public:
- JSContextLock(JSGlobalContextRef ctx) noexcept;
- ~JSContextLock() noexcept;
-private:
-#if WITH_FBJSCEXTENSIONS
- JSGlobalContextRef ctx_;
- pthread_mutex_t globalLock_;
-#endif
-};
-
-JSValueRef translatePendingCppExceptionToJSError(JSContextRef ctx, const char *exceptionLocation);
-JSValueRef translatePendingCppExceptionToJSError(JSContextRef ctx, JSObjectRef jsFunctionCause);
-
-template<JSValueRef (method)(JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef *exception)>
-inline JSObjectCallAsFunctionCallback exceptionWrapMethod() {
- struct funcWrapper {
- static JSValueRef call(
- JSContextRef ctx,
- JSObjectRef function,
- JSObjectRef thisObject,
- size_t argumentCount,
- const JSValueRef arguments[],
- JSValueRef *exception) {
- try {
- return (*method)(ctx, function, thisObject, argumentCount, arguments, exception);
- } catch (...) {
- *exception = translatePendingCppExceptionToJSError(ctx, function);
- return JSC_JSValueMakeUndefined(ctx);
- }
- }
- };
-
- return &funcWrapper::call;
-}
-
-} }

ReactCommon/jschelpers/JSCWrapper.cpp

@@ -1,45 +0,0 @@
-/**
- * Copyright (c) 2016-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#include "JSCWrapper.h"
-
-#if defined(__APPLE__)
-
-// TODO: use glog in OSS too
-#if __has_include(<glog/logging.h>)
-#define USE_GLOG 1
-#include <glog/logging.h>
-#else
-#define USE_GLOG 0
-#endif
-
-namespace facebook {
-namespace react {
-
-static const JSCWrapper* s_customWrapper = nullptr;
-
-bool isCustomJSCWrapperSet() {
- return s_customWrapper != nullptr;
-}
-
-const JSCWrapper* customJSCWrapper() {
- #if USE_GLOG
- CHECK(s_customWrapper != nullptr) << "Accessing custom JSC wrapper before it's set";
- #endif
- return s_customWrapper;
-}
-
-void setCustomJSCWrapper(const JSCWrapper* wrapper) {
- #if USE_GLOG
- CHECK(s_customWrapper == nullptr) << "Can't set custom JSC wrapper multiple times";
- #endif
- s_customWrapper = wrapper;
-}
-
-} }
-
-#endif

ReactCommon/jschelpers/JSCWrapper.h

@@ -1,189 +0,0 @@
-/**
- * Copyright (c) 2016-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#pragma once
-
-#include <functional>
-#include <string>
-#include <JavaScriptCore/JavaScript.h>
-
-#if defined(JSCINTERNAL) || (!defined(__APPLE__))
-#define JSC_IMPORT extern "C"
-#else
-#define JSC_IMPORT extern
-#endif
-
-#ifndef RN_EXPORT
-#define RN_EXPORT __attribute__((visibility("default")))
-#endif
-
-namespace facebook {
-namespace react {
- class IInspector;
-}
-}
-
-JSC_IMPORT void JSGlobalContextEnableDebugger(
- JSGlobalContextRef ctx,
- facebook::react::IInspector &globalInspector,
- const char *title,
- const std::function<bool()> &checkIsInspectedRemote);
-JSC_IMPORT void JSGlobalContextDisableDebugger(
- JSGlobalContextRef ctx,
- facebook::react::IInspector &globalInspector);
-
-// This is used to substitute an alternate JSC implementation for
-// testing. These calls must all be ABI compatible with the standard JSC.
-JSC_IMPORT JSValueRef JSEvaluateBytecodeBundle(JSContextRef, JSObjectRef, int, JSStringRef, JSValueRef*);
-JSC_IMPORT bool JSSamplingProfilerEnabled();
-JSC_IMPORT void JSStartSamplingProfilingOnMainJSCThread(JSGlobalContextRef);
-JSC_IMPORT JSValueRef JSPokeSamplingProfiler(JSContextRef);
-#ifdef __cplusplus
-extern "C" {
-#endif
-JSC_IMPORT void configureJSCForIOS(std::string); // TODO: replace with folly::dynamic once supported
-JSC_IMPORT void FBJSContextStartGCTimers(JSContextRef);
-#ifdef __cplusplus
-}
-#endif
-
-#if defined(__APPLE__)
-#include <objc/objc.h>
-#include <JavaScriptCore/JSStringRefCF.h>
-#include <string>
-
-/**
- * JSNoBytecodeFileFormatVersion
- *
- * Version number indicating that bytecode is not supported by this runtime.
- */
-RN_EXPORT extern const int32_t JSNoBytecodeFileFormatVersion;
-
-namespace facebook {
-namespace react {
-
-#define JSC_WRAPPER_METHOD(m) decltype(&m) m
-
-struct JSCWrapper {
- // JSGlobalContext
- JSC_WRAPPER_METHOD(JSGlobalContextCreateInGroup);
- JSC_WRAPPER_METHOD(JSGlobalContextRelease);
- JSC_WRAPPER_METHOD(JSGlobalContextSetName);
-
- // JSContext
- JSC_WRAPPER_METHOD(JSContextGetGlobalContext);
- JSC_WRAPPER_METHOD(JSContextGetGlobalObject);
- JSC_WRAPPER_METHOD(FBJSContextStartGCTimers);
-
- // JSEvaluate
- JSC_WRAPPER_METHOD(JSEvaluateScript);
- JSC_WRAPPER_METHOD(JSEvaluateBytecodeBundle);
-
- // JSString
- JSC_WRAPPER_METHOD(JSStringCreateWithUTF8CString);
- JSC_WRAPPER_METHOD(JSStringCreateWithCFString);
- #if WITH_FBJSCEXTENSIONS
- JSC_WRAPPER_METHOD(JSStringCreateWithUTF8CStringExpectAscii);
- #endif
- JSC_WRAPPER_METHOD(JSStringCopyCFString);
- JSC_WRAPPER_METHOD(JSStringGetCharactersPtr);
- JSC_WRAPPER_METHOD(JSStringGetLength);
- JSC_WRAPPER_METHOD(JSStringGetMaximumUTF8CStringSize);
- JSC_WRAPPER_METHOD(JSStringIsEqualToUTF8CString);
- JSC_WRAPPER_METHOD(JSStringRelease);
- JSC_WRAPPER_METHOD(JSStringRetain);
-
- // JSClass
- JSC_WRAPPER_METHOD(JSClassCreate);
- JSC_WRAPPER_METHOD(JSClassRetain);
- JSC_WRAPPER_METHOD(JSClassRelease);
-
- // JSObject
- JSC_WRAPPER_METHOD(JSObjectCallAsConstructor);
- JSC_WRAPPER_METHOD(JSObjectCallAsFunction);
- JSC_WRAPPER_METHOD(JSObjectGetPrivate);
- JSC_WRAPPER_METHOD(JSObjectGetProperty);
- JSC_WRAPPER_METHOD(JSObjectGetPropertyAtIndex);
- JSC_WRAPPER_METHOD(JSObjectIsConstructor);
- JSC_WRAPPER_METHOD(JSObjectIsFunction);
- JSC_WRAPPER_METHOD(JSObjectMake);
- JSC_WRAPPER_METHOD(JSObjectMakeArray);
- JSC_WRAPPER_METHOD(JSObjectMakeDate);
- JSC_WRAPPER_METHOD(JSObjectMakeError);
- JSC_WRAPPER_METHOD(JSObjectMakeFunctionWithCallback);
- JSC_WRAPPER_METHOD(JSObjectSetPrivate);
- JSC_WRAPPER_METHOD(JSObjectSetProperty);
- JSC_WRAPPER_METHOD(JSObjectSetPropertyAtIndex);
-
- // JSPropertyNameArray
- JSC_WRAPPER_METHOD(JSObjectCopyPropertyNames);
- JSC_WRAPPER_METHOD(JSPropertyNameArrayGetCount);
- JSC_WRAPPER_METHOD(JSPropertyNameArrayGetNameAtIndex);
- JSC_WRAPPER_METHOD(JSPropertyNameArrayRelease);
-
- // JSValue
- JSC_WRAPPER_METHOD(JSValueCreateJSONString);
- JSC_WRAPPER_METHOD(JSValueGetType);
- JSC_WRAPPER_METHOD(JSValueMakeFromJSONString);
- JSC_WRAPPER_METHOD(JSValueMakeBoolean);
- JSC_WRAPPER_METHOD(JSValueMakeNull);
- JSC_WRAPPER_METHOD(JSValueMakeNumber);
- JSC_WRAPPER_METHOD(JSValueMakeString);
- JSC_WRAPPER_METHOD(JSValueMakeUndefined);
- JSC_WRAPPER_METHOD(JSValueProtect);
- JSC_WRAPPER_METHOD(JSValueToBoolean);
- JSC_WRAPPER_METHOD(JSValueToNumber);
- JSC_WRAPPER_METHOD(JSValueToObject);
- JSC_WRAPPER_METHOD(JSValueToStringCopy);
- JSC_WRAPPER_METHOD(JSValueUnprotect);
- JSC_WRAPPER_METHOD(JSValueIsNull);
-
- // Sampling profiler
- JSC_WRAPPER_METHOD(JSSamplingProfilerEnabled);
- JSC_WRAPPER_METHOD(JSPokeSamplingProfiler);
- JSC_WRAPPER_METHOD(JSStartSamplingProfilingOnMainJSCThread);
-
- JSC_WRAPPER_METHOD(JSGlobalContextEnableDebugger);
- JSC_WRAPPER_METHOD(JSGlobalContextDisableDebugger);
-
- JSC_WRAPPER_METHOD(configureJSCForIOS);
-
- // Objective-C API
- Class JSContext;
- Class JSValue;
-
- int32_t JSBytecodeFileFormatVersion;
-};
-
-template <typename T>
-bool isCustomJSCPtr(T *x) {
- return (uintptr_t)x & 0x1;
-}
-
-RN_EXPORT bool isCustomJSCWrapperSet();
-RN_EXPORT void setCustomJSCWrapper(const JSCWrapper* wrapper);
-
-// This will return a single value for the whole life of the process.
-RN_EXPORT const JSCWrapper *systemJSCWrapper();
-RN_EXPORT const JSCWrapper *customJSCWrapper();
-
-} }
-
-#else
-
-namespace facebook {
-namespace react {
-
-template <typename T>
-bool isCustomJSCPtr(T *x) {
- // Always use system JSC pointers
- return false;
-}
-
-} }
-
-#endif

ReactCommon/jschelpers/noncopyable.h

@@ -1,15 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#pragma once
-namespace facebook {
-namespace react {
-struct noncopyable {
- noncopyable(const noncopyable&) = delete;
- noncopyable& operator=(const noncopyable&) = delete;
- protected:
- noncopyable() = default;
-};
-}}

ReactCommon/jschelpers/systemJSCWrapper.cpp

@@ -1,154 +0,0 @@
-/**
- * Copyright (c) 2016-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-#include <jschelpers/JSCWrapper.h>
-
-#if defined(__APPLE__)
-
-#include <mutex>
-
-#include <objc/runtime.h>
-
-// Crash the app (with a descriptive stack trace) if a function that is not supported by
-// the system JSC is called.
-#define UNIMPLEMENTED_SYSTEM_JSC_FUNCTION(FUNC_NAME) \
-static void Unimplemented_##FUNC_NAME(__unused void* args...) { \
- assert(false); \
-}
-
-UNIMPLEMENTED_SYSTEM_JSC_FUNCTION(JSEvaluateBytecodeBundle)
-#if WITH_FBJSCEXTENSIONS
-UNIMPLEMENTED_SYSTEM_JSC_FUNCTION(JSStringCreateWithUTF8CStringExpectAscii)
-#endif
-UNIMPLEMENTED_SYSTEM_JSC_FUNCTION(JSPokeSamplingProfiler)
-UNIMPLEMENTED_SYSTEM_JSC_FUNCTION(JSStartSamplingProfilingOnMainJSCThread)
-
-UNIMPLEMENTED_SYSTEM_JSC_FUNCTION(JSGlobalContextEnableDebugger)
-UNIMPLEMENTED_SYSTEM_JSC_FUNCTION(JSGlobalContextDisableDebugger)
-
-UNIMPLEMENTED_SYSTEM_JSC_FUNCTION(configureJSCForIOS)
-
-UNIMPLEMENTED_SYSTEM_JSC_FUNCTION(FBJSContextStartGCTimers)
-
-bool JSSamplingProfilerEnabled() {
- return false;
-}
-
-const int32_t JSNoBytecodeFileFormatVersion = -1;
-
-namespace facebook {
-namespace react {
-
-static JSCWrapper s_systemWrapper = {};
-
-const JSCWrapper* systemJSCWrapper() {
- // Note that this is not used on Android. All methods are statically linked instead.
- // Some fields are lazily initialized
- static std::once_flag flag;
- std::call_once(flag, []() {
- s_systemWrapper = {
- .JSGlobalContextCreateInGroup = JSGlobalContextCreateInGroup,
- .JSGlobalContextRelease = JSGlobalContextRelease,
- .JSGlobalContextSetName = JSGlobalContextSetName,
-
- .JSContextGetGlobalContext = JSContextGetGlobalContext,
- .JSContextGetGlobalObject = JSContextGetGlobalObject,
- .FBJSContextStartGCTimers =
- (decltype(&FBJSContextStartGCTimers))
- Unimplemented_FBJSContextStartGCTimers,
-
- .JSEvaluateScript = JSEvaluateScript,
- .JSEvaluateBytecodeBundle =
- (decltype(&JSEvaluateBytecodeBundle))
- Unimplemented_JSEvaluateBytecodeBundle,
-
- .JSStringCreateWithUTF8CString = JSStringCreateWithUTF8CString,
- .JSStringCreateWithCFString = JSStringCreateWithCFString,
- #if WITH_FBJSCEXTENSIONS
- .JSStringCreateWithUTF8CStringExpectAscii =
- (decltype(&JSStringCreateWithUTF8CStringExpectAscii))
- Unimplemented_JSStringCreateWithUTF8CStringExpectAscii,
- #endif
- .JSStringCopyCFString = JSStringCopyCFString,
- .JSStringGetCharactersPtr = JSStringGetCharactersPtr,
- .JSStringGetLength = JSStringGetLength,
- .JSStringGetMaximumUTF8CStringSize = JSStringGetMaximumUTF8CStringSize,
- .JSStringIsEqualToUTF8CString = JSStringIsEqualToUTF8CString,
- .JSStringRelease = JSStringRelease,
- .JSStringRetain = JSStringRetain,
-
- .JSClassCreate = JSClassCreate,
- .JSClassRetain = JSClassRetain,
- .JSClassRelease = JSClassRelease,
-
- .JSObjectCallAsConstructor = JSObjectCallAsConstructor,
- .JSObjectCallAsFunction = JSObjectCallAsFunction,
- .JSObjectGetPrivate = JSObjectGetPrivate,
- .JSObjectGetProperty = JSObjectGetProperty,
- .JSObjectGetPropertyAtIndex = JSObjectGetPropertyAtIndex,
- .JSObjectIsConstructor = JSObjectIsConstructor,
- .JSObjectIsFunction = JSObjectIsFunction,
- .JSObjectMake = JSObjectMake,
- .JSObjectMakeArray = JSObjectMakeArray,
- .JSObjectMakeDate = JSObjectMakeDate,
- .JSObjectMakeError = JSObjectMakeError,
- .JSObjectMakeFunctionWithCallback = JSObjectMakeFunctionWithCallback,
- .JSObjectSetPrivate = JSObjectSetPrivate,
- .JSObjectSetProperty = JSObjectSetProperty,
- .JSObjectSetPropertyAtIndex = JSObjectSetPropertyAtIndex,
-
- .JSObjectCopyPropertyNames = JSObjectCopyPropertyNames,
- .JSPropertyNameArrayGetCount = JSPropertyNameArrayGetCount,
- .JSPropertyNameArrayGetNameAtIndex = JSPropertyNameArrayGetNameAtIndex,
- .JSPropertyNameArrayRelease = JSPropertyNameArrayRelease,
-
- .JSValueCreateJSONString = JSValueCreateJSONString,
- .JSValueGetType = JSValueGetType,
- .JSValueMakeFromJSONString = JSValueMakeFromJSONString,
- .JSValueMakeBoolean = JSValueMakeBoolean,
- .JSValueMakeNull = JSValueMakeNull,
- .JSValueMakeNumber = JSValueMakeNumber,
- .JSValueMakeString = JSValueMakeString,
- .JSValueMakeUndefined = JSValueMakeUndefined,
- .JSValueProtect = JSValueProtect,
- .JSValueToBoolean = JSValueToBoolean,
- .JSValueToNumber = JSValueToNumber,
- .JSValueToObject = JSValueToObject,
- .JSValueToStringCopy = JSValueToStringCopy,
- .JSValueUnprotect = JSValueUnprotect,
- .JSValueIsNull = JSValueIsNull,
-
- .JSSamplingProfilerEnabled = JSSamplingProfilerEnabled,
- .JSPokeSamplingProfiler =
- (decltype(&JSPokeSamplingProfiler))
- Unimplemented_JSPokeSamplingProfiler,
- .JSStartSamplingProfilingOnMainJSCThread =
- (decltype(&JSStartSamplingProfilingOnMainJSCThread))
- Unimplemented_JSStartSamplingProfilingOnMainJSCThread,
-
- .JSGlobalContextEnableDebugger =
- (decltype(&JSGlobalContextEnableDebugger))
- Unimplemented_JSGlobalContextEnableDebugger,
- .JSGlobalContextDisableDebugger =
- (decltype(&JSGlobalContextDisableDebugger))
- Unimplemented_JSGlobalContextDisableDebugger,
-
- .configureJSCForIOS =
- (decltype(&configureJSCForIOS))Unimplemented_configureJSCForIOS,
-
- .JSContext = objc_getClass("JSContext"),
- .JSValue = objc_getClass("JSValue"),
-
- .JSBytecodeFileFormatVersion = JSNoBytecodeFileFormatVersion,
- };
- });
- return &s_systemWrapper;
-}
-
-} }
-
-#endif

ReactCommon/jschelpers/Unicode.cpp

@@ -1,91 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#include "Unicode.h"
-
-namespace facebook {
-namespace react {
-namespace unicode {
-namespace {
-
-// TODO(12827176): Don't duplicate this code here and fbjni.
-
-const uint16_t kUtf8OneByteBoundary = 0x80;
-const uint16_t kUtf8TwoBytesBoundary = 0x800;
-const uint16_t kUtf16HighSubLowBoundary = 0xD800;
-const uint16_t kUtf16HighSubHighBoundary = 0xDC00;
-const uint16_t kUtf16LowSubHighBoundary = 0xE000;
-
-// Calculate how many bytes are needed to convert an UTF16 string into UTF8
-// UTF16 string
-size_t utf16toUTF8Length(const uint16_t* utf16String, size_t utf16StringLen) {
- if (!utf16String || utf16StringLen == 0) {
- return 0;
- }
-
- uint32_t utf8StringLen = 0;
- auto utf16StringEnd = utf16String + utf16StringLen;
- auto idx16 = utf16String;
- while (idx16 < utf16StringEnd) {
- auto ch = *idx16++;
- if (ch < kUtf8OneByteBoundary) {
- utf8StringLen++;
- } else if (ch < kUtf8TwoBytesBoundary) {
- utf8StringLen += 2;
- } else if (
- (ch >= kUtf16HighSubLowBoundary) && (ch < kUtf16HighSubHighBoundary) &&
- (idx16 < utf16StringEnd) &&
- (*idx16 >= kUtf16HighSubHighBoundary) && (*idx16 < kUtf16LowSubHighBoundary)) {
- utf8StringLen += 4;
- idx16++;
- } else {
- utf8StringLen += 3;
- }
- }
-
- return utf8StringLen;
-}
-
-} // namespace
-
-std::string utf16toUTF8(const uint16_t* utf16String, size_t utf16StringLen) noexcept {
- if (!utf16String || utf16StringLen <= 0) {
- return "";
- }
-
- std::string utf8String(utf16toUTF8Length(utf16String, utf16StringLen), '\0');
- auto idx8 = utf8String.begin();
- auto idx16 = utf16String;
- auto utf16StringEnd = utf16String + utf16StringLen;
- while (idx16 < utf16StringEnd) {
- auto ch = *idx16++;
- if (ch < kUtf8OneByteBoundary) {
- *idx8++ = (ch & 0x7F);
- } else if (ch < kUtf8TwoBytesBoundary) {
- *idx8++ = 0b11000000 | (ch >> 6);
- *idx8++ = 0b10000000 | (ch & 0x3F);
- } else if (
- (ch >= kUtf16HighSubLowBoundary) && (ch < kUtf16HighSubHighBoundary) &&
- (idx16 < utf16StringEnd) &&
- (*idx16 >= kUtf16HighSubHighBoundary) && (*idx16 < kUtf16LowSubHighBoundary)) {
- auto ch2 = *idx16++;
- uint8_t trunc_byte = (((ch >> 6) & 0x0F) + 1);
- *idx8++ = 0b11110000 | (trunc_byte >> 2);
- *idx8++ = 0b10000000 | ((trunc_byte & 0x03) << 4) | ((ch >> 2) & 0x0F);
- *idx8++ = 0b10000000 | ((ch & 0x03) << 4) | ((ch2 >> 6) & 0x0F);
- *idx8++ = 0b10000000 | (ch2 & 0x3F);
- } else {
- *idx8++ = 0b11100000 | (ch >> 12);
- *idx8++ = 0b10000000 | ((ch >> 6) & 0x3F);
- *idx8++ = 0b10000000 | (ch & 0x3F);
- }
- }
-
- return utf8String;
-}
-
-} // namespace unicode
-} // namespace react
-} // namespace facebook

ReactCommon/jschelpers/Unicode.h

@@ -1,17 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#pragma once
-
-#include <string>
-#include <cstdint>
-
-namespace facebook {
-namespace react {
-namespace unicode {
-__attribute__((visibility("default"))) std::string utf16toUTF8(const uint16_t* utf16, size_t length) noexcept;
-}
-}
-}

ReactCommon/jschelpers/Value.cpp

@@ -1,325 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#include "Value.h"
-
-#include <folly/json.h>
-#include <folly/Conv.h>
-
-#include "JSCHelpers.h"
-#include "JavaScriptCore.h"
-
-// See the comment under Value::fromDynamic()
-#if !defined(__APPLE__) && defined(WITH_FB_JSC_TUNING)
-#define USE_FAST_FOLLY_DYNAMIC_CONVERSION 1
-#else
-#define USE_FAST_FOLLY_DYNAMIC_CONVERSION 0
-#endif
-
-namespace facebook {
-namespace react {
-
-/* static */
-Object Object::makeDate(JSContextRef ctx, Object::TimeType time) {
- using std::chrono::duration_cast;
- using std::chrono::milliseconds;
-
- JSValueRef arguments[1];
- arguments[0] = JSC_JSValueMakeNumber(
- ctx,
- duration_cast<milliseconds>(time.time_since_epoch()).count());
-
- JSValueRef exn;
- auto result = JSC_JSObjectMakeDate(ctx, 1, arguments, &exn);
- if (!result) {
- throw JSException(ctx, exn, "Failed to create Date");
- }
- return Object(ctx, result);
-}
-
-Object Object::makeArray(JSContextRef ctx, JSValueRef* elements, unsigned length) {
- JSValueRef exn;
- auto arr = JSC_JSObjectMakeArray(ctx, length, elements, &exn);
- if (!arr) {
- throw JSException(ctx, exn, "Failed to create an Array");
- }
- return Object(ctx, arr);
-}
-
-Value::Value(JSContextRef context, JSValueRef value)
- : m_context(context), m_value(value) {}
-
-Value::Value(JSContextRef context, JSStringRef str)
- : m_context(context), m_value(JSC_JSValueMakeString(context, str)) {}
-
-JSContextRef Value::context() const {
- return m_context;
-}
-
-/* static */
-std::string Value::toJSONString(unsigned indent) const {
- JSValueRef exn;
- auto stringToAdopt = JSC_JSValueCreateJSONString(m_context, m_value, indent, &exn);
- if (!stringToAdopt) {
- throw JSException(m_context, exn, "Exception creating JSON string");
- }
- return String::adopt(m_context, stringToAdopt).str();
-}
-
-/* static */
-Value Value::fromJSON(const String& json) {
- JSContextRef ctx = json.context();
- auto result = JSC_JSValueMakeFromJSONString(ctx, json);
- if (!result) {
- throw JSException(folly::to<std::string>(
- "Failed to create Value from JSON: ", json.str()).c_str());
- }
- return Value(ctx, result);
-}
-
-Value Value::fromDynamic(JSContextRef ctx, const folly::dynamic& value) {
-// JavaScriptCore's iOS APIs have their own version of this direct conversion.
-// In addition, using this requires exposing some of JSC's private APIs,
-// so it's limited to non-apple platforms and to builds that use the custom JSC.
-// Otherwise, we use the old way of converting through JSON.
-#if USE_FAST_FOLLY_DYNAMIC_CONVERSION
- // Defer GC during the creation of the JSValue, as we don't want
- // intermediate objects to be collected.
- // We could use JSValueProtect(), but it will make the process much slower.
- JSDeferredGCRef deferGC = JSDeferGarbageCollection(ctx);
- // Set a global lock for the whole process,
- // instead of re-acquiring the lock for each operation.
- JSLock(ctx);
- JSValueRef jsVal = Value::fromDynamicInner(ctx, value);
- JSUnlock(ctx);
- JSResumeGarbageCollection(ctx, deferGC);
- return Value(ctx, jsVal);
-#else
- auto json = folly::toJson(value);
- return fromJSON(String(ctx, json.c_str()));
-#endif
-}
-
-JSValueRef Value::fromDynamicInner(JSContextRef ctx, const folly::dynamic& obj) {
- switch (obj.type()) {
- // For primitive types (and strings), just create and return an equivalent JSValue
- case folly::dynamic::Type::NULLT:
- return JSC_JSValueMakeNull(ctx);
-
- case folly::dynamic::Type::BOOL:
- return JSC_JSValueMakeBoolean(ctx, obj.getBool());
-
- case folly::dynamic::Type::DOUBLE:
- return JSC_JSValueMakeNumber(ctx, obj.getDouble());
-
- case folly::dynamic::Type::INT64:
- return JSC_JSValueMakeNumber(ctx, obj.asDouble());
-
- case folly::dynamic::Type::STRING:
- return JSC_JSValueMakeString(ctx, String(ctx, obj.getString().c_str()));
-
- case folly::dynamic::Type::ARRAY: {
- // Collect JSValue for every element in the array
- JSValueRef vals[obj.size()];
- for (size_t i = 0; i < obj.size(); ++i) {
- vals[i] = fromDynamicInner(ctx, obj[i]);
- }
- // Create a JSArray with the values
- JSValueRef arr = JSC_JSObjectMakeArray(ctx, obj.size(), vals, nullptr);
- return arr;
- }
-
- case folly::dynamic::Type::OBJECT: {
- // Create an empty object
- JSObjectRef jsObj = JSC_JSObjectMake(ctx, nullptr, nullptr);
- // Create a JSValue for each of the object's children and set them in the object
- for (auto it = obj.items().begin(); it != obj.items().end(); ++it) {
- JSC_JSObjectSetProperty(
- ctx,
- jsObj,
- String(ctx, it->first.asString().c_str()),
- fromDynamicInner(ctx, it->second),
- kJSPropertyAttributeNone,
- nullptr);
- }
- return jsObj;
- }
- default:
- // Assert not reached
- LOG(FATAL) << "Trying to convert a folly object of unsupported type.";
- return JSC_JSValueMakeNull(ctx);
- }
-}
-
-Object Value::asObject() const {
- JSValueRef exn;
- JSObjectRef jsObj = JSC_JSValueToObject(context(), m_value, &exn);
- if (!jsObj) {
- throw JSException(m_context, exn, "Failed to convert to object");
- }
- return Object(context(), jsObj);
-}
-
-String Value::toString() const {
- JSValueRef exn;
- JSStringRef jsStr = JSC_JSValueToStringCopy(context(), m_value, &exn);
- if (!jsStr) {
- throw JSException(m_context, exn, "Failed to convert to string");
- }
- return String::adopt(context(), jsStr);
-}
-
-Value Value::makeError(JSContextRef ctx, const char *error, const char *stack)
-{
- auto errorMsg = Value(ctx, String(ctx, error));
- JSValueRef args[] = {errorMsg};
- if (stack) {
- // Using this instead of JSObjectMakeError to actually get a stack property.
- // MakeError only sets it stack when returning from the invoked function, so we
- // can't extend it here.
- auto errorConstructor = Object::getGlobalObject(ctx).getProperty("Error").asObject();
- auto jsError = errorConstructor.callAsConstructor({errorMsg});
- auto fullStack = std::string(stack) + jsError.getProperty("stack").toString().str();
- jsError.setProperty("stack", String(ctx, fullStack.c_str()));
- return jsError;
- } else {
- JSValueRef exn;
- JSObjectRef errorObj = JSC_JSObjectMakeError(ctx, 1, args, &exn);
- if (!errorObj) {
- throw JSException(ctx, exn, "Exception making error");
- }
- return Value(ctx, errorObj);
- }
-}
-
-void Value::throwTypeException(const std::string &expectedType) const {
- std::string wat("TypeError: Expected ");
- wat += expectedType;
- wat += ", instead got '";
- wat += toString().str();
- wat += "'";
- throw JSException(wat.c_str());
-}
-
-Object::operator Value() const {
- return Value(m_context, m_obj);
-}
-
-Value Object::callAsFunction(std::initializer_list<JSValueRef> args) const {
- return callAsFunction(nullptr, args.size(), args.begin());
-}
-
-Value Object::callAsFunction(const Object& thisObj, std::initializer_list<JSValueRef> args) const {
- return callAsFunction((JSObjectRef)thisObj, args.size(), args.begin());
-}
-
-Value Object::callAsFunction(int nArgs, const JSValueRef args[]) const {
- return callAsFunction(nullptr, nArgs, args);
-}
-
-Value Object::callAsFunction(const Object& thisObj, int nArgs, const JSValueRef args[]) const {
- return callAsFunction(static_cast<JSObjectRef>(thisObj), nArgs, args);
-}
-
-Value Object::callAsFunction(JSObjectRef thisObj, int nArgs, const JSValueRef args[]) const {
- JSValueRef exn;
- JSValueRef result = JSC_JSObjectCallAsFunction(m_context, m_obj, thisObj, nArgs, args, &exn);
- if (!result) {
- throw JSException(m_context, exn, "Exception calling object as function");
- }
- return Value(m_context, result);
-}
-
-Object Object::callAsConstructor(std::initializer_list<JSValueRef> args) const {
- JSValueRef exn;
- JSObjectRef result = JSC_JSObjectCallAsConstructor(m_context, m_obj, args.size(), args.begin(), &exn);
- if (!result) {
- throw JSException(m_context, exn, "Exception calling object as constructor");
- }
- return Object(m_context, result);
-}
-
-Value Object::getProperty(const String& propName) const {
- JSValueRef exn;
- JSValueRef property = JSC_JSObjectGetProperty(m_context, m_obj, propName, &exn);
- if (!property) {
- throw JSException(m_context, exn, folly::to<std::string>(
- "Failed to get property '", propName.str(), "'").c_str());
- }
- return Value(m_context, property);
-}
-
-Value Object::getPropertyAtIndex(unsigned int index) const {
- JSValueRef exn;
- JSValueRef property = JSC_JSObjectGetPropertyAtIndex(m_context, m_obj, index, &exn);
- if (!property) {
- throw JSException(m_context, exn, folly::to<std::string>(
- "Failed to get property at index ", index).c_str());
- }
- return Value(m_context, property);
-}
-
-Value Object::getProperty(const char *propName) const {
- return getProperty(String(m_context, propName));
-}
-
-void Object::setProperty(const String& propName, const Value& value) {
- JSValueRef exn = nullptr;
- JSC_JSObjectSetProperty(m_context, m_obj, propName, value, kJSPropertyAttributeNone, &exn);
- if (exn) {
- throw JSException(m_context, exn, folly::to<std::string>(
- "Failed to set property '", propName.str(), "'").c_str());
- }
-}
-
-void Object::setPropertyAtIndex(unsigned int index, const Value& value) {
- JSValueRef exn = nullptr;
- JSC_JSObjectSetPropertyAtIndex(m_context, m_obj, index, value, &exn);
- if (exn) {
- throw JSException(m_context, exn, folly::to<std::string>(
- "Failed to set property at index ", index).c_str());
- }
-}
-
-void Object::setProperty(const char *propName, const Value& value) {
- setProperty(String(m_context, propName), value);
-}
-
-std::vector<String> Object::getPropertyNames() const {
- auto namesRef = JSC_JSObjectCopyPropertyNames(m_context, m_obj);
- size_t count = JSC_JSPropertyNameArrayGetCount(m_context, namesRef);
- std::vector<String> names;
- names.reserve(count);
- for (size_t i = 0; i < count; i++) {
- names.emplace_back(String::ref(m_context,
- JSC_JSPropertyNameArrayGetNameAtIndex(m_context, namesRef, i)));
- }
- JSC_JSPropertyNameArrayRelease(m_context, namesRef);
- return names;
-}
-
-std::unordered_map<std::string, std::string> Object::toJSONMap() const {
- std::unordered_map<std::string, std::string> map;
- auto namesRef = JSC_JSObjectCopyPropertyNames(m_context, m_obj);
- size_t count = JSC_JSPropertyNameArrayGetCount(m_context, namesRef);
- for (size_t i = 0; i < count; i++) {
- auto key = String::ref(m_context,
- JSC_JSPropertyNameArrayGetNameAtIndex(m_context, namesRef, i));
- map.emplace(key.str(), getProperty(key).toJSONString());
- }
- JSC_JSPropertyNameArrayRelease(m_context, namesRef);
- return map;
-}
-
-/* static */
-Object Object::create(JSContextRef ctx) {
- JSObjectRef newObj = JSC_JSObjectMake(
- ctx,
- NULL, // create instance of default object class
- NULL); // no private data
- return Object(ctx, newObj);
-}
-
-} }

ReactCommon/jschelpers/Value.h

@@ -1,373 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#pragma once
-
-#include <chrono>
-#include <memory>
-#include <sstream>
-#include <unordered_map>
-#include <vector>
-
-#include <folly/dynamic.h>
-#include <jschelpers/JavaScriptCore.h>
-#include <jschelpers/Unicode.h>
-#include <jschelpers/noncopyable.h>
-#include <privatedata/PrivateDataBase.h>
-
-#ifndef RN_EXPORT
-#define RN_EXPORT __attribute__((visibility("default")))
-#endif
-
-namespace facebook {
-namespace react {
-
-class Value;
-
-// C++ object wrapper for JSStringRef
-class String : public noncopyable {
-public:
- explicit String(): m_context(nullptr), m_string(nullptr) {} // dummy empty constructor
-
- explicit String(JSContextRef context, const char* utf8)
- : m_context(context), m_string(JSC_JSStringCreateWithUTF8CString(context, utf8)) {}
-
- String(String&& other) :
- m_context(other.m_context), m_string(other.m_string)
- {
- other.m_string = nullptr;
- }
-
- String(const String& other) :
- m_context(other.m_context), m_string(other.m_string)
- {
- if (m_string) {
- JSC_JSStringRetain(m_context, m_string);
- }
- }
-
- ~String() {
- if (m_string) {
- JSC_JSStringRelease(m_context, m_string);
- }
- }
-
- String& operator=(String&& other) {
- if (m_string) {
- JSC_JSStringRelease(m_context, m_string);
- }
-
- m_context = other.m_context;
- m_string = other.m_string;
- other.m_string = nullptr;
-
- return *this;
- }
-
- operator JSStringRef() const {
- return m_string;
- }
-
- JSContextRef context() const {
- return m_context;
- }
-
- // Length in characters
- size_t length() const {
- return m_string ? JSC_JSStringGetLength(m_context, m_string) : 0;
- }
-
- // Length in bytes of a nul-terminated utf8 encoded value
- size_t utf8Size() const {
- return m_string ? JSC_JSStringGetMaximumUTF8CStringSize(m_context, m_string) : 0;
- }
-
- /*
- * JavaScriptCore is built with strict utf16 -> utf8 conversion.
- * This means if JSC's built-in conversion function encounters a JavaScript
- * string which contains half of a 32-bit UTF-16 symbol, it produces an error
- * rather than returning a string.
- *
- * Instead of relying on this, we use our own utf16 -> utf8 conversion function
- * which is more lenient and always returns a string. When an invalid UTF-16
- * string is provided, it'll likely manifest as a rendering glitch in the app for
- * the invalid symbol.
- *
- * For details on JavaScript's unicode support see:
- * https://mathiasbynens.be/notes/javascript-unicode
- */
- std::string str() const {
- if (!m_string) {
- return "";
- }
- const JSChar* utf16 = JSC_JSStringGetCharactersPtr(m_context, m_string);
- size_t stringLength = JSC_JSStringGetLength(m_context, m_string);
- return unicode::utf16toUTF8(utf16, stringLength);
- }
-
- // Assumes that utf8 is nul-terminated
- bool equals(const char* utf8) {
- return m_string ? JSC_JSStringIsEqualToUTF8CString(m_context, m_string, utf8) : false;
- }
-
- // This assumes ascii is nul-terminated.
- static String createExpectingAscii(JSContextRef context, const char* ascii, size_t len) {
-#if WITH_FBJSCEXTENSIONS
- return String(context, JSC_JSStringCreateWithUTF8CStringExpectAscii(context, ascii, len), true);
-#else
- return String(context, JSC_JSStringCreateWithUTF8CString(context, ascii), true);
-#endif
- }
-
- static String createExpectingAscii(JSContextRef context, std::string const &ascii) {
- return createExpectingAscii(context, ascii.c_str(), ascii.size());
- }
-
- // Creates a String wrapper and increases the refcount of the JSStringRef
- static String ref(JSContextRef context, JSStringRef string) {
- return String(context, string, false);
- }
-
- // Creates a String wrapper that takes over ownership of the string. The
- // JSStringRef passed in must previously have been created or retained.
- static String adopt(JSContextRef context, JSStringRef string) {
- return String(context, string, true);
- }
-
-private:
- explicit String(JSContextRef context, JSStringRef string, bool adopt) :
- m_context(context), m_string(string)
- {
- if (!adopt && string) {
- JSC_JSStringRetain(context, string);
- }
- }
-
- JSContextRef m_context;
- JSStringRef m_string;
-};
-
-// C++ object wrapper for JSObjectRef. The underlying JSObjectRef can be
-// optionally protected. You must protect the object if it is ever
-// heap-allocated, since otherwise you may end up with an invalid reference.
-class Object : public noncopyable {
-public:
- using TimeType = std::chrono::time_point<std::chrono::system_clock>;
-
- Object(JSContextRef context, JSObjectRef obj) :
- m_context(context),
- m_obj(obj)
- {}
-
- Object(Object&& other) :
- m_context(other.m_context),
- m_obj(other.m_obj),
- m_isProtected(other.m_isProtected) {
- other.m_obj = nullptr;
- other.m_isProtected = false;
- }
-
- ~Object() {
- if (m_isProtected && m_obj) {
- JSC_JSValueUnprotect(m_context, m_obj);
- }
- }
-
- Object& operator=(Object&& other) {
- std::swap(m_context, other.m_context);
- std::swap(m_obj, other.m_obj);
- std::swap(m_isProtected, other.m_isProtected);
- return *this;
- }
-
- operator JSObjectRef() const {
- return m_obj;
- }
-
- operator Value() const;
-
- bool isFunction() const {
- return JSC_JSObjectIsFunction(m_context, m_obj);
- }
-
- Value callAsFunction(std::initializer_list<JSValueRef> args) const;
- Value callAsFunction(const Object& thisObj, std::initializer_list<JSValueRef> args) const;
- Value callAsFunction(int nArgs, const JSValueRef args[]) const;
- Value callAsFunction(const Object& thisObj, int nArgs, const JSValueRef args[]) const;
-
- Object callAsConstructor(std::initializer_list<JSValueRef> args) const;
-
- Value getProperty(const String& propName) const;
- Value getProperty(const char *propName) const;
- Value getPropertyAtIndex(unsigned int index) const;
- void setProperty(const String& propName, const Value& value);
- void setProperty(const char *propName, const Value& value);
- void setPropertyAtIndex(unsigned int index, const Value& value);
- std::vector<String> getPropertyNames() const;
- std::unordered_map<std::string, std::string> toJSONMap() const;
-
- void makeProtected() {
- if (!m_isProtected && m_obj) {
- JSC_JSValueProtect(m_context, m_obj);
- m_isProtected = true;
- }
- }
-
- RN_EXPORT static Object makeArray(JSContextRef ctx, JSValueRef* elements, unsigned length);
- RN_EXPORT static Object makeDate(JSContextRef ctx, TimeType time);
-
- template<typename ReturnType>
- ReturnType* getPrivate() const {
- const bool isCustomJSC = isCustomJSCPtr(m_context);
- return PrivateDataBase::cast<ReturnType>(JSC_JSObjectGetPrivate(isCustomJSC, m_obj));
- }
-
- void setPrivate(PrivateDataBase* data) const {
- const bool isCustomJSC = isCustomJSCPtr(m_context);
- JSC_JSObjectSetPrivate(isCustomJSC, m_obj, data);
- }
-
- JSContextRef context() const {
- return m_context;
- }
-
- static Object getGlobalObject(JSContextRef ctx) {
- auto globalObj = JSC_JSContextGetGlobalObject(ctx);
- return Object(ctx, globalObj);
- }
-
- /**
- * Creates an instance of the default object class.
- */
- static Object create(JSContextRef ctx);
-
-private:
- JSContextRef m_context;
- JSObjectRef m_obj;
- bool m_isProtected = false;
-
- Value callAsFunction(JSObjectRef thisObj, int nArgs, const JSValueRef args[]) const;
-};
-
-// C++ object wrapper for JSValueRef. The underlying JSValueRef is not
-// protected, so this class should always be used as a stack-allocated
-// variable.
-class Value : public noncopyable {
-public:
- RN_EXPORT Value(JSContextRef context, JSValueRef value);
- RN_EXPORT Value(JSContextRef context, JSStringRef value);
-
- RN_EXPORT Value(const Value &o) : Value(o.m_context, o.m_value) {}
- RN_EXPORT Value(const String &o) : Value(o.context(), o) {}
-
- Value& operator=(Value&& other) {
- m_context = other.m_context;
- m_value = other.m_value;
- other.m_value = NULL;
- return *this;
- };
-
- operator JSValueRef() const {
- return m_value;
- }
-
- JSType getType() const {
- return JSC_JSValueGetType(m_context, m_value);
- }
-
- bool isBoolean() const {
- return getType() == kJSTypeBoolean;
- }
-
- bool asBoolean() const {
- return JSC_JSValueToBoolean(context(), m_value);
- }
-
- bool isNumber() const {
- return getType() == kJSTypeNumber;
- }
-
- bool isNull() const {
- return getType() == kJSTypeNull;
- }
-
- bool isUndefined() const {
- return getType() == kJSTypeUndefined;
- }
-
- double asNumber() const {
- if (isNumber()) {
- return JSC_JSValueToNumber(context(), m_value, nullptr);
- } else {
- return 0.0f;
- }
- }
-
- double getNumberOrThrow() const {
- if (!isNumber()) {
- throwTypeException("Number");
- }
- return JSC_JSValueToNumber(context(), m_value, nullptr);
- }
-
- int32_t asInteger() const {
- return static_cast<int32_t>(asNumber());
- }
-
- uint32_t asUnsignedInteger() const {
- return static_cast<uint32_t>(asNumber());
- }
-
- bool isObject() const {
- return getType() == kJSTypeObject;
- }
-
- RN_EXPORT Object asObject() const;
-
- bool isString() const {
- return getType() == kJSTypeString;
- }
-
- RN_EXPORT String toString() const;
-
- // Create an error, optionally adding an additional number of lines to the stack.
- // Stack must be empty or newline terminated.
- RN_EXPORT static Value makeError(JSContextRef ctx, const char *error, const char *stack = nullptr);
-
- static Value makeNumber(JSContextRef ctx, double value) {
- return Value(ctx, JSC_JSValueMakeNumber(ctx, value));
- }
-
- static Value makeUndefined(JSContextRef ctx) {
- return Value(ctx, JSC_JSValueMakeUndefined(ctx));
- }
-
- static Value makeNull(JSContextRef ctx) {
- return Value(ctx, JSC_JSValueMakeNull(ctx));
- }
-
- static Value makeBoolean(JSContextRef ctx, bool value) {
- return Value(ctx, JSC_JSValueMakeBoolean(ctx, value));
- }
-
- static Value makeString(JSContextRef ctx, const char* utf8) {
- return Value(ctx, String(ctx, utf8));
- }
-
- RN_EXPORT std::string toJSONString(unsigned indent = 0) const;
- RN_EXPORT static Value fromJSON(const String& json);
- RN_EXPORT static Value fromDynamic(JSContextRef ctx, const folly::dynamic& value);
- RN_EXPORT JSContextRef context() const;
-
-private:
- JSContextRef m_context;
- JSValueRef m_value;
-
- void throwTypeException(const std::string &expectedType) const;
- static JSValueRef fromDynamicInner(JSContextRef ctx, const folly::dynamic& obj);
-
-};
-
-} }

ReactCommon/jsi/Android.mk

@@ -0,0 +1,20 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := jsi
+
+LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp)
+
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/..
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
+
+LOCAL_CFLAGS := -fexceptions -frtti -O3
+LOCAL_SHARED_LIBRARIES := libfolly_json libjsc glog
+
+include $(BUILD_STATIC_LIBRARY)

ReactCommon/jsi/BUCK

@@ -0,0 +1,110 @@
+# BUILD FILE SYNTAX: SKYLARK
+
+load("//tools/build_defs/oss:rn_defs.bzl", "react_native_xplat_dep", "rn_xplat_cxx_library")
+
+rn_xplat_cxx_library(
+ name = "jsi",
+ srcs = [
+ "jsi.cpp",
+ ],
+ header_namespace = "jsi",
+ exported_headers = [
+ "instrumentation.h",
+ "jsi.h",
+ "jsi-inl.h",
+ ],
+ compiler_flags = [
+ "-O3",
+ "-fexceptions",
+ "-frtti",
+ "-std=c++14",
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ "-Wcast-qual",
+ "-Wdelete-non-virtual-dtor",
+ "-Wwrite-strings",
+ ],
+ cxx_compiler_flags = [
+ "-Wglobal-constructors",
+ "-Wmissing-prototypes",
+ ],
+ fbobjc_compiler_flags = [
+ "-Wglobal-constructors",
+ "-Wmissing-prototypes",
+ ],
+ visibility = ["PUBLIC"],
+)
+
+rn_xplat_cxx_library(
+ name = "JSIDynamic",
+ srcs = [
+ "JSIDynamic.cpp",
+ ],
+ header_namespace = "jsi",
+ exported_headers = [
+ "JSIDynamic.h",
+ ],
+ compiler_flags = [
+ "-fexceptions",
+ "-frtti",
+ ],
+ fbobjc_force_static = True,
+ visibility = [
+ "PUBLIC",
+ ],
+ xcode_public_headers_symlinks = True,
+ deps = [
+ "xplat//folly:molly",
+ react_native_xplat_dep("jsi:jsi"),
+ ],
+)
+
+rn_xplat_cxx_library(
+ name = "JSCRuntime",
+ srcs = [
+ "JSCRuntime.cpp",
+ ],
+ header_namespace = "jsi",
+ exported_headers = [
+ "JSCRuntime.h",
+ ],
+ cxx_exported_platform_linker_flags = [
+ (
+ "macosx-x86_64",
+ [
+ "-framework",
+ "JavaScriptCore",
+ ],
+ ),
+ ],
+ cxx_platform_deps = [
+ (
+ "^(linux|gcc|platform)",
+ [
+ "xplat//jsc:jsc",
+ ],
+ ),
+ ],
+ fbandroid_compiler_flags = [
+ "-fexceptions",
+ "-frtti",
+ "-O3",
+ ],
+ fbandroid_deps = [
+ "xplat//jsc:jsc",
+ ],
+ fbobjc_compiler_flags = [
+ "-Os",
+ ],
+ fbobjc_frameworks = [
+ "$SDKROOT/System/Library/Frameworks/JavaScriptCore.framework",
+ ],
+ visibility = ["PUBLIC"],
+ xplat_mangled_args = {
+ "soname": "libjscjsi.$(ext)",
+ },
+ exported_deps = [
+ react_native_xplat_dep("jsi:jsi"),
+ ],
+)

ReactCommon/jsi/instrumentation.h

@@ -0,0 +1,76 @@
+// 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.
+
+#pragma once
+
+#include <string>
+
+#include <jsi/jsi.h>
+
+namespace facebook {
+namespace jsi {
+
+/// Methods for starting and collecting instrumentation, an \c Instrumentation
+/// instance is associated with a particular \c Runtime instance, which it
+/// controls the instrumentation of.
+class Instrumentation {
+ public:
+ virtual ~Instrumentation() = default;
+
+ /// Returns GC statistics as a JSON-encoded string, with an object containing
+ /// "type" and "version" fields outermost. "type" is a string, unique to a
+ /// particular implementation of \c jsi::Instrumentation, and "version" is a
+ /// number to indicate any revision to that implementation and its output
+ /// format.
+ ///
+ /// \pre This call can only be made on the instrumentation instance of a
+ /// runtime initialised to collect GC statistics.
+ ///
+ /// \post All cumulative measurements mentioned in the output are accumulated
+ /// across the entire lifetime of the Runtime.
+ ///
+ /// \return the GC statistics collected so far, as a JSON-encoded string.
+ virtual std::string getRecordedGCStats() = 0;
+
+ /// Request statistics about the current state of the runtime's heap. This
+ /// function can be called at any time, and should produce information that is
+ /// correct at the instant it is called (i.e, not stale).
+ ///
+ /// \return a jsi Value containing whichever statistics the runtime supports
+ /// for its heap.
+ virtual Value getHeapInfo(bool includeExpensive) = 0;
+
+ /// perform a full garbage collection
+ virtual void collectGarbage() = 0;
+
+ /// Captures the heap to a file
+ ///
+ /// \param path to save the heap capture
+ ///
+ /// \param compact Whether the JSON should be compact or pretty
+ ///
+ /// \return true iff the heap capture succeeded
+ virtual bool createSnapshotToFile(const std::string& path, bool compact) = 0;
+
+ /// Write a trace of bridge traffic to the given file name.
+ virtual void writeBridgeTrafficTraceToFile(
+ const std::string& fileName) const = 0;
+
+ /// Write basic block profile trace to the given file name.
+ virtual void writeBasicBlockProfileTraceToFile(
+ const std::string& fileName) const = 0;
+
+ /// Enable sampling profiler.
+ virtual void enableSamplingProfiler() const = 0;
+
+ /// Dump sampled stack trace to the given file name.
+ virtual void dumpSampledTraceToFile(const std::string& fileName) const = 0;
+
+ /// Dump external profiler symbols to the given file name.
+ virtual void dumpProfilerSymbolsToFile(const std::string& fileName) const = 0;
+};
+
+} // namespace jsi
+} // namespace facebook

ReactCommon/jsi/JSCRuntime.cpp

@@ -0,0 +1,1230 @@
+// 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.
+
+#include "JSCRuntime.h"
+
+#include <JavaScriptCore/JavaScript.h>
+#include <atomic>
+#include <condition_variable>
+#include <cstdlib>
+#include <mutex>
+#include <queue>
+#include <sstream>
+#include <thread>
+
+namespace facebook {
+namespace jsc {
+
+namespace detail {
+class ArgsConverter;
+} // namespace detail
+
+class JSCRuntime;
+
+struct Lock {
+ void lock(const jsc::JSCRuntime&) const {}
+ void unlock(const jsc::JSCRuntime&) const {}
+};
+
+class JSCRuntime : public jsi::Runtime {
+ public:
+ // Creates new context in new context group
+ JSCRuntime();
+ // Retains ctx
+ JSCRuntime(JSGlobalContextRef ctx);
+ ~JSCRuntime();
+
+ void evaluateJavaScript(
+ std::unique_ptr<const jsi::Buffer> buffer,
+ const std::string& sourceURL) override;
+ jsi::Object global() override;
+
+ std::string description() override;
+
+ bool isInspectable() override;
+
+ void setDescription(const std::string& desc);
+
+ // Please don't use the following two functions, only exposed for
+ // integration efforts.
+ JSGlobalContextRef getContext() {
+ return ctx_;
+ }
+
+ // JSValueRef->JSValue (needs make.*Value so it must be member function)
+ jsi::Value createValue(JSValueRef value) const;
+
+ // Value->JSValueRef (similar to above)
+ JSValueRef valueRef(const jsi::Value& value);
+
+ protected:
+ friend class detail::ArgsConverter;
+ class JSCStringValue final : public PointerValue {
+#ifndef NDEBUG
+ JSCStringValue(JSStringRef str, std::atomic<intptr_t>& counter);
+#else
+ JSCStringValue(JSStringRef str);
+#endif
+ void invalidate() override;
+
+ JSStringRef str_;
+#ifndef NDEBUG
+ std::atomic<intptr_t>& counter_;
+#endif
+ protected:
+ friend class JSCRuntime;
+ };
+
+ class JSCObjectValue final : public PointerValue {
+ JSCObjectValue(
+ JSGlobalContextRef ctx,
+ const std::atomic<bool>& ctxInvalid,
+ JSObjectRef obj
+#ifndef NDEBUG
+ ,
+ std::atomic<intptr_t>& counter
+#endif
+ );
+
+ void invalidate() override;
+
+ JSGlobalContextRef ctx_;
+ const std::atomic<bool>& ctxInvalid_;
+ JSObjectRef obj_;
+#ifndef NDEBUG
+ std::atomic<intptr_t>& counter_;
+#endif
+ protected:
+ friend class JSCRuntime;
+ };
+
+ PointerValue* cloneString(const Runtime::PointerValue* pv) override;
+ PointerValue* cloneObject(const Runtime::PointerValue* pv) override;
+ PointerValue* clonePropNameID(const Runtime::PointerValue* pv) override;
+
+ jsi::PropNameID createPropNameIDFromAscii(const char* str, size_t length)
+ override;
+ jsi::PropNameID createPropNameIDFromUtf8(const uint8_t* utf8, size_t length)
+ override;
+ jsi::PropNameID createPropNameIDFromString(const jsi::String& str) override;
+ std::string utf8(const jsi::PropNameID&) override;
+ bool compare(const jsi::PropNameID&, const jsi::PropNameID&) override;
+
+ jsi::String createStringFromAscii(const char* str, size_t length) override;
+ jsi::String createStringFromUtf8(const uint8_t* utf8, size_t length) override;
+ std::string utf8(const jsi::String&) override;
+
+ jsi::Object createObject() override;
+ jsi::Object createObject(std::shared_ptr<jsi::HostObject> ho) override;
+ virtual std::shared_ptr<jsi::HostObject> getHostObject(
+ const jsi::Object&) override;
+ jsi::HostFunctionType& getHostFunction(const jsi::Function&) override;
+
+ jsi::Value getProperty(const jsi::Object&, const jsi::String& name) override;
+ jsi::Value getProperty(const jsi::Object&, const jsi::PropNameID& name)
+ override;
+ bool hasProperty(const jsi::Object&, const jsi::String& name) override;
+ bool hasProperty(const jsi::Object&, const jsi::PropNameID& name) override;
+ void setPropertyValue(
+ jsi::Object&,
+ const jsi::String& name,
+ const jsi::Value& value) override;
+ void setPropertyValue(
+ jsi::Object&,
+ const jsi::PropNameID& name,
+ const jsi::Value& value) override;
+ bool isArray(const jsi::Object&) const override;
+ bool isArrayBuffer(const jsi::Object&) const override;
+ bool isFunction(const jsi::Object&) const override;
+ bool isHostObject(const jsi::Object&) const override;
+ bool isHostFunction(const jsi::Function&) const override;
+ jsi::Array getPropertyNames(const jsi::Object&) override;
+
+ jsi::WeakObject createWeakObject(const jsi::Object&) override;
+ jsi::Value lockWeakObject(const jsi::WeakObject&) override;
+
+ jsi::Array createArray(size_t length) override;
+ size_t size(const jsi::Array&) override;
+ size_t size(const jsi::ArrayBuffer&) override;
+ uint8_t* data(const jsi::ArrayBuffer&) override;
+ jsi::Value getValueAtIndex(const jsi::Array&, size_t i) override;
+ void setValueAtIndexImpl(jsi::Array&, size_t i, const jsi::Value& value)
+ override;
+
+ jsi::Function createFunctionFromHostFunction(
+ const jsi::PropNameID& name,
+ unsigned int paramCount,
+ jsi::HostFunctionType func) override;
+ jsi::Value call(
+ const jsi::Function&,
+ const jsi::Value& jsThis,
+ const jsi::Value* args,
+ size_t count) override;
+ jsi::Value callAsConstructor(
+ const jsi::Function&,
+ const jsi::Value* args,
+ size_t count) override;
+
+ bool strictEquals(const jsi::String& a, const jsi::String& b) const override;
+ bool strictEquals(const jsi::Object& a, const jsi::Object& b) const override;
+ bool instanceOf(const jsi::Object& o, const jsi::Function& f) override;
+
+ private:
+ // Basically convenience casts
+ static JSStringRef stringRef(const jsi::String& str);
+ static JSStringRef stringRef(const jsi::PropNameID& sym);
+ static JSObjectRef objectRef(const jsi::Object& obj);
+
+ // Factory methods for creating String/Object
+ jsi::String createString(JSStringRef stringRef) const;
+ jsi::PropNameID createPropNameID(JSStringRef stringRef);
+ jsi::Object createObject(JSObjectRef objectRef) const;
+
+ // Used by factory methods and clone methods
+ jsi::Runtime::PointerValue* makeStringValue(JSStringRef str) const;
+ jsi::Runtime::PointerValue* makeObjectValue(JSObjectRef obj) const;
+
+ void checkException(JSValueRef exc);
+ void checkException(JSValueRef res, JSValueRef exc);
+ void checkException(JSValueRef exc, const char* msg);
+ void checkException(JSValueRef res, JSValueRef exc, const char* msg);
+
+ JSGlobalContextRef ctx_;
+ std::atomic<bool> ctxInvalid_;
+ std::string desc_;
+#ifndef NDEBUG
+ mutable std::atomic<intptr_t> objectCounter_;
+ mutable std::atomic<intptr_t> stringCounter_;
+#endif
+};
+
+#ifndef __has_builtin
+#define __has_builtin(x) 0
+#endif
+
+#if __has_builtin(__builtin_expect) || defined(__GNUC__)
+#define JSC_LIKELY(EXPR) __builtin_expect((bool)(EXPR), true)
+#define JSC_UNLIKELY(EXPR) __builtin_expect((bool)(EXPR), false)
+#else
+#define JSC_LIKELY(EXPR) (EXPR)
+#define JSC_UNLIKELY(EXPR) (EXPR)
+#endif
+
+#define JSC_ASSERT(x) \
+ do { \
+ if (JSC_UNLIKELY(!!(x))) { \
+ abort(); \
+ } \
+ } while (0)
+
+#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
+// This takes care of watch and tvos (due to backwards compatibility in
+// Availability.h
+#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0
+#define _JSC_FAST_IS_ARRAY
+#endif
+#endif
+#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_11
+// Only one of these should be set for a build. If somehow that's not
+// true, this will be a compile-time error and it can be resolved when
+// we understand why.
+#define _JSC_FAST_IS_ARRAY
+#endif
+#endif
+
+// JSStringRef utilities
+namespace {
+std::string JSStringToSTLString(JSStringRef str) {
+ size_t maxBytes = JSStringGetMaximumUTF8CStringSize(str);
+ std::vector<char> buffer(maxBytes);
+ JSStringGetUTF8CString(str, buffer.data(), maxBytes);
+ return std::string(buffer.data());
+}
+
+JSStringRef getLengthString() {
+ static JSStringRef length = JSStringCreateWithUTF8CString("length");
+ return length;
+}
+
+JSStringRef getNameString() {
+ static JSStringRef name = JSStringCreateWithUTF8CString("name");
+ return name;
+}
+
+JSStringRef getFunctionString() {
+ static JSStringRef func = JSStringCreateWithUTF8CString("Function");
+ return func;
+}
+
+#if !defined(_JSC_FAST_IS_ARRAY)
+JSStringRef getArrayString() {
+ static JSStringRef array = JSStringCreateWithUTF8CString("Array");
+ return array;
+}
+
+JSStringRef getIsArrayString() {
+ static JSStringRef isArray = JSStringCreateWithUTF8CString("isArray");
+ return isArray;
+}
+#endif
+} // namespace
+
+// std::string utility
+namespace {
+std::string to_string(void* value) {
+ std::ostringstream ss;
+ ss << value;
+ return ss.str();
+}
+} // namespace
+
+JSCRuntime::JSCRuntime()
+ : JSCRuntime(JSGlobalContextCreateInGroup(nullptr, nullptr)) {
+ JSGlobalContextRelease(ctx_);
+}
+
+JSCRuntime::JSCRuntime(JSGlobalContextRef ctx)
+ : ctx_(JSGlobalContextRetain(ctx)),
+ ctxInvalid_(false)
+#ifndef NDEBUG
+ ,
+ objectCounter_(0),
+ stringCounter_(0)
+#endif
+{
+}
+
+JSCRuntime::~JSCRuntime() {
+ // On shutting down and cleaning up: when JSC is actually torn down,
+ // it calls JSC::Heap::lastChanceToFinalize internally which
+ // finalizes anything left over. But at this point,
+ // JSValueUnprotect() can no longer be called. We use an
+ // atomic<bool> to avoid unsafe unprotects happening after shutdown
+ // has started.
+ ctxInvalid_ = true;
+ JSGlobalContextRelease(ctx_);
+#ifndef NDEBUG
+ assert(
+ objectCounter_ == 0 && "JSCRuntime destroyed with a dangling API object");
+ assert(
+ stringCounter_ == 0 && "JSCRuntime destroyed with a dangling API string");
+#endif
+}
+
+void JSCRuntime::evaluateJavaScript(
+ std::unique_ptr<const jsi::Buffer> buffer,
+ const std::string& sourceURL) {
+ std::string tmp(
+ reinterpret_cast<const char*>(buffer->data()), buffer->size());
+ JSStringRef sourceRef = JSStringCreateWithUTF8CString(tmp.c_str());
+ JSStringRef sourceURLRef = nullptr;
+ if (!sourceURL.empty()) {
+ sourceURLRef = JSStringCreateWithUTF8CString(sourceURL.c_str());
+ }
+ JSValueRef exc = nullptr;
+ JSValueRef res =
+ JSEvaluateScript(ctx_, sourceRef, nullptr, sourceURLRef, 0, &exc);
+ JSStringRelease(sourceRef);
+ if (sourceURLRef) {
+ JSStringRelease(sourceURLRef);
+ }
+ checkException(res, exc);
+}
+
+jsi::Object JSCRuntime::global() {
+ return createObject(JSContextGetGlobalObject(ctx_));
+}
+
+std::string JSCRuntime::description() {
+ if (desc_.empty()) {
+ desc_ = std::string("<JSCRuntime@") + to_string(this) + ">";
+ }
+ return desc_;
+}
+
+bool JSCRuntime::isInspectable() {
+ return false;
+}
+
+#ifndef NDEBUG
+JSCRuntime::JSCStringValue::JSCStringValue(
+ JSStringRef str,
+ std::atomic<intptr_t>& counter)
+ : str_(JSStringRetain(str)), counter_(counter) {
+ // Since std::atomic returns a copy instead of a reference when calling
+ // operator+= we must do this explicitly in the constructor
+ counter_ += 1;
+}
+#else
+JSCRuntime::JSCStringValue::JSCStringValue(JSStringRef str)
+ : str_(JSStringRetain(str)) {
+}
+#endif
+
+void JSCRuntime::JSCStringValue::invalidate() {
+ // These JSC{String,Object}Value objects are implicitly owned by the
+ // {String,Object} objects, thus when a String/Object is destructed
+ // the JSC{String,Object}Value should be released.
+#ifndef NDEBUG
+ counter_ -= 1;
+#endif
+ JSStringRelease(str_);
+ // Angery reaccs only
+ delete this;
+}
+
+JSCRuntime::JSCObjectValue::JSCObjectValue(
+ JSGlobalContextRef ctx,
+ const std::atomic<bool>& ctxInvalid,
+ JSObjectRef obj
+#ifndef NDEBUG
+ ,
+ std::atomic<intptr_t>& counter
+#endif
+ )
+ : ctx_(ctx),
+ ctxInvalid_(ctxInvalid),
+ obj_(obj)
+#ifndef NDEBUG
+ ,
+ counter_(counter)
+#endif
+{
+ JSValueProtect(ctx_, obj_);
+#ifndef NDEBUG
+ counter_ += 1;
+#endif
+}
+
+void JSCRuntime::JSCObjectValue::invalidate() {
+#ifndef NDEBUG
+ counter_ -= 1;
+#endif
+ // When shutting down the VM, if there is a HostObject which
+ // contains or otherwise owns a jsi::Object, then the final GC will
+ // finalize the HostObject, leading to a call to invalidate(). But
+ // at that point, making calls to JSValueUnprotect will crash.
+ // It is up to the application to make sure that any other calls to
+ // invalidate() happen before VM destruction; see the comment on
+ // jsi::Runtime.
+ //
+ // Another potential concern here is that in the non-shutdown case,
+ // if a HostObject is GCd, JSValueUnprotect will be called from the
+ // JSC finalizer. The documentation warns against this: "You must
+ // not call any function that may cause a garbage collection or an
+ // allocation of a garbage collected object from within a
+ // JSObjectFinalizeCallback. This includes all functions that have a
+ // JSContextRef parameter." However, an audit of the source code for
+ // JSValueUnprotect in late 2018 shows that it cannot cause
+ // allocation or a GC, and further, this code has not changed in
+ // about two years. In the future, we may choose to reintroduce the
+ // mechanism previously used here which uses a separate thread for
+ // JSValueUnprotect, in order to conform to the documented API, but
+ // use the "unsafe" synchronous version on iOS 11 and earlier.
+
+ if (!ctxInvalid_) {
+ JSValueUnprotect(ctx_, obj_);
+ }
+ delete this;
+}
+
+jsi::Runtime::PointerValue* JSCRuntime::cloneString(
+ const jsi::Runtime::PointerValue* pv) {
+ if (!pv) {
+ return nullptr;
+ }
+ const JSCStringValue* string = static_cast<const JSCStringValue*>(pv);
+ return makeStringValue(string->str_);
+}
+
+jsi::Runtime::PointerValue* JSCRuntime::cloneObject(
+ const jsi::Runtime::PointerValue* pv) {
+ if (!pv) {
+ return nullptr;
+ }
+ const JSCObjectValue* object = static_cast<const JSCObjectValue*>(pv);
+ assert(
+ object->ctx_ == ctx_ &&
+ "Don't try to clone an object backed by a different Runtime");
+ return makeObjectValue(object->obj_);
+}
+
+jsi::Runtime::PointerValue* JSCRuntime::clonePropNameID(
+ const jsi::Runtime::PointerValue* pv) {
+ if (!pv) {
+ return nullptr;
+ }
+ const JSCStringValue* string = static_cast<const JSCStringValue*>(pv);
+ return makeStringValue(string->str_);
+}
+
+jsi::PropNameID JSCRuntime::createPropNameIDFromAscii(
+ const char* str,
+ size_t length) {
+ // For system JSC this must is identical to a string
+ std::string tmp(str, length);
+ JSStringRef strRef = JSStringCreateWithUTF8CString(tmp.c_str());
+ auto res = createPropNameID(strRef);
+ JSStringRelease(strRef);
+ return res;
+}
+
+jsi::PropNameID JSCRuntime::createPropNameIDFromUtf8(
+ const uint8_t* utf8,
+ size_t length) {
+ std::string tmp(reinterpret_cast<const char*>(utf8), length);
+ JSStringRef strRef = JSStringCreateWithUTF8CString(tmp.c_str());
+ auto res = createPropNameID(strRef);
+ JSStringRelease(strRef);
+ return res;
+}
+
+jsi::PropNameID JSCRuntime::createPropNameIDFromString(const jsi::String& str) {
+ return createPropNameID(stringRef(str));
+}
+
+std::string JSCRuntime::utf8(const jsi::PropNameID& sym) {
+ return JSStringToSTLString(stringRef(sym));
+}
+
+bool JSCRuntime::compare(const jsi::PropNameID& a, const jsi::PropNameID& b) {
+ return JSStringIsEqual(stringRef(a), stringRef(b));
+}
+
+jsi::String JSCRuntime::createStringFromAscii(const char* str, size_t length) {
+ // Yes we end up double casting for semantic reasons (UTF8 contains ASCII,
+ // not the other way around)
+ return this->createStringFromUtf8(
+ reinterpret_cast<const uint8_t*>(str), length);
+}
+
+jsi::String JSCRuntime::createStringFromUtf8(
+ const uint8_t* str,
+ size_t length) {
+ std::string tmp(reinterpret_cast<const char*>(str), length);
+ JSStringRef stringRef = JSStringCreateWithUTF8CString(tmp.c_str());
+ return createString(stringRef);
+}
+
+std::string JSCRuntime::utf8(const jsi::String& str) {
+ return JSStringToSTLString(stringRef(str));
+}
+
+jsi::Object JSCRuntime::createObject() {
+ return createObject(static_cast<JSObjectRef>(nullptr));
+}
+
+// HostObject details
+namespace detail {
+struct HostObjectProxyBase {
+ HostObjectProxyBase(
+ JSCRuntime& rt,
+ const std::shared_ptr<jsi::HostObject>& sho)
+ : runtime(rt), hostObject(sho) {}
+
+ JSCRuntime& runtime;
+ std::shared_ptr<jsi::HostObject> hostObject;
+};
+} // namespace detail
+
+namespace {
+std::once_flag hostObjectClassOnceFlag;
+JSClassRef hostObjectClass{};
+} // namespace
+
+jsi::Object JSCRuntime::createObject(std::shared_ptr<jsi::HostObject> ho) {
+ struct HostObjectProxy : public detail::HostObjectProxyBase {
+ static JSValueRef getProperty(
+ JSContextRef ctx,
+ JSObjectRef object,
+ JSStringRef propertyName,
+ JSValueRef* exception) {
+ auto proxy = static_cast<HostObjectProxy*>(JSObjectGetPrivate(object));
+ auto& rt = proxy->runtime;
+ jsi::PropNameID sym = rt.createPropNameID(propertyName);
+ jsi::Value ret;
+ try {
+ ret = proxy->hostObject->get(rt, sym);
+ } catch (const jsi::JSError& error) {
+ *exception = rt.valueRef(error.value());
+ return JSValueMakeUndefined(ctx);
+ } catch (const std::exception& ex) {
+ auto excValue =
+ rt.global()
+ .getPropertyAsFunction(rt, "Error")
+ .call(
+ rt,
+ std::string("Exception in HostObject::get: ") + ex.what());
+ *exception = rt.valueRef(excValue);
+ return JSValueMakeUndefined(ctx);
+ } catch (...) {
+ auto excValue =
+ rt.global()
+ .getPropertyAsFunction(rt, "Error")
+ .call(rt, "Exception in HostObject::get: <unknown>");
+ *exception = rt.valueRef(excValue);
+ return JSValueMakeUndefined(ctx);
+ }
+ return rt.valueRef(ret);
+ }
+
+ #define JSC_UNUSED(x) (void) (x);
+
+ static bool setProperty(
+ JSContextRef ctx,
+ JSObjectRef object,
+ JSStringRef propName,
+ JSValueRef value,
+ JSValueRef* exception) {
+ JSC_UNUSED(ctx);
+ auto proxy = static_cast<HostObjectProxy*>(JSObjectGetPrivate(object));
+ auto& rt = proxy->runtime;
+ jsi::PropNameID sym = rt.createPropNameID(propName);
+ try {
+ proxy->hostObject->set(rt, sym, rt.createValue(value));
+ } catch (const jsi::JSError& error) {
+ *exception = rt.valueRef(error.value());
+ return false;
+ } catch (const std::exception& ex) {
+ auto excValue =
+ rt.global()
+ .getPropertyAsFunction(rt, "Error")
+ .call(
+ rt,
+ std::string("Exception in HostObject::set: ") + ex.what());
+ *exception = rt.valueRef(excValue);
+ return false;
+ } catch (...) {
+ auto excValue =
+ rt.global()
+ .getPropertyAsFunction(rt, "Error")
+ .call(rt, "Exception in HostObject::set: <unknown>");
+ *exception = rt.valueRef(excValue);
+ return false;
+ }
+ return true;
+ }
+
+ // JSC does not provide means to communicate errors from this callback,
+ // so the error handling strategy is very brutal - we'll just crash
+ // due to noexcept.
+ static void getPropertyNames(
+ JSContextRef ctx,
+ JSObjectRef object,
+ JSPropertyNameAccumulatorRef propertyNames) noexcept {
+ JSC_UNUSED(ctx);
+ auto proxy = static_cast<HostObjectProxy*>(JSObjectGetPrivate(object));
+ auto& rt = proxy->runtime;
+ auto names = proxy->hostObject->getPropertyNames(rt);
+ for (auto& name : names) {
+ JSPropertyNameAccumulatorAddName(propertyNames, stringRef(name));
+ }
+ }
+
+ #undef JSC_UNUSED
+
+ static void finalize(JSObjectRef obj) {
+ auto hostObject = static_cast<HostObjectProxy*>(JSObjectGetPrivate(obj));
+ JSObjectSetPrivate(obj, nullptr);
+ delete hostObject;
+ }
+
+ using HostObjectProxyBase::HostObjectProxyBase;
+ };
+
+ std::call_once(hostObjectClassOnceFlag, []() {
+ JSClassDefinition hostObjectClassDef = kJSClassDefinitionEmpty;
+ hostObjectClassDef.version = 0;
+ hostObjectClassDef.attributes = kJSClassAttributeNoAutomaticPrototype;
+ hostObjectClassDef.finalize = HostObjectProxy::finalize;
+ hostObjectClassDef.getProperty = HostObjectProxy::getProperty;
+ hostObjectClassDef.setProperty = HostObjectProxy::setProperty;
+ hostObjectClassDef.getPropertyNames = HostObjectProxy::getPropertyNames;
+ hostObjectClass = JSClassCreate(&hostObjectClassDef);
+ });
+
+ JSObjectRef obj =
+ JSObjectMake(ctx_, hostObjectClass, new HostObjectProxy(*this, ho));
+ return createObject(obj);
+}
+
+std::shared_ptr<jsi::HostObject> JSCRuntime::getHostObject(
+ const jsi::Object& obj) {
+ // We are guarenteed at this point to have isHostObject(obj) == true
+ // so the private data should be HostObjectMetadata
+ JSObjectRef object = objectRef(obj);
+ auto metadata =
+ static_cast<detail::HostObjectProxyBase*>(JSObjectGetPrivate(object));
+ assert(metadata);
+ return metadata->hostObject;
+}
+
+jsi::Value JSCRuntime::getProperty(
+ const jsi::Object& obj,
+ const jsi::String& name) {
+ JSObjectRef objRef = objectRef(obj);
+ JSValueRef exc = nullptr;
+ JSValueRef res = JSObjectGetProperty(ctx_, objRef, stringRef(name), &exc);
+ checkException(exc);
+ return createValue(res);
+}
+
+jsi::Value JSCRuntime::getProperty(
+ const jsi::Object& obj,
+ const jsi::PropNameID& name) {
+ JSObjectRef objRef = objectRef(obj);
+ JSValueRef exc = nullptr;
+ JSValueRef res = JSObjectGetProperty(ctx_, objRef, stringRef(name), &exc);
+ checkException(exc);
+ return createValue(res);
+}
+
+bool JSCRuntime::hasProperty(const jsi::Object& obj, const jsi::String& name) {
+ JSObjectRef objRef = objectRef(obj);
+ return JSObjectHasProperty(ctx_, objRef, stringRef(name));
+}
+
+bool JSCRuntime::hasProperty(
+ const jsi::Object& obj,
+ const jsi::PropNameID& name) {
+ JSObjectRef objRef = objectRef(obj);
+ return JSObjectHasProperty(ctx_, objRef, stringRef(name));
+}
+
+void JSCRuntime::setPropertyValue(
+ jsi::Object& object,
+ const jsi::PropNameID& name,
+ const jsi::Value& value) {
+ JSValueRef exc = nullptr;
+ JSObjectSetProperty(
+ ctx_,
+ objectRef(object),
+ stringRef(name),
+ valueRef(value),
+ kJSPropertyAttributeNone,
+ &exc);
+ checkException(exc);
+}
+
+void JSCRuntime::setPropertyValue(
+ jsi::Object& object,
+ const jsi::String& name,
+ const jsi::Value& value) {
+ JSValueRef exc = nullptr;
+ JSObjectSetProperty(
+ ctx_,
+ objectRef(object),
+ stringRef(name),
+ valueRef(value),
+ kJSPropertyAttributeNone,
+ &exc);
+ checkException(exc);
+}
+
+bool JSCRuntime::isArray(const jsi::Object& obj) const {
+#if !defined(_JSC_FAST_IS_ARRAY)
+ JSObjectRef global = JSContextGetGlobalObject(ctx_);
+ JSStringRef arrayString = getArrayString();
+ JSValueRef exc = nullptr;
+ JSValueRef arrayCtorValue =
+ JSObjectGetProperty(ctx_, global, arrayString, &exc);
+ JSC_ASSERT(exc);
+ JSObjectRef arrayCtor = JSValueToObject(ctx_, arrayCtorValue, &exc);
+ JSC_ASSERT(exc);
+ JSStringRef isArrayString = getIsArrayString();
+ JSValueRef isArrayValue =
+ JSObjectGetProperty(ctx_, arrayCtor, isArrayString, &exc);
+ JSC_ASSERT(exc);
+ JSObjectRef isArray = JSValueToObject(ctx_, isArrayValue, &exc);
+ JSC_ASSERT(exc);
+ JSValueRef arg = objectRef(obj);
+ JSValueRef result =
+ JSObjectCallAsFunction(ctx_, isArray, nullptr, 1, &arg, &exc);
+ JSC_ASSERT(exc);
+ return JSValueToBoolean(ctx_, result);
+#else
+ return JSValueIsArray(ctx_, objectRef(obj));
+#endif
+}
+
+bool JSCRuntime::isArrayBuffer(const jsi::Object& /*obj*/) const {
+ // TODO: T23270523 - This would fail on builds that use our custom JSC
+ // auto typedArrayType = JSValueGetTypedArrayType(ctx_, objectRef(obj),
+ // nullptr); return typedArrayType == kJSTypedArrayTypeArrayBuffer;
+ throw std::runtime_error("Unsupported");
+}
+
+uint8_t* JSCRuntime::data(const jsi::ArrayBuffer& /*obj*/) {
+ // TODO: T23270523 - This would fail on builds that use our custom JSC
+ // return static_cast<uint8_t*>(
+ // JSObjectGetArrayBufferBytesPtr(ctx_, objectRef(obj), nullptr));
+ throw std::runtime_error("Unsupported");
+}
+
+size_t JSCRuntime::size(const jsi::ArrayBuffer& /*obj*/) {
+ // TODO: T23270523 - This would fail on builds that use our custom JSC
+ // return JSObjectGetArrayBufferByteLength(ctx_, objectRef(obj), nullptr);
+ throw std::runtime_error("Unsupported");
+}
+
+bool JSCRuntime::isFunction(const jsi::Object& obj) const {
+ return JSObjectIsFunction(ctx_, objectRef(obj));
+}
+
+bool JSCRuntime::isHostObject(const jsi::Object& obj) const {
+ auto cls = hostObjectClass;
+ return cls != nullptr && JSValueIsObjectOfClass(ctx_, objectRef(obj), cls);
+}
+
+// Very expensive
+jsi::Array JSCRuntime::getPropertyNames(const jsi::Object& obj) {
+ JSPropertyNameArrayRef names =
+ JSObjectCopyPropertyNames(ctx_, objectRef(obj));
+ size_t len = JSPropertyNameArrayGetCount(names);
+ // Would be better if we could create an array with explicit elements
+ auto result = createArray(len);
+ for (size_t i = 0; i < len; i++) {
+ JSStringRef str = JSPropertyNameArrayGetNameAtIndex(names, i);
+ result.setValueAtIndex(*this, i, createString(str));
+ }
+ JSPropertyNameArrayRelease(names);
+ return result;
+}
+
+jsi::WeakObject JSCRuntime::createWeakObject(const jsi::Object&) {
+ throw std::logic_error("Not implemented");
+}
+
+jsi::Value JSCRuntime::lockWeakObject(const jsi::WeakObject&) {
+ throw std::logic_error("Not implemented");
+}
+
+jsi::Array JSCRuntime::createArray(size_t length) {
+ JSValueRef exc = nullptr;
+ JSObjectRef obj = JSObjectMakeArray(ctx_, 0, nullptr, &exc);
+ checkException(obj, exc);
+ JSObjectSetProperty(
+ ctx_,
+ obj,
+ getLengthString(),
+ JSValueMakeNumber(ctx_, static_cast<double>(length)),
+ 0,
+ &exc);
+ checkException(exc);
+ return createObject(obj).getArray(*this);
+}
+
+size_t JSCRuntime::size(const jsi::Array& arr) {
+ return static_cast<size_t>(
+ getProperty(arr, createPropNameID(getLengthString())).getNumber());
+}
+
+jsi::Value JSCRuntime::getValueAtIndex(const jsi::Array& arr, size_t i) {
+ JSValueRef exc = nullptr;
+ auto res = JSObjectGetPropertyAtIndex(ctx_, objectRef(arr), (int)i, &exc);
+ checkException(exc);
+ return createValue(res);
+}
+
+void JSCRuntime::setValueAtIndexImpl(
+ jsi::Array& arr,
+ size_t i,
+ const jsi::Value& value) {
+ JSValueRef exc = nullptr;
+ JSObjectSetPropertyAtIndex(ctx_, objectRef(arr), (int)i, valueRef(value), &exc);
+ checkException(exc);
+}
+
+namespace {
+std::once_flag hostFunctionClassOnceFlag;
+JSClassRef hostFunctionClass{};
+
+class HostFunctionProxy {
+ public:
+ HostFunctionProxy(jsi::HostFunctionType hostFunction)
+ : hostFunction_(hostFunction) {}
+
+ jsi::HostFunctionType& getHostFunction() {
+ return hostFunction_;
+ }
+
+ protected:
+ jsi::HostFunctionType hostFunction_;
+};
+} // namespace
+
+jsi::Function JSCRuntime::createFunctionFromHostFunction(
+ const jsi::PropNameID& name,
+ unsigned int paramCount,
+ jsi::HostFunctionType func) {
+ class HostFunctionMetadata : public HostFunctionProxy {
+ public:
+ static void initialize(JSContextRef ctx, JSObjectRef object) {
+ // We need to set up the prototype chain properly here. In theory we
+ // could set func.prototype.prototype = Function.prototype to get the
+ // same result. Not sure which approach is better.
+ HostFunctionMetadata* metadata =
+ static_cast<HostFunctionMetadata*>(JSObjectGetPrivate(object));
+
+ JSValueRef exc = nullptr;
+ JSObjectSetProperty(
+ ctx,
+ object,
+ getLengthString(),
+ JSValueMakeNumber(ctx, metadata->argCount),
+ kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum |
+ kJSPropertyAttributeDontDelete,
+ &exc);
+ if (exc) {
+ // Silently fail to set length
+ exc = nullptr;
+ }
+
+ JSStringRef name = nullptr;
+ std::swap(metadata->name, name);
+ JSObjectSetProperty(
+ ctx,
+ object,
+ getNameString(),
+ JSValueMakeString(ctx, name),
+ kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum |
+ kJSPropertyAttributeDontDelete,
+ &exc);
+ JSStringRelease(name);
+ if (exc) {
+ // Silently fail to set name
+ exc = nullptr;
+ }
+
+ JSObjectRef global = JSContextGetGlobalObject(ctx);
+ JSValueRef value =
+ JSObjectGetProperty(ctx, global, getFunctionString(), &exc);
+ // If we don't have Function then something bad is going on.
+ if (JSC_UNLIKELY(exc)) {
+ abort();
+ }
+ JSObjectRef funcCtor = JSValueToObject(ctx, value, &exc);
+ if (!funcCtor) {
+ // We can't do anything if Function is not an object
+ return;
+ }
+ JSValueRef funcProto = JSObjectGetPrototype(ctx, funcCtor);
+ JSObjectSetPrototype(ctx, object, funcProto);
+ }
+
+ static JSValueRef makeError(JSCRuntime& rt, const std::string& desc) {
+ jsi::Value value =
+ rt.global().getPropertyAsFunction(rt, "Error").call(rt, desc);
+ return rt.valueRef(value);
+ }
+
+ static JSValueRef call(
+ JSContextRef ctx,
+ JSObjectRef function,
+ JSObjectRef thisObject,
+ size_t argumentCount,
+ const JSValueRef arguments[],
+ JSValueRef* exception) {
+ HostFunctionMetadata* metadata =
+ static_cast<HostFunctionMetadata*>(JSObjectGetPrivate(function));
+ JSCRuntime& rt = *(metadata->runtime);
+ const unsigned maxStackArgCount = 8;
+ jsi::Value stackArgs[maxStackArgCount];
+ std::unique_ptr<jsi::Value[]> heapArgs;
+ jsi::Value* args;
+ if (argumentCount > maxStackArgCount) {
+ heapArgs = std::make_unique<jsi::Value[]>(argumentCount);
+ for (size_t i = 0; i < argumentCount; i++) {
+ heapArgs[i] = rt.createValue(arguments[i]);
+ }
+ args = heapArgs.get();
+ } else {
+ for (size_t i = 0; i < argumentCount; i++) {
+ stackArgs[i] = rt.createValue(arguments[i]);
+ }
+ args = stackArgs;
+ }
+ JSValueRef res;
+ jsi::Value thisVal(rt.createObject(thisObject));
+ try {
+ res = rt.valueRef(
+ metadata->hostFunction_(rt, thisVal, args, argumentCount));
+ } catch (const jsi::JSError& error) {
+ *exception = rt.valueRef(error.value());
+ res = JSValueMakeUndefined(ctx);
+ } catch (const std::exception& ex) {
+ std::string exceptionString("Exception in HostFunction: ");
+ exceptionString += ex.what();
+ *exception = makeError(rt, exceptionString);
+ res = JSValueMakeUndefined(ctx);
+ } catch (...) {
+ std::string exceptionString("Exception in HostFunction: <unknown>");
+ *exception = makeError(rt, exceptionString);
+ res = JSValueMakeUndefined(ctx);
+ }
+ return res;
+ }
+
+ static void finalize(JSObjectRef object) {
+ HostFunctionMetadata* metadata =
+ static_cast<HostFunctionMetadata*>(JSObjectGetPrivate(object));
+ JSObjectSetPrivate(object, nullptr);
+ delete metadata;
+ }
+
+ HostFunctionMetadata(
+ JSCRuntime* rt,
+ jsi::HostFunctionType hf,
+ unsigned ac,
+ JSStringRef n)
+ : HostFunctionProxy(hf),
+ runtime(rt),
+ argCount(ac),
+ name(JSStringRetain(n)) {}
+
+ JSCRuntime* runtime;
+ unsigned argCount;
+ JSStringRef name;
+ };
+
+ std::call_once(hostFunctionClassOnceFlag, []() {
+ JSClassDefinition functionClass = kJSClassDefinitionEmpty;
+ functionClass.version = 0;
+ functionClass.attributes = kJSClassAttributeNoAutomaticPrototype;
+ functionClass.initialize = HostFunctionMetadata::initialize;
+ functionClass.finalize = HostFunctionMetadata::finalize;
+ functionClass.callAsFunction = HostFunctionMetadata::call;
+
+ hostFunctionClass = JSClassCreate(&functionClass);
+ });
+
+ JSObjectRef funcRef = JSObjectMake(
+ ctx_,
+ hostFunctionClass,
+ new HostFunctionMetadata(this, func, paramCount, stringRef(name)));
+ return createObject(funcRef).getFunction(*this);
+}
+
+namespace detail {
+
+class ArgsConverter {
+ public:
+ ArgsConverter(JSCRuntime& rt, const jsi::Value* args, size_t count) {
+ JSValueRef* destination = inline_;
+ if (count > maxStackArgs) {
+ outOfLine_ = std::make_unique<JSValueRef[]>(count);
+ destination = outOfLine_.get();
+ }
+
+ for (size_t i = 0; i < count; ++i) {
+ destination[i] = rt.valueRef(args[i]);
+ }
+ }
+
+ operator JSValueRef*() {
+ return outOfLine_ ? outOfLine_.get() : inline_;
+ }
+
+ private:
+ constexpr static unsigned maxStackArgs = 8;
+ JSValueRef inline_[maxStackArgs];
+ std::unique_ptr<JSValueRef[]> outOfLine_;
+};
+} // namespace detail
+
+bool JSCRuntime::isHostFunction(const jsi::Function& obj) const {
+ auto cls = hostFunctionClass;
+ return cls != nullptr && JSValueIsObjectOfClass(ctx_, objectRef(obj), cls);
+}
+
+jsi::HostFunctionType& JSCRuntime::getHostFunction(const jsi::Function& obj) {
+ // We know that isHostFunction(obj) is true here, so its safe to proceed
+ auto proxy =
+ static_cast<HostFunctionProxy*>(JSObjectGetPrivate(objectRef(obj)));
+ return proxy->getHostFunction();
+}
+
+jsi::Value JSCRuntime::call(
+ const jsi::Function& f,
+ const jsi::Value& jsThis,
+ const jsi::Value* args,
+ size_t count) {
+ JSValueRef exc = nullptr;
+ auto res = JSObjectCallAsFunction(
+ ctx_,
+ objectRef(f),
+ jsThis.isUndefined() ? nullptr : objectRef(jsThis.getObject(*this)),
+ count,
+ detail::ArgsConverter(*this, args, count),
+ &exc);
+ checkException(exc);
+ return createValue(res);
+}
+
+jsi::Value JSCRuntime::callAsConstructor(
+ const jsi::Function& f,
+ const jsi::Value* args,
+ size_t count) {
+ JSValueRef exc = nullptr;
+ auto res = JSObjectCallAsConstructor(
+ ctx_,
+ objectRef(f),
+ count,
+ detail::ArgsConverter(*this, args, count),
+ &exc);
+ checkException(exc);
+ return createValue(res);
+}
+
+bool JSCRuntime::strictEquals(const jsi::String& a, const jsi::String& b)
+ const {
+ return JSStringIsEqual(stringRef(a), stringRef(b));
+}
+
+bool JSCRuntime::strictEquals(const jsi::Object& a, const jsi::Object& b)
+ const {
+ return objectRef(a) == objectRef(b);
+}
+
+bool JSCRuntime::instanceOf(const jsi::Object& o, const jsi::Function& f) {
+ JSValueRef exc = nullptr;
+ bool res =
+ JSValueIsInstanceOfConstructor(ctx_, objectRef(o), objectRef(f), &exc);
+ checkException(exc);
+ return res;
+}
+
+namespace {
+JSStringRef getEmptyString() {
+ static JSStringRef empty = JSStringCreateWithUTF8CString("");
+ return empty;
+}
+} // namespace
+
+jsi::Runtime::PointerValue* JSCRuntime::makeStringValue(
+ JSStringRef stringRef) const {
+ if (!stringRef) {
+ stringRef = getEmptyString();
+ }
+#ifndef NDEBUG
+ return new JSCStringValue(stringRef, stringCounter_);
+#else
+ return new JSCStringValue(stringRef);
+#endif
+}
+
+jsi::String JSCRuntime::createString(JSStringRef str) const {
+ return make<jsi::String>(makeStringValue(str));
+}
+
+jsi::PropNameID JSCRuntime::createPropNameID(JSStringRef str) {
+ return make<jsi::PropNameID>(makeStringValue(str));
+}
+
+jsi::Runtime::PointerValue* JSCRuntime::makeObjectValue(
+ JSObjectRef objectRef) const {
+ if (!objectRef) {
+ objectRef = JSObjectMake(ctx_, nullptr, nullptr);
+ }
+#ifndef NDEBUG
+ return new JSCObjectValue(ctx_, ctxInvalid_, objectRef, objectCounter_);
+#else
+ return new JSCObjectValue(ctx_, ctxInvalid_, objectRef);
+#endif
+}
+
+jsi::Object JSCRuntime::createObject(JSObjectRef obj) const {
+ return make<jsi::Object>(makeObjectValue(obj));
+}
+
+jsi::Value JSCRuntime::createValue(JSValueRef value) const {
+ if (JSValueIsNumber(ctx_, value)) {
+ return jsi::Value(JSValueToNumber(ctx_, value, nullptr));
+ } else if (JSValueIsBoolean(ctx_, value)) {
+ return jsi::Value(JSValueToBoolean(ctx_, value));
+ } else if (JSValueIsNull(ctx_, value)) {
+ return jsi::Value(nullptr);
+ } else if (JSValueIsUndefined(ctx_, value)) {
+ return jsi::Value();
+ } else if (JSValueIsString(ctx_, value)) {
+ JSStringRef str = JSValueToStringCopy(ctx_, value, nullptr);
+ auto result = jsi::Value(createString(str));
+ JSStringRelease(str);
+ return result;
+ } else if (JSValueIsObject(ctx_, value)) {
+ JSObjectRef objRef = JSValueToObject(ctx_, value, nullptr);
+ return jsi::Value(createObject(objRef));
+ } else {
+ // WHAT ARE YOU
+ abort();
+ }
+}
+
+JSValueRef JSCRuntime::valueRef(const jsi::Value& value) {
+ // I would rather switch on value.kind_
+ if (value.isUndefined()) {
+ return JSValueMakeUndefined(ctx_);
+ } else if (value.isNull()) {
+ return JSValueMakeNull(ctx_);
+ } else if (value.isBool()) {
+ return JSValueMakeBoolean(ctx_, value.getBool());
+ } else if (value.isNumber()) {
+ return JSValueMakeNumber(ctx_, value.getNumber());
+ } else if (value.isString()) {
+ return JSValueMakeString(ctx_, stringRef(value.getString(*this)));
+ } else if (value.isObject()) {
+ return objectRef(value.getObject(*this));
+ } else {
+ // What are you?
+ abort();
+ }
+}
+
+JSStringRef JSCRuntime::stringRef(const jsi::String& str) {
+ return static_cast<const JSCStringValue*>(getPointerValue(str))->str_;
+}
+
+JSStringRef JSCRuntime::stringRef(const jsi::PropNameID& sym) {
+ return static_cast<const JSCStringValue*>(getPointerValue(sym))->str_;
+}
+
+JSObjectRef JSCRuntime::objectRef(const jsi::Object& obj) {
+ return static_cast<const JSCObjectValue*>(getPointerValue(obj))->obj_;
+}
+
+void JSCRuntime::checkException(JSValueRef exc) {
+ if (JSC_UNLIKELY(exc)) {
+ throw jsi::JSError(*this, createValue(exc));
+ }
+}
+
+void JSCRuntime::checkException(JSValueRef res, JSValueRef exc) {
+ if (JSC_UNLIKELY(!res)) {
+ throw jsi::JSError(*this, createValue(exc));
+ }
+}
+
+void JSCRuntime::checkException(JSValueRef exc, const char* msg) {
+ if (JSC_UNLIKELY(exc)) {
+ throw jsi::JSError(std::string(msg), *this, createValue(exc));
+ }
+}
+
+void JSCRuntime::checkException(
+ JSValueRef res,
+ JSValueRef exc,
+ const char* msg) {
+ if (JSC_UNLIKELY(!res)) {
+ throw jsi::JSError(std::string(msg), *this, createValue(exc));
+ }
+}
+
+std::unique_ptr<jsi::Runtime> makeJSCRuntime() {
+ return std::make_unique<JSCRuntime>();
+}
+
+} // namespace jsc
+} // namespace facebook

ReactCommon/jsi/JSCRuntime.h

@@ -0,0 +1,17 @@
+// 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.
+
+#pragma once
+
+#include <jsi/jsi.h>
+#include <memory.h>
+
+namespace facebook {
+namespace jsc {
+
+std::unique_ptr<jsi::Runtime> makeJSCRuntime();
+
+} // namespace jsc
+} // namespace facebook

ReactCommon/jsi/jsi.cpp

@@ -0,0 +1,353 @@
+// 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.
+
+#include <cassert>
+#include <cmath>
+#include <cstdlib>
+#include <stdexcept>
+
+#include <jsi/instrumentation.h>
+#include <jsi/jsi.h>
+
+namespace facebook {
+namespace jsi {
+
+namespace detail {
+
+void throwJSError(Runtime& rt, const char* msg) {
+ throw JSError(rt, msg);
+}
+
+} // namespace detail
+
+Buffer::~Buffer() {}
+
+Value HostObject::get(Runtime&, const PropNameID&) {
+ return Value();
+}
+
+void HostObject::set(Runtime& rt, const PropNameID& name, const Value&) {
+ std::string msg("TypeError: Cannot assign to property '");
+ msg += name.utf8(rt);
+ msg += "' on HostObject with default setter";
+ throw JSError(rt, msg);
+}
+
+HostObject::~HostObject() {}
+
+Runtime::~Runtime() {}
+
+Instrumentation& Runtime::instrumentation() {
+ class NoInstrumentation : public Instrumentation {
+ std::string getRecordedGCStats() override {
+ return "";
+ }
+
+ Value getHeapInfo(bool) override {
+ return Value::undefined();
+ }
+
+ void collectGarbage() override {}
+
+ bool createSnapshotToFile(const std::string&, bool) override {
+ return false;
+ }
+
+ void writeBridgeTrafficTraceToFile(const std::string&) const override {
+ std::abort();
+ }
+
+ void writeBasicBlockProfileTraceToFile(const std::string&) const override {
+ std::abort();
+ }
+
+ void enableSamplingProfiler() const override {
+ std::abort();
+ }
+
+ void dumpSampledTraceToFile(const std::string&) const override {
+ std::abort();
+ }
+
+ void dumpProfilerSymbolsToFile(const std::string&) const override {
+ std::abort();
+ }
+ };
+
+ static NoInstrumentation sharedInstance;
+ return sharedInstance;
+}
+
+Pointer& Pointer::operator=(Pointer&& other) {
+ if (ptr_) {
+ ptr_->invalidate();
+ }
+ ptr_ = other.ptr_;
+ other.ptr_ = nullptr;
+ return *this;
+}
+
+Object Object::getPropertyAsObject(Runtime& runtime, const char* name) const {
+ Value v = getProperty(runtime, name);
+
+ if (!v.isObject()) {
+ throw JSError(
+ runtime,
+ std::string("getPropertyAsObject: property '") + name +
+ "' is not an Object");
+ }
+
+ return v.getObject(runtime);
+}
+
+Function Object::getPropertyAsFunction(Runtime& runtime, const char* name)
+ const {
+ Object obj = getPropertyAsObject(runtime, name);
+ if (!obj.isFunction(runtime)) {
+ throw JSError(
+ runtime,
+ std::string("getPropertyAsFunction: property '") + name +
+ "' is not a Function");
+ };
+
+ Runtime::PointerValue* value = obj.ptr_;
+ obj.ptr_ = nullptr;
+ return Function(value);
+}
+
+Array Object::asArray(Runtime& runtime) const& {
+ if (!isArray(runtime)) {
+ throw JSError(runtime, "Object is not an array");
+ }
+ return getArray(runtime);
+}
+
+Array Object::asArray(Runtime& runtime) && {
+ if (!isArray(runtime)) {
+ throw JSError(runtime, "Object is not an array");
+ }
+ return std::move(*this).getArray(runtime);
+}
+
+Function Object::asFunction(Runtime& runtime) const& {
+ if (!isFunction(runtime)) {
+ throw JSError(runtime, "Object is not a function");
+ }
+ return getFunction(runtime);
+}
+
+Function Object::asFunction(Runtime& runtime) && {
+ if (!isFunction(runtime)) {
+ throw JSError(runtime, "Object is not a function");
+ }
+ return std::move(*this).getFunction(runtime);
+}
+
+Value::Value(Value&& other) : Value(other.kind_) {
+ if (kind_ == BooleanKind) {
+ data_.boolean = other.data_.boolean;
+ } else if (kind_ == NumberKind) {
+ data_.number = other.data_.number;
+ } else if (kind_ >= PointerKind) {
+ new (&data_.pointer) Pointer(std::move(other.data_.pointer));
+ }
+ // when the other's dtor runs, nothing will happen.
+ other.kind_ = UndefinedKind;
+}
+
+Value::Value(Runtime& runtime, const Value& other) : Value(other.kind_) {
+ // data_ is uninitialized, so use placement new to create non-POD
+ // types in it. Any other kind of initialization will call a dtor
+ // first, which is incorrect.
+ if (kind_ == BooleanKind) {
+ data_.boolean = other.data_.boolean;
+ } else if (kind_ == NumberKind) {
+ data_.number = other.data_.number;
+ } else if (kind_ == StringKind) {
+ new (&data_.pointer) Pointer(runtime.cloneString(other.data_.pointer.ptr_));
+ } else if (kind_ >= ObjectKind) {
+ new (&data_.pointer) Pointer(runtime.cloneObject(other.data_.pointer.ptr_));
+ }
+}
+
+Value::~Value() {
+ if (kind_ >= PointerKind) {
+ data_.pointer.~Pointer();
+ }
+}
+
+Value Value::createFromJsonUtf8(
+ Runtime& runtime,
+ const uint8_t* json,
+ size_t length) {
+ Function parseJson = runtime.global()
+ .getPropertyAsObject(runtime, "JSON")
+ .getPropertyAsFunction(runtime, "parse");
+ return parseJson.call(runtime, String::createFromUtf8(runtime, json, length));
+}
+
+bool Value::strictEquals(Runtime& runtime, const Value& a, const Value& b) {
+ if (a.kind_ != b.kind_) {
+ return false;
+ }
+ switch (a.kind_) {
+ case UndefinedKind:
+ case NullKind:
+ return true;
+ case BooleanKind:
+ return a.data_.boolean == b.data_.boolean;
+ case NumberKind:
+ return a.data_.number == b.data_.number;
+ case StringKind:
+ return runtime.strictEquals(
+ static_cast<const String&>(a.data_.pointer),
+ static_cast<const String&>(b.data_.pointer));
+ case ObjectKind:
+ return runtime.strictEquals(
+ static_cast<const Object&>(a.data_.pointer),
+ static_cast<const Object&>(b.data_.pointer));
+ }
+ return false;
+}
+
+double Value::asNumber() const {
+ if (!isNumber()) {
+ throw JSINativeException("Value is not an Object");
+ }
+
+ return getNumber();
+}
+
+Object Value::asObject(Runtime& runtime) const& {
+ if (!isObject()) {
+ throw JSError(runtime, "Value is not an Object");
+ }
+
+ return getObject(runtime);
+}
+
+Object Value::asObject(Runtime& rt) && {
+ if (!isObject()) {
+ throw JSError(rt, "Value is not an Object");
+ }
+ auto ptr = data_.pointer.ptr_;
+ data_.pointer.ptr_ = nullptr;
+ return static_cast<Object>(ptr);
+}
+
+String Value::asString(Runtime& rt) const& {
+ if (!isString()) {
+ throw JSError(rt, "Value is not a String");
+ }
+
+ return getString(rt);
+}
+
+String Value::asString(Runtime& rt) && {
+ if (!isString()) {
+ throw JSError(rt, "Value is not a String");
+ }
+
+ return std::move(*this).getString(rt);
+}
+
+String Value::toString(Runtime& runtime) const {
+ Function toString = runtime.global().getPropertyAsFunction(runtime, "String");
+ return toString.call(runtime, *this).getString(runtime);
+}
+
+Array Array::createWithElements(
+ Runtime& rt,
+ std::initializer_list<Value> elements) {
+ Array result(rt, elements.size());
+ size_t index = 0;
+ for (const auto& element : elements) {
+ result.setValueAtIndex(rt, index++, element);
+ }
+ return result;
+}
+
+std::vector<PropNameID> HostObject::getPropertyNames(Runtime&) {
+ return {};
+}
+
+Runtime::ScopeState* Runtime::pushScope() {
+ return nullptr;
+}
+
+void Runtime::popScope(ScopeState*) {}
+
+JSError::JSError(Runtime& rt, Value&& value) {
+ setValue(rt, std::move(value));
+}
+
+JSError::JSError(Runtime& rt, std::string msg) : message_(std::move(msg)) {
+ try {
+ setValue(
+ rt, rt.global().getPropertyAsFunction(rt, "Error").call(rt, message_));
+ } catch (...) {
+ setValue(rt, Value());
+ }
+}
+
+JSError::JSError(Runtime& rt, std::string msg, std::string stack)
+ : message_(std::move(msg)), stack_(std::move(stack)) {
+ try {
+ Object e(rt);
+ e.setProperty(rt, "message", String::createFromUtf8(rt, message_));
+ e.setProperty(rt, "stack", String::createFromUtf8(rt, stack_));
+ setValue(rt, std::move(e));
+ } catch (...) {
+ setValue(rt, Value());
+ }
+}
+
+JSError::JSError(std::string what, Runtime& rt, Value&& value)
+ : JSIException(std::move(what)) {
+ setValue(rt, std::move(value));
+}
+
+void JSError::setValue(Runtime& rt, Value&& value) {
+ value_ = std::make_shared<jsi::Value>(std::move(value));
+
+ try {
+ if ((message_.empty() || stack_.empty()) && value_->isObject()) {
+ auto obj = value_->getObject(rt);
+
+ if (message_.empty()) {
+ jsi::Value message = obj.getProperty(rt, "message");
+ if (!message.isUndefined()) {
+ message_ = message.toString(rt).utf8(rt);
+ }
+ }
+
+ if (stack_.empty()) {
+ jsi::Value stack = obj.getProperty(rt, "stack");
+ if (!stack.isUndefined()) {
+ stack_ = stack.toString(rt).utf8(rt);
+ }
+ }
+ }
+
+ if (message_.empty()) {
+ message_ = value_->toString(rt).utf8(rt);
+ }
+
+ if (stack_.empty()) {
+ stack_ = "no stack";
+ }
+
+ if (what_.empty()) {
+ what_ = message_ + "\n\n" + stack_;
+ }
+ } catch (...) {
+ message_ = "[Exception caught creating message string]";
+ stack_ = "[Exception caught creating stack string]";
+ what_ = "[Exception caught getting value fields]";
+ }
+}
+
+} // namespace jsi
+} // namespace facebook

ReactCommon/jsi/JSIDynamic.cpp

@@ -0,0 +1,96 @@
+// 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.
+
+#include "JSIDynamic.h"
+
+#include <folly/dynamic.h>
+#include <jsi/jsi.h>
+
+using namespace facebook::jsi;
+
+namespace facebook {
+namespace jsi {
+
+Value valueFromDynamic(Runtime& runtime, const folly::dynamic& dyn) {
+ switch (dyn.type()) {
+ case folly::dynamic::NULLT:
+ return Value::null();
+ case folly::dynamic::ARRAY: {
+ Array ret = Array(runtime, dyn.size());
+ for (size_t i = 0; i < dyn.size(); ++i) {
+ ret.setValueAtIndex(runtime, i, valueFromDynamic(runtime, dyn[i]));
+ }
+ return std::move(ret);
+ }
+ case folly::dynamic::BOOL:
+ return dyn.getBool();
+ case folly::dynamic::DOUBLE:
+ return dyn.getDouble();
+ case folly::dynamic::INT64:
+ // Can't use asDouble() here. If the int64 value is too bit to be
+ // represented precisely as a double, folly will throw an
+ // exception.
+ return (double)dyn.getInt();
+ case folly::dynamic::OBJECT: {
+ Object ret(runtime);
+ for (const auto& element : dyn.items()) {
+ Value value = valueFromDynamic(runtime, element.second);
+ if (element.first.isNumber() || element.first.isString()) {
+ ret.setProperty(runtime, element.first.asString().c_str(), value);
+ }
+ }
+ return std::move(ret);
+ }
+ case folly::dynamic::STRING:
+ return String::createFromUtf8(runtime, dyn.getString());
+ }
+ CHECK(false);
+}
+
+folly::dynamic dynamicFromValue(Runtime& runtime, const Value& value) {
+ if (value.isUndefined() || value.isNull()) {
+ return nullptr;
+ } else if (value.isBool()) {
+ return value.getBool();
+ } else if (value.isNumber()) {
+ return value.getNumber();
+ } else if (value.isString()) {
+ return value.getString(runtime).utf8(runtime);
+ } else {
+ Object obj = value.getObject(runtime);
+ if (obj.isArray(runtime)) {
+ Array array = obj.getArray(runtime);
+ folly::dynamic ret = folly::dynamic::array();
+ for (size_t i = 0; i < array.size(runtime); ++i) {
+ ret.push_back(dynamicFromValue(runtime, array.getValueAtIndex(runtime, i)));
+ }
+ return ret;
+ } else if (obj.isFunction(runtime)) {
+ throw JSError(runtime, "JS Functions are not convertible to dynamic");
+ } else {
+ folly::dynamic ret = folly::dynamic::object();
+ Array names = obj.getPropertyNames(runtime);
+ for (size_t i = 0; i < names.size(runtime); ++i) {
+ String name = names.getValueAtIndex(runtime, i).getString(runtime);
+ Value prop = obj.getProperty(runtime, name);
+ if (prop.isUndefined()) {
+ continue;
+ }
+ // The JSC conversion uses JSON.stringify, which substitutes
+ // null for a function, so we do the same here. Just dropping
+ // the pair might also work, but would require more testing.
+ if (prop.isObject() && prop.getObject(runtime).isFunction(runtime)) {
+ prop = Value::null();
+ }
+ ret.insert(
+ name.utf8(runtime), dynamicFromValue(runtime, std::move(prop)));
+ }
+ return ret;
+ }
+ }
+}
+
+}
+}

ReactCommon/jsi/JSIDynamic.h

@@ -0,0 +1,21 @@
+// 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.
+
+#pragma once
+
+#include <folly/dynamic.h>
+#include <jsi/jsi.h>
+
+namespace facebook {
+namespace jsi {
+
+facebook::jsi::Value valueFromDynamic(
+ facebook::jsi::Runtime& runtime, const folly::dynamic& dyn);
+
+folly::dynamic dynamicFromValue(facebook::jsi::Runtime& runtime,
+ const facebook::jsi::Value& value);
+
+}
+}

ReactCommon/jsi/jsi.h

@@ -0,0 +1,1162 @@
+// 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.
+
+#pragma once
+
+#include <cassert>
+#include <cstring>
+#include <exception>
+#include <functional>
+#include <memory>
+#include <string>
+#include <vector>
+
+#ifndef JSI_EXPORT
+#ifdef _MSC_VER
+#define JSI_EXPORT
+#else
+#define JSI_EXPORT __attribute__((visibility("default")))
+#endif
+#endif
+
+class FBJSRuntime;
+namespace facebook {
+namespace jsi {
+
+namespace detail {
+
+template <typename R, typename L>
+class ThreadSafeRuntimeImpl;
+}
+
+class Buffer {
+ public:
+ virtual ~Buffer();
+ virtual size_t size() const = 0;
+ virtual const uint8_t* data() const = 0;
+};
+
+class StringBuffer : public Buffer {
+ public:
+ StringBuffer(std::string s) : s_(std::move(s)) {}
+ size_t size() const override {
+ return s_.size();
+ }
+ const uint8_t* data() const override {
+ return reinterpret_cast<const uint8_t*>(s_.data());
+ }
+
+ private:
+ std::string s_;
+};
+
+class Runtime;
+class Pointer;
+class PropNameID;
+class String;
+class Object;
+class WeakObject;
+class Array;
+class ArrayBuffer;
+class Function;
+class Value;
+class Instrumentation;
+class Scope;
+class JSIException;
+class JSError;
+
+/// A function which has this type can be registered as a function
+/// callable from JavaScript using Function::createFromHostFunction().
+/// When the function is called, args will point to the arguments, and
+/// count will indicate how many arguments are passed. The function
+/// can return a Value to the caller, or throw an exception. If a C++
+/// exception is thrown, a JS Error will be created and thrown into
+/// JS; if the C++ exception extends std::exception, the Error's
+/// message will be whatever what() returns. Note that it is undefined whether
+/// HostFunctions may or may not be called in strict mode; that is `thisVal`
+/// can be any value - it will not necessarily be coerced to an object or
+/// or set to the global object.
+using HostFunctionType = std::function<
+ Value(Runtime& rt, const Value& thisVal, const Value* args, size_t count)>;
+
+/// An object which implements this interface can be registered as an
+/// Object with the JS runtime.
+class JSI_EXPORT HostObject {
+ public:
+ // The C++ object's dtor will be called when the GC finalizes this
+ // object. (This may be as late as when the Runtime is shut down.)
+ // You have no control over which thread it is called on. This will
+ // be called from inside the GC, so it is unsafe to do any VM
+ // operations which require a Runtime&. Derived classes' dtors
+ // should also avoid doing anything expensive. Calling the dtor on
+ // a jsi object is explicitly ok. If you want to do JS operations,
+ // or any nontrivial work, you should add it to a work queue, and
+ // manage it externally.
+ virtual ~HostObject();
+
+ // When JS wants a property with a given name from the HostObject,
+ // it will call this method. If it throws an exception, the call
+ // will throw a JS \c Error object. By default this returns undefined.
+ // \return the value for the property.
+ virtual Value get(Runtime&, const PropNameID& name);
+
+ // When JS wants to set a property with a given name on the HostObject,
+ // it will call this method. If it throws an exception, the call will
+ // throw a JS \c Error object. By default this throws a type error exception
+ // mimicking the behavior of a frozen object in strict mode.
+ virtual void set(Runtime&, const PropNameID& name, const Value& value);
+
+ // When JS wants a list of property names for the HostObject, it will
+ // call this method. If it throws an exception, the call will thow a
+ // JS \c Error object. The default implementation returns empty vector.
+ virtual std::vector<PropNameID> getPropertyNames(Runtime& rt);
+};
+
+/// Represents a JS runtime. Movable, but not copyable. Note that
+/// this object may not be thread-aware, but cannot be used safely from
+/// multiple threads at once. The application is responsible for
+/// ensuring that it is used safely. This could mean using the
+/// Runtime from a single thread, using a mutex, doing all work on a
+/// serial queue, etc. This restriction applies to the methods of
+/// this class, and any method in the API which take a Runtime& as an
+/// argument. Destructors (all but ~Scope), operators, or other methods
+/// which do not take Runtime& as an argument are safe to call from any
+/// thread, but it is still forbidden to make write operations on a single
+/// instance of any class from more than one thread. In addition, to
+/// make shutdown safe, destruction of objects associated with the Runtime
+/// must be destroyed before the Runtime is destroyed, or from the
+/// destructor of a managed HostObject or HostFunction. Informally, this
+/// means that the main source of unsafe behavior is to hold a jsi object
+/// in a non-Runtime-managed object, and not clean it up before the Runtime
+/// is shut down. If your lifecycle is such that avoiding this is hard,
+/// you will probably need to do use your own locks.
+class Runtime {
+ public:
+ virtual ~Runtime();
+
+ /// Evaluates the given JavaScript \c buffer. \c sourceURL is used
+ /// to annotate the stack trace if there is an exception. The
+ /// contents may be utf8-encoded JS source code, or binary bytcode
+ /// whose format is specific to the implementation. If the input
+ /// format is unknown, or evaluation causes an error, a JSIException
+ /// will be thrown.
+ virtual void evaluateJavaScript(
+ std::unique_ptr<const Buffer> buffer,
+ const std::string& sourceURL) = 0;
+ /// \return the global object
+ virtual Object global() = 0;
+
+ /// \return a short printable description of the instance. This
+ /// should only be used by logging, debugging, and other
+ /// developer-facing callers.
+ virtual std::string description() = 0;
+
+ /// \return whether or not the underlying runtime supports debugging via the
+ /// Chrome remote debugging protocol.
+ ///
+ /// NOTE: the API for determining whether a runtime is debuggable and
+ /// registering a runtime with the debugger is still in flux, so please don't
+ /// use this API unless you know what you're doing.
+ virtual bool isInspectable() = 0;
+
+ /// \return an interface to extract metrics from this \c Runtime. The default
+ /// implementation of this function returns an \c Instrumentation instance
+ /// which returns no metrics.
+ virtual Instrumentation& instrumentation();
+
+ protected:
+ friend class Pointer;
+ friend class PropNameID;
+ friend class String;
+ friend class Object;
+ friend class WeakObject;
+ friend class Array;
+ friend class ArrayBuffer;
+ friend class Function;
+ friend class Value;
+ friend class Scope;
+ friend class JSError;
+
+ // Potential optimization: avoid the cloneFoo() virtual dispatch,
+ // and instead just fix the number of fields, and copy them, since
+ // in practice they are trivially copyable. Sufficient use of
+ // rvalue arguments/methods would also reduce the number of clones.
+
+ struct PointerValue {
+ virtual void invalidate() = 0;
+
+ protected:
+ ~PointerValue() = default;
+ };
+
+ virtual PointerValue* cloneString(const Runtime::PointerValue* pv) = 0;
+ virtual PointerValue* cloneObject(const Runtime::PointerValue* pv) = 0;
+ virtual PointerValue* clonePropNameID(const Runtime::PointerValue* pv) = 0;
+
+ virtual PropNameID createPropNameIDFromAscii(
+ const char* str,
+ size_t length) = 0;
+ virtual PropNameID createPropNameIDFromUtf8(
+ const uint8_t* utf8,
+ size_t length) = 0;
+ virtual PropNameID createPropNameIDFromString(const String& str) = 0;
+ virtual std::string utf8(const PropNameID&) = 0;
+ virtual bool compare(const PropNameID&, const PropNameID&) = 0;
+
+ virtual String createStringFromAscii(const char* str, size_t length) = 0;
+ virtual String createStringFromUtf8(const uint8_t* utf8, size_t length) = 0;
+ virtual std::string utf8(const String&) = 0;
+
+ virtual Object createObject() = 0;
+ virtual Object createObject(std::shared_ptr<HostObject> ho) = 0;
+ virtual std::shared_ptr<HostObject> getHostObject(const jsi::Object&) = 0;
+ virtual HostFunctionType& getHostFunction(const jsi::Function&) = 0;
+
+ virtual Value getProperty(const Object&, const PropNameID& name) = 0;
+ virtual Value getProperty(const Object&, const String& name) = 0;
+ virtual bool hasProperty(const Object&, const PropNameID& name) = 0;
+ virtual bool hasProperty(const Object&, const String& name) = 0;
+ virtual void
+ setPropertyValue(Object&, const PropNameID& name, const Value& value) = 0;
+ virtual void
+ setPropertyValue(Object&, const String& name, const Value& value) = 0;
+
+ virtual bool isArray(const Object&) const = 0;
+ virtual bool isArrayBuffer(const Object&) const = 0;
+ virtual bool isFunction(const Object&) const = 0;
+ virtual bool isHostObject(const jsi::Object&) const = 0;
+ virtual bool isHostFunction(const jsi::Function&) const = 0;
+ virtual Array getPropertyNames(const Object&) = 0;
+
+ virtual WeakObject createWeakObject(const Object&) = 0;
+ virtual Value lockWeakObject(const WeakObject&) = 0;
+
+ virtual Array createArray(size_t length) = 0;
+ virtual size_t size(const Array&) = 0;
+ virtual size_t size(const ArrayBuffer&) = 0;
+ virtual uint8_t* data(const ArrayBuffer&) = 0;
+ virtual Value getValueAtIndex(const Array&, size_t i) = 0;
+ virtual void setValueAtIndexImpl(Array&, size_t i, const Value& value) = 0;
+
+ virtual Function createFunctionFromHostFunction(
+ const PropNameID& name,
+ unsigned int paramCount,
+ HostFunctionType func) = 0;
+ virtual Value call(
+ const Function&,
+ const Value& jsThis,
+ const Value* args,
+ size_t count) = 0;
+ virtual Value
+ callAsConstructor(const Function&, const Value* args, size_t count) = 0;
+
+ // Private data for managing scopes.
+ struct ScopeState;
+ virtual ScopeState* pushScope();
+ virtual void popScope(ScopeState*);
+
+ virtual bool strictEquals(const String& a, const String& b) const = 0;
+ virtual bool strictEquals(const Object& a, const Object& b) const = 0;
+
+ virtual bool instanceOf(const Object& o, const Function& f) = 0;
+
+ // These exist so derived classes can access the private parts of
+ // Value, String, and Object, which are all friends of Runtime.
+ template <typename T>
+ static T make(PointerValue* pv);
+ static const PointerValue* getPointerValue(const Pointer& pointer);
+ static const PointerValue* getPointerValue(const Value& value);
+
+ // TODO T25594389: think harder about this friend declaration (and
+ // it's forward decl above)
+ template <typename R, typename L>
+ friend class detail::ThreadSafeRuntimeImpl;
+ friend class ::FBJSRuntime;
+};
+
+// Base class for pointer-storing types.
+class Pointer {
+ protected:
+ explicit Pointer(Pointer&& other) : ptr_(other.ptr_) {
+ other.ptr_ = nullptr;
+ }
+
+ ~Pointer() {
+ if (ptr_) {
+ ptr_->invalidate();
+ }
+ }
+
+ Pointer& operator=(Pointer&& other);
+
+ friend class Runtime;
+ friend class Value;
+
+ explicit Pointer(Runtime::PointerValue* ptr) : ptr_(ptr) {}
+
+ typename Runtime::PointerValue* ptr_;
+};
+
+/// Represents something that can be a JS property key. Movable, not copyable.
+class PropNameID : public Pointer {
+ public:
+ using Pointer::Pointer;
+
+ PropNameID(Runtime &runtime, const PropNameID &other)
+ : Pointer(runtime.clonePropNameID(other.ptr_)) {}
+
+ PropNameID(PropNameID&& other) = default;
+ PropNameID& operator=(PropNameID&& other) = default;
+
+ /// Create a JS property name id from ascii values. The data is
+ /// copied.
+ static PropNameID forAscii(Runtime& runtime, const char* str, size_t length) {
+ return runtime.createPropNameIDFromAscii(str, length);
+ }
+
+ /// Create a property name id from a nul-terminated C ascii name. The data is
+ /// copied.
+ static PropNameID forAscii(Runtime& runtime, const char* str) {
+ return forAscii(runtime, str, strlen(str));
+ }
+
+ /// Create a PropNameID from a C++ string. The string is copied.
+ static PropNameID forAscii(Runtime& runtime, const std::string& str) {
+ return forAscii(runtime, str.c_str(), str.size());
+ }
+
+ /// Create a PropNameID from utf8 values. The data is copied.
+ static PropNameID
+ forUtf8(Runtime& runtime, const uint8_t* utf8, size_t length) {
+ return runtime.createPropNameIDFromUtf8(utf8, length);
+ }
+
+ /// Create a PropNameID from utf8-encoded octets stored in a
+ /// std::string. The string data is transformed and copied.
+ static PropNameID forUtf8(Runtime& runtime, const std::string& utf8) {
+ return runtime.createPropNameIDFromUtf8(
+ reinterpret_cast<const uint8_t*>(utf8.data()), utf8.size());
+ }
+
+ /// Create a PropNameID from a JS string.
+ static PropNameID forString(Runtime& runtime, const jsi::String& str) {
+ return runtime.createPropNameIDFromString(str);
+ }
+
+ // Creates a vector of PropNameIDs constructed from given arguments.
+ template <typename... Args>
+ static std::vector<PropNameID> names(Runtime& runtime, Args&&... args);
+
+ // Creates a vector of given PropNameIDs.
+ template <size_t N>
+ static std::vector<PropNameID> names(PropNameID(&&propertyNames)[N]);
+
+ /// Copies the data in a PropNameID as utf8 into a C++ string.
+ std::string utf8(Runtime& runtime) const {
+ return runtime.utf8(*this);
+ }
+
+ static bool compare(
+ Runtime& runtime,
+ const jsi::PropNameID& a,
+ const jsi::PropNameID& b) {
+ return runtime.compare(a, b);
+ }
+
+ friend class Runtime;
+ friend class Value;
+};
+
+/// Represents a JS String. Movable, not copyable.
+class String : public Pointer {
+ public:
+ using Pointer::Pointer;
+
+ String(String&& other) = default;
+ String& operator=(String&& other) = default;
+
+ /// Create a JS string from ascii values. The string data is
+ /// copied.
+ static String
+ createFromAscii(Runtime& runtime, const char* str, size_t length) {
+ return runtime.createStringFromAscii(str, length);
+ }
+
+ /// Create a JS string from a nul-terminated C ascii string. The
+ /// string data is copied.
+ static String createFromAscii(Runtime& runtime, const char* str) {
+ return createFromAscii(runtime, str, strlen(str));
+ }
+
+ /// Create a JS string from a C++ string. The string data is
+ /// copied.
+ static String createFromAscii(Runtime& runtime, const std::string& str) {
+ return createFromAscii(runtime, str.c_str(), str.size());
+ }
+
+ /// Create a JS string from utf8-encoded octets. The string data is
+ /// transformed and copied.
+ static String
+ createFromUtf8(Runtime& runtime, const uint8_t* utf8, size_t length) {
+ return runtime.createStringFromUtf8(utf8, length);
+ }
+
+ /// Create a JS string from utf8-encoded octets stored in a
+ /// std::string. The string data is transformed and copied.
+ static String createFromUtf8(Runtime& runtime, const std::string& utf8) {
+ return runtime.createStringFromUtf8(
+ reinterpret_cast<const uint8_t*>(utf8.data()), utf8.length());
+ }
+
+ /// \return whether a and b contain the same characters.
+ static bool strictEquals(Runtime& runtime, const String& a, const String& b) {
+ return runtime.strictEquals(a, b);
+ }
+
+ /// Copies the data in a JS string as utf8 into a C++ string.
+ std::string utf8(Runtime& runtime) const {
+ return runtime.utf8(*this);
+ }
+
+ friend class Runtime;
+ friend class Value;
+};
+
+class Array;
+class Function;
+
+/// Represents a JS Object. Movable, not copyable.
+class Object : public Pointer {
+ public:
+ using Pointer::Pointer;
+
+ Object(Object&& other) = default;
+ Object& operator=(Object&& other) = default;
+
+ /// Creates a new Object instance, like '{}' in JS.
+ Object(Runtime& runtime) : Object(runtime.createObject()) {}
+
+ static Object createFromHostObject(
+ Runtime& runtime,
+ std::shared_ptr<HostObject> ho) {
+ return runtime.createObject(ho);
+ }
+
+ /// \return whether this and \c obj are the same JSObject or not.
+ static bool strictEquals(Runtime& runtime, const Object& a, const Object& b) {
+ return runtime.strictEquals(a, b);
+ }
+
+ /// \return the result of `this instanceOf ctor` in JS.
+ bool instanceOf(Runtime& rt, const Function& ctor) {
+ return rt.instanceOf(*this, ctor);
+ }
+
+ /// \return the property of the object with the given ascii name.
+ /// If the name isn't a property on the object, returns the
+ /// undefined value.
+ Value getProperty(Runtime& runtime, const char* name) const;
+
+ /// \return the property of the object with the String name.
+ /// If the name isn't a property on the object, returns the
+ /// undefined value.
+ Value getProperty(Runtime& runtime, const String& name) const;
+
+ /// \return the property of the object with the given JS PropNameID
+ /// name. If the name isn't a property on the object, returns the
+ /// undefined value.
+ Value getProperty(Runtime& runtime, const PropNameID& name) const;
+
+ /// \return true if and only if the object has a property with the
+ /// given ascii name.
+ bool hasProperty(Runtime& runtime, const char* name) const;
+
+ /// \return true if and only if the object has a property with the
+ /// given String name.
+ bool hasProperty(Runtime& runtime, const String& name) const;
+
+ /// \return true if and only if the object has a property with the
+ /// given PropNameID name.
+ bool hasProperty(Runtime& runtime, const PropNameID& name) const;
+
+ /// Sets the property value from a Value or anything which can be
+ /// used to make one: nullptr_t, bool, double, int, const char*,
+ /// String, or Object.
+ template <typename T>
+ void setProperty(Runtime& runtime, const char* name, T&& value);
+
+ /// Sets the property value from a Value or anything which can be
+ /// used to make one: nullptr_t, bool, double, int, const char*,
+ /// String, or Object.
+ template <typename T>
+ void setProperty(Runtime& runtime, const String& name, T&& value);
+
+ /// Sets the property value from a Value or anything which can be
+ /// used to make one: nullptr_t, bool, double, int, const char*,
+ /// String, or Object.
+ template <typename T>
+ void setProperty(Runtime& runtime, const PropNameID& name, T&& value);
+
+ /// \return true iff JS \c Array.isArray() would return \c true. If
+ /// so, then \c getArray() will succeed.
+ bool isArray(Runtime& runtime) const {
+ return runtime.isArray(*this);
+ }
+
+ /// \return true iff the Object is an ArrayBuffer. If so, then \c
+ /// getArrayBuffer() will succeed.
+ bool isArrayBuffer(Runtime& runtime) const {
+ return runtime.isArrayBuffer(*this);
+ }
+
+ /// \return true iff the Object is callable. If so, then \c
+ /// getFunction will succeed.
+ bool isFunction(Runtime& runtime) const {
+ return runtime.isFunction(*this);
+ }
+
+ /// \return true iff the Object was initialized with \c createFromHostObject
+ /// and the HostObject passed is of type \c T. If returns \c true then
+ /// \c getHostObject<T> will succeed.
+ template <typename T = HostObject>
+ bool isHostObject(Runtime& runtime) const;
+
+ /// \return an Array instance which refers to the same underlying
+ /// object. If \c isArray() would return false, this will assert.
+ Array getArray(Runtime& runtime) const&;
+
+ /// \return an Array instance which refers to the same underlying
+ /// object. If \c isArray() would return false, this will assert.
+ Array getArray(Runtime& runtime) &&;
+
+ /// \return an Array instance which refers to the same underlying
+ /// object. If \c isArray() would return false, this will throw
+ /// JSIException.
+ Array asArray(Runtime& runtime) const&;
+
+ /// \return an Array instance which refers to the same underlying
+ /// object. If \c isArray() would return false, this will throw
+ /// JSIException.
+ Array asArray(Runtime& runtime) &&;
+
+ /// \return an ArrayBuffer instance which refers to the same underlying
+ /// object. If \c isArrayBuffer() would return false, this will assert.
+ ArrayBuffer getArrayBuffer(Runtime& runtime) const&;
+
+ /// \return an ArrayBuffer instance which refers to the same underlying
+ /// object. If \c isArrayBuffer() would return false, this will assert.
+ ArrayBuffer getArrayBuffer(Runtime& runtime) &&;
+
+ /// \return a Function instance which refers to the same underlying
+ /// object. If \c isFunction() would return false, this will assert.
+ Function getFunction(Runtime& runtime) const&;
+
+ /// \return a Function instance which refers to the same underlying
+ /// object. If \c isFunction() would return false, this will assert.
+ Function getFunction(Runtime& runtime) &&;
+
+ /// \return a Function instance which refers to the same underlying
+ /// object. If \c isFunction() would return false, this will throw
+ /// JSIException.
+ Function asFunction(Runtime& runtime) const&;
+
+ /// \return a Function instance which refers to the same underlying
+ /// object. If \c isFunction() would return false, this will throw
+ /// JSIException.
+ Function asFunction(Runtime& runtime) &&;
+
+ /// \return a shared_ptr<T> which refers to the same underlying
+ /// \c HostObject that was used to create this object. If \c isHostObject<T>
+ /// is false, this will assert. Note that this does a type check and will
+ /// assert if the underlying HostObject isn't of type \c T
+ template <typename T = HostObject>
+ std::shared_ptr<T> getHostObject(Runtime& runtime) const;
+
+ /// \return a shared_ptr<T> which refers to the same underlying
+ /// \c HostObject that was used to crete this object. If \c isHostObject<T>
+ /// is false, this will throw.
+ template <typename T = HostObject>
+ std::shared_ptr<T> asHostObject(Runtime& runtime) const;
+
+ /// \return same as \c getProperty(name).asObject(), except with
+ /// a better exception message.
+ Object getPropertyAsObject(Runtime& runtime, const char* name) const;
+
+ /// \return similar to \c
+ /// getProperty(name).getObject().getFunction(), except it will
+ /// throw JSIException instead of asserting if the property is
+ /// not an object, or the object is not callable.
+ Function getPropertyAsFunction(Runtime& runtime, const char* name) const;
+
+ /// \return an Array consisting of all enumerable property names in
+ /// the object and its prototype chain. All values in the return
+ /// will be isString(). (This is probably not optimal, but it
+ /// works. I only need it in one place.)
+ Array getPropertyNames(Runtime& runtime) const;
+
+ protected:
+ void
+ setPropertyValue(Runtime& runtime, const String& name, const Value& value) {
+ return runtime.setPropertyValue(*this, name, value);
+ }
+
+ void setPropertyValue(
+ Runtime& runtime,
+ const PropNameID& name,
+ const Value& value) {
+ return runtime.setPropertyValue(*this, name, value);
+ }
+
+ friend class Runtime;
+ friend class Value;
+};
+
+/// Represents a weak reference to a JS Object. If the only reference
+/// to an Object are these, the object is eligible for GC. Method
+/// names are inspired by C++ weak_ptr. Movable, not copyable.
+class WeakObject : public Pointer {
+ public:
+ using Pointer::Pointer;
+
+ WeakObject(WeakObject&& other) = default;
+ WeakObject& operator=(WeakObject&& other) = default;
+
+ /// Create a WeakObject from an Object.
+ WeakObject(Runtime& runtime, const Object& o)
+ : WeakObject(runtime.createWeakObject(o)) {}
+
+ /// \return a Value representing the underlying Object if it is still valid;
+ /// otherwise returns \c undefined. Note that this method has nothing to do
+ /// with threads or concurrency. The name is based on std::weak_ptr::lock()
+ /// which serves a similar purpose.
+ Value lock(Runtime& runtime);
+
+ friend class Runtime;
+};
+
+/// Represents a JS Object which can be efficiently used as an array
+/// with integral indices.
+class Array : public Object {
+ public:
+ Array(Array&&) = default;
+ /// Creates a new Array instance, with \c length undefined elements.
+ Array(Runtime& runtime, size_t length) : Array(runtime.createArray(length)) {}
+
+ Array& operator=(Array&&) = default;
+
+ /// \return the size of the Array, according to its length property.
+ /// (C++ naming convention)
+ size_t size(Runtime& runtime) const {
+ return runtime.size(*this);
+ }
+
+ /// \return the size of the Array, according to its length property.
+ /// (JS naming convention)
+ size_t length(Runtime& runtime) const {
+ return size(runtime);
+ }
+
+ /// \return the property of the array at index \c i. If there is no
+ /// such property, returns the undefined value. If \c i is out of
+ /// range [ 0..\c length ] throws a JSIException.
+ Value getValueAtIndex(Runtime& runtime, size_t i) const;
+
+ /// Sets the property of the array at index \c i. The argument
+ /// value behaves as with Object::setProperty(). If \c i is out of
+ /// range [ 0..\c length ] throws a JSIException.
+ template <typename T>
+ void setValueAtIndex(Runtime& runtime, size_t i, T&& value);
+
+ /// There is no current API for changing the size of an array once
+ /// created. We'll probably need that eventually.
+
+ /// Creates a new Array instance from provided values
+ template <typename... Args>
+ static Array createWithElements(Runtime&, Args&&... args);
+
+ /// Creates a new Array instance from intitializer list.
+ static Array createWithElements(
+ Runtime& runtime,
+ std::initializer_list<Value> elements);
+
+ private:
+ friend class Object;
+ friend class Value;
+
+ void setValueAtIndexImpl(Runtime& runtime, size_t i, const Value& value) {
+ return runtime.setValueAtIndexImpl(*this, i, value);
+ }
+
+ Array(Runtime::PointerValue* value) : Object(value) {}
+};
+
+/// Represents a JSArrayBuffer
+class ArrayBuffer : public Object {
+ public:
+ ArrayBuffer(ArrayBuffer&&) = default;
+ ArrayBuffer& operator=(ArrayBuffer&&) = default;
+
+ /// \return the size of the ArrayBuffer, according to its byteLength property.
+ /// (C++ naming convention)
+ size_t size(Runtime& runtime) const {
+ return runtime.size(*this);
+ }
+
+ size_t length(Runtime& runtime) const {
+ return runtime.size(*this);
+ }
+
+ uint8_t* data(Runtime& runtime) {
+ return runtime.data(*this);
+ }
+
+ private:
+ friend class Object;
+ friend class Value;
+
+ ArrayBuffer(Runtime::PointerValue* value) : Object(value) {}
+};
+
+/// Represents a JS Object which is guaranteed to be Callable.
+class Function : public Object {
+ public:
+ Function(Function&&) = default;
+ Function& operator=(Function&&) = default;
+
+ /// Create a function which, when invoked, calls C++ code. If the
+ /// function throws an exception, a JS Error will be created and
+ /// thrown.
+ /// \param name the name property for the function.
+ /// \param paramCount the length property for the function, which
+ /// may not be the number of arguments the function is passed.
+ static Function createFromHostFunction(
+ Runtime& runtime,
+ const jsi::PropNameID& name,
+ unsigned int paramCount,
+ jsi::HostFunctionType func);
+
+ /// Calls the function with \c count \c args. The \c this value of
+ /// the JS function will be undefined.
+ Value call(Runtime& runtime, const Value* args, size_t count) const;
+
+ /// Calls the function with a \c std::initializer_list of Value
+ /// arguments. The \c this value of the JS function will be
+ /// undefined.
+ Value call(Runtime& runtime, std::initializer_list<Value> args) const;
+
+ /// Calls the function with any number of arguments similarly to
+ /// Object::setProperty(). The \c this value of the JS function
+ /// will be undefined.
+ template <typename... Args>
+ Value call(Runtime& runtime, Args&&... args) const;
+
+ /// Calls the function with \c count \c args and \c jsThis value passed
+ /// as this value.
+ Value callWithThis(
+ Runtime& Runtime,
+ const Object& jsThis,
+ const Value* args,
+ size_t count) const;
+
+ /// Calls the function with a \c std::initializer_list of Value
+ /// arguments. The \c this value of the JS function will be
+ /// undefined.
+ Value callWithThis(
+ Runtime& runtime,
+ const Object& jsThis,
+ std::initializer_list<Value> args) const;
+
+ /// Calls the function with any number of arguments similarly to
+ /// Object::setProperty(). The \c this value of the JS function
+ /// will be undefined.
+ template <typename... Args>
+ Value callWithThis(Runtime& runtime, const Object& jsThis, Args&&... args)
+ const;
+
+ /// Calls the function as a constructor with \c count \c args. Equivalent
+ /// to calling `new Func` where `Func` is the js function reqresented by
+ /// this.
+ Value callAsConstructor(Runtime& runtime, const Value* args, size_t count)
+ const;
+
+ /// Same as above `callAsConstructor`, except use an initializer_list to
+ /// supply the arguments.
+ Value callAsConstructor(Runtime& runtime, std::initializer_list<Value> args)
+ const;
+
+ /// Same as above `callAsConstructor`, but automatically converts/wraps
+ /// any argument with a jsi Value.
+ template <typename... Args>
+ Value callAsConstructor(Runtime& runtime, Args&&... args) const;
+
+ /// Returns whether this was created with Function::createFromHostFunction.
+ /// If true then you can use getHostFunction to get the underlying
+ /// HostFunctionType.
+ bool isHostFunction(Runtime& runtime) const {
+ return runtime.isHostFunction(*this);
+ }
+
+ /// Returns the underlying HostFunctionType iff isHostFunction returns true
+ /// and asserts otherwise. You can use this to use std::function<>::target
+ /// to get the object that was passed to create the HostFunctionType.
+ ///
+ /// Note: The reference returned is borrowed from the JS object underlying
+ /// \c this, and thus only lasts as long as the object underlying
+ /// \c this does.
+ HostFunctionType& getHostFunction(Runtime& runtime) const {
+ assert(isHostFunction(runtime));
+ return runtime.getHostFunction(*this);
+ }
+
+ private:
+ friend class Object;
+ friend class Value;
+
+ Function(Runtime::PointerValue* value) : Object(value) {}
+};
+
+/// Represents any JS Value (undefined, null, boolean, number, string,
+/// or object). Movable, or explicitly copyable (has no copy ctor).
+class Value {
+ public:
+ /// Default ctor creates an \c undefined JS value.
+ Value() : Value(UndefinedKind) {}
+
+ /// Creates a \c null JS value.
+ /* implicit */ Value(std::nullptr_t) : kind_(NullKind) {}
+
+ /// Creates a boolean JS value.
+ /* implicit */ Value(bool b) : Value(BooleanKind) {
+ data_.boolean = b;
+ }
+
+ /// Creates a number JS value.
+ /* implicit */ Value(double d) : Value(NumberKind) {
+ data_.number = d;
+ }
+
+ /// Creates a number JS value.
+ /* implicit */ Value(int i) : Value(NumberKind) {
+ data_.number = i;
+ }
+
+ /// Moves a String or Object rvalue into a new JS value.
+ template <typename T>
+ /* implicit */ Value(T&& other) : Value(kindOf(other)) {
+ static_assert(
+ std::is_base_of<String, T>::value || std::is_base_of<Object, T>::value,
+ "Value cannot be implictly move-constructed from this type");
+ new (&data_.pointer) T(std::move(other));
+ }
+
+ /// Value("foo") will treat foo as a bool. This makes doing that a
+ /// compile error.
+ template <typename T = void>
+ Value(const char*) {
+ static_assert(
+ !std::is_same<void, T>::value,
+ "Value cannot be constructed directly from const char*");
+ }
+
+ Value(Value&& value);
+
+ /// Copies a String lvalue into a new JS value.
+ Value(Runtime& runtime, const String& str) : Value(StringKind) {
+ new (&data_.pointer) String(runtime.cloneString(str.ptr_));
+ }
+
+ /// Copies a Object lvalue into a new JS value.
+ Value(Runtime& runtime, const Object& obj) : Value(ObjectKind) {
+ new (&data_.pointer) Object(runtime.cloneObject(obj.ptr_));
+ }
+
+ /// Creates a JS value from another Value lvalue.
+ Value(Runtime& runtime, const Value& value);
+
+ /// Value(rt, "foo") will treat foo as a bool. This makes doing
+ /// that a compile error.
+ template <typename T = void>
+ Value(Runtime&, const char*) {
+ static_assert(
+ !std::is_same<T, void>::value,
+ "Value cannot be constructed directly from const char*");
+ }
+
+ ~Value();
+ // \return the undefined \c Value.
+ static Value undefined() {
+ return Value();
+ }
+
+ // \return the null \c Value.
+ static Value null() {
+ return Value(nullptr);
+ }
+
+ // \return a \c Value created from a utf8-encoded JSON string.
+ static Value
+ createFromJsonUtf8(Runtime& runtime, const uint8_t* json, size_t length);
+
+ /// \return according to the SameValue algorithm see more here:
+ // https://www.ecma-international.org/ecma-262/5.1/#sec-11.9.4
+ static bool strictEquals(Runtime& runtime, const Value& a, const Value& b);
+
+ Value& operator=(Value&& other) {
+ this->~Value();
+ new (this) Value(std::move(other));
+ return *this;
+ }
+
+ bool isUndefined() const {
+ return kind_ == UndefinedKind;
+ }
+
+ bool isNull() const {
+ return kind_ == NullKind;
+ }
+
+ bool isBool() const {
+ return kind_ == BooleanKind;
+ }
+
+ bool isNumber() const {
+ return kind_ == NumberKind;
+ }
+
+ bool isString() const {
+ return kind_ == StringKind;
+ }
+
+ bool isObject() const {
+ return kind_ == ObjectKind;
+ }
+
+ /// \return the boolean value, or asserts if not a boolean.
+ bool getBool() const {
+ assert(isBool());
+ return data_.boolean;
+ }
+
+ /// \return the number value, or asserts if not a number.
+ double getNumber() const {
+ assert(isNumber());
+ return data_.number;
+ }
+
+ /// \return the number value, or throws JSIException if not a
+ /// number.
+ double asNumber() const;
+
+ /// \return the String value, or asserts if not a string.
+ String getString(Runtime& runtime) const& {
+ assert(isString());
+ return String(runtime.cloneString(data_.pointer.ptr_));
+ }
+
+ /// \return the String value, or asserts if not a string.
+ /// Can be used on rvalue references to avoid cloning more strings.
+ String getString(Runtime&) && {
+ assert(isString());
+ auto ptr = data_.pointer.ptr_;
+ data_.pointer.ptr_ = nullptr;
+ return static_cast<String>(ptr);
+ }
+
+ String asString(Runtime& runtime) const&;
+ String asString(Runtime& runtime) &&;
+
+ /// \return the Object value, or asserts if not an object.
+ Object getObject(Runtime& runtime) const& {
+ assert(isObject());
+ return Object(runtime.cloneObject(data_.pointer.ptr_));
+ }
+
+ /// \return the Object value, or asserts if not an object.
+ /// Can be used on rvalue references to avoid cloning more objects.
+ Object getObject(Runtime&) && {
+ assert(isObject());
+ auto ptr = data_.pointer.ptr_;
+ data_.pointer.ptr_ = nullptr;
+ return static_cast<Object>(ptr);
+ }
+
+ /// \return the Object value, or throws JSIException if not an
+ /// object.
+ Object asObject(Runtime& runtime) const&;
+ Object asObject(Runtime& runtime) &&;
+
+ // \return a String like JS .toString() would do.
+ String toString(Runtime& runtime) const;
+
+ private:
+ friend class Runtime;
+
+ enum ValueKind {
+ UndefinedKind,
+ NullKind,
+ BooleanKind,
+ NumberKind,
+ StringKind,
+ ObjectKind,
+ PointerKind = StringKind,
+ };
+
+ union Data {
+ // Value's ctor and dtor will manage the lifecycle of the contained Data.
+ Data() {
+ static_assert(
+ sizeof(Data) == sizeof(uint64_t),
+ "Value data should fit in a 64-bit register");
+ }
+ ~Data() {}
+
+ // scalars
+ bool boolean;
+ double number;
+ // pointers
+ Pointer pointer; // String, Object, Array, Function
+ };
+
+ Value(ValueKind kind) : kind_(kind) {}
+
+ constexpr static ValueKind kindOf(const String&) {
+ return StringKind;
+ }
+ constexpr static ValueKind kindOf(const Object&) {
+ return ObjectKind;
+ }
+
+ ValueKind kind_;
+ Data data_;
+
+ // In the future: Value becomes NaN-boxed. In the Hermes impl, if
+ // the object contains a PinnedHermesValue, we need to be able to
+ // get a pointer to it; this can be casted from 'this'. In the JSC
+ // impl, we need to be able to convert the boxed value into a JSC
+ // ref. This can be done by casting this, deferencing it to get a
+ // number, doing some bit masks, and then casting again into the
+ // desired JSC ref type.
+};
+
+/// Not movable and not copyable RAII marker advising the underlying
+/// JavaScript VM to track resources allocated since creation until
+/// destruction so that they can be recycled eagerly when the Scope
+/// goes out of scope instead of floating in the air until the next
+/// garbage collection or any other delayed release occurs.
+///
+/// This API should be treated only as advice, implementations can
+/// choose to ignore the fact that Scopes are created or destroyed.
+///
+/// This class is an exception to the rule allowing destructors to be
+/// called without proper synchronization (see Runtime documentation).
+/// The whole point of this class is to enable all sorts of clean ups
+/// when the destructor is called and this proper synchronization is
+/// required at that time.
+///
+/// Instances of this class are intended to be created as automatic stack
+/// variables in which case destructor calls don't require any additional
+/// locking, provided that the lock (if any) is managed with RAII helpers.
+class Scope {
+ public:
+ explicit Scope(Runtime& rt) : rt_(rt), prv_(rt.pushScope()) {}
+ ~Scope() {
+ rt_.popScope(prv_);
+ };
+
+ Scope(const Scope&) = delete;
+ Scope(Scope&&) = delete;
+
+ Scope& operator=(const Scope&) = delete;
+ Scope& operator=(Scope&&) = delete;
+
+ template <typename F>
+ static auto callInNewScope(Runtime& rt, F f) -> decltype(f()) {
+ Scope s(rt);
+ return f();
+ }
+
+ private:
+ Runtime& rt_;
+ Runtime::ScopeState* prv_;
+};
+
+/// Base class for jsi exceptions
+class JSIException : public std::exception {
+ protected:
+ JSIException(){};
+ JSIException(std::string what) : what_(std::move(what)){};
+
+ public:
+ virtual const char* what() const noexcept override {
+ return what_.c_str();
+ }
+
+ protected:
+ std::string what_;
+};
+
+/// This exception will be thrown by API functions on errors not related to
+/// JavaScript execution.
+class JSINativeException : public JSIException {
+ public:
+ JSINativeException(std::string what) : JSIException(std::move(what)) {}
+};
+
+/// This exception will be thrown by API functions whenever a JS
+/// operation causes an exception as described by the spec, or as
+/// otherwise described.
+class JSError : public JSIException {
+ public:
+ /// Creates a JSError referring to provided \c value
+ JSError(Runtime& r, Value&& value);
+
+ /// Creates a JSError referring to new \c Error instance capturing current
+ /// JavaScript stack. The error message property is set to given \c message.
+ JSError(Runtime& rt, std::string message);
+
+ /// Creates a JSError referring to new \c Error instance capturing current
+ /// JavaScript stack. The error message property is set to given \c message.
+ JSError(Runtime& rt, const char* message)
+ : JSError(rt, std::string(message)){};
+
+ /// Creates a JSError referring to a JavaScript Object having message and
+ /// stack properties set to provided values.
+ JSError(Runtime& rt, std::string message, std::string stack);
+
+ /// Creates a JSError referring to provided value and what string
+ /// set to provided message. This argument order is a bit weird,
+ /// but necessary to avoid ambiguity with the above.
+ JSError(std::string what, Runtime& rt, Value&& value);
+
+ const std::string& getStack() const {
+ return stack_;
+ }
+
+ const std::string& getMessage() const {
+ return message_;
+ }
+
+ const jsi::Value& value() const {
+ assert(value_);
+ return *value_;
+ }
+
+ private:
+ // This initializes the value_ member and does some other
+ // validation, so it must be called by every branch through the
+ // constructors.
+ void setValue(Runtime& rt, Value&& value);
+
+ // This needs to be on the heap, because throw requires the object
+ // be copyable, and Value is not.
+ std::shared_ptr<jsi::Value> value_;
+ std::string message_;
+ std::string stack_;
+};
+
+} // namespace jsi
+} // namespace facebook
+
+#include <jsi/jsi-inl.h>

ReactCommon/jsi/jsi-inl.h

@@ -0,0 +1,309 @@
+// 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.
+
+#pragma once
+
+namespace facebook {
+namespace jsi {
+namespace detail {
+
+inline Value toValue(Runtime&, std::nullptr_t) {
+ return Value::null();
+}
+inline Value toValue(Runtime&, bool b) {
+ return Value(b);
+}
+inline Value toValue(Runtime&, double d) {
+ return Value(d);
+}
+inline Value toValue(Runtime&, int i) {
+ return Value(i);
+}
+inline Value toValue(Runtime& runtime, const char* str) {
+ return String::createFromAscii(runtime, str);
+}
+inline Value toValue(Runtime& runtime, const std::string& str) {
+ return String::createFromAscii(runtime, str);
+}
+template <typename T>
+inline Value toValue(Runtime& runtime, const T& other) {
+ static_assert(
+ std::is_base_of<Pointer, T>::value,
+ "This type cannot be converted to Value");
+ return Value(runtime, other);
+}
+inline Value toValue(Runtime& runtime, const Value& value) {
+ return Value(runtime, value);
+}
+inline Value&& toValue(Runtime&, Value&& value) {
+ return std::move(value);
+}
+
+inline PropNameID toPropNameID(Runtime& runtime, const char* name) {
+ return PropNameID::forAscii(runtime, name);
+}
+inline PropNameID toPropNameID(Runtime& runtime, const std::string& name) {
+ return PropNameID::forUtf8(runtime, name);
+}
+inline PropNameID&& toPropNameID(Runtime&, PropNameID&& name) {
+ return std::move(name);
+}
+
+void throwJSError(Runtime&, const char* msg);
+
+} // namespace detail
+
+template <typename T>
+inline T Runtime::make(Runtime::PointerValue* pv) {
+ return T(pv);
+}
+
+inline const Runtime::PointerValue* Runtime::getPointerValue(
+ const jsi::Pointer& pointer) {
+ return pointer.ptr_;
+}
+
+inline const Runtime::PointerValue* Runtime::getPointerValue(
+ const jsi::Value& value) {
+ return value.data_.pointer.ptr_;
+}
+
+inline Value Object::getProperty(Runtime& runtime, const char* name) const {
+ return getProperty(runtime, String::createFromAscii(runtime, name));
+}
+
+inline Value Object::getProperty(Runtime& runtime, const String& name) const {
+ return runtime.getProperty(*this, name);
+}
+
+inline Value Object::getProperty(Runtime& runtime, const PropNameID& name)
+ const {
+ return runtime.getProperty(*this, name);
+}
+
+inline bool Object::hasProperty(Runtime& runtime, const char* name) const {
+ return hasProperty(runtime, String::createFromAscii(runtime, name));
+}
+
+inline bool Object::hasProperty(Runtime& runtime, const String& name) const {
+ return runtime.hasProperty(*this, name);
+}
+
+inline bool Object::hasProperty(Runtime& runtime, const PropNameID& name)
+ const {
+ return runtime.hasProperty(*this, name);
+}
+
+template <typename T>
+void Object::setProperty(Runtime& runtime, const char* name, T&& value) {
+ setProperty(
+ runtime, String::createFromAscii(runtime, name), std::forward<T>(value));
+}
+
+template <typename T>
+void Object::setProperty(Runtime& runtime, const String& name, T&& value) {
+ setPropertyValue(
+ runtime, name, detail::toValue(runtime, std::forward<T>(value)));
+}
+
+template <typename T>
+void Object::setProperty(Runtime& runtime, const PropNameID& name, T&& value) {
+ setPropertyValue(
+ runtime, name, detail::toValue(runtime, std::forward<T>(value)));
+}
+
+inline Array Object::getArray(Runtime& runtime) const& {
+ assert(runtime.isArray(*this));
+ (void)runtime; // when assert is disabled we need to mark this as used
+ return Array(runtime.cloneObject(ptr_));
+}
+
+inline Array Object::getArray(Runtime& runtime) && {
+ assert(runtime.isArray(*this));
+ (void)runtime; // when assert is disabled we need to mark this as used
+ Runtime::PointerValue* value = ptr_;
+ ptr_ = nullptr;
+ return Array(value);
+}
+
+inline ArrayBuffer Object::getArrayBuffer(Runtime& runtime) const& {
+ assert(runtime.isArrayBuffer(*this));
+ (void)runtime; // when assert is disabled we need to mark this as used
+ return ArrayBuffer(runtime.cloneObject(ptr_));
+}
+
+inline ArrayBuffer Object::getArrayBuffer(Runtime& runtime) && {
+ assert(runtime.isArrayBuffer(*this));
+ (void)runtime; // when assert is disabled we need to mark this as used
+ Runtime::PointerValue* value = ptr_;
+ ptr_ = nullptr;
+ return ArrayBuffer(value);
+}
+
+inline Function Object::getFunction(Runtime& runtime) const& {
+ assert(runtime.isFunction(*this));
+ return Function(runtime.cloneObject(ptr_));
+}
+
+inline Function Object::getFunction(Runtime& runtime) && {
+ assert(runtime.isFunction(*this));
+ (void)runtime; // when assert is disabled we need to mark this as used
+ Runtime::PointerValue* value = ptr_;
+ ptr_ = nullptr;
+ return Function(value);
+}
+
+template <typename T>
+inline bool Object::isHostObject(Runtime& runtime) const {
+ return runtime.isHostObject(*this) &&
+ std::dynamic_pointer_cast<T>(runtime.getHostObject(*this));
+}
+
+template <>
+inline bool Object::isHostObject<HostObject>(Runtime& runtime) const {
+ return runtime.isHostObject(*this);
+}
+
+template <typename T>
+inline std::shared_ptr<T> Object::getHostObject(Runtime& runtime) const {
+ assert(isHostObject<T>(runtime));
+ return std::static_pointer_cast<T>(runtime.getHostObject(*this));
+}
+
+template <typename T>
+inline std::shared_ptr<T> Object::asHostObject(Runtime& runtime) const {
+ if (!isHostObject<T>(runtime)) {
+ detail::throwJSError(runtime, "Object is not a HostObject of desired type");
+ }
+ return std::static_pointer_cast<T>(runtime.getHostObject(*this));
+}
+
+template <>
+inline std::shared_ptr<HostObject> Object::getHostObject<HostObject>(
+ Runtime& runtime) const {
+ assert(runtime.isHostObject(*this));
+ return runtime.getHostObject(*this);
+}
+
+inline Array Object::getPropertyNames(Runtime& runtime) const {
+ return runtime.getPropertyNames(*this);
+}
+
+inline Value WeakObject::lock(Runtime& runtime) {
+ return runtime.lockWeakObject(*this);
+}
+
+template <typename T>
+void Array::setValueAtIndex(Runtime& runtime, size_t i, T&& value) {
+ setValueAtIndexImpl(
+ runtime, i, detail::toValue(runtime, std::forward<T>(value)));
+}
+
+inline Value Array::getValueAtIndex(Runtime& runtime, size_t i) const {
+ return runtime.getValueAtIndex(*this, i);
+}
+
+inline Function Function::createFromHostFunction(
+ Runtime& runtime,
+ const jsi::PropNameID& name,
+ unsigned int paramCount,
+ jsi::HostFunctionType func) {
+ return runtime.createFunctionFromHostFunction(
+ name, paramCount, std::move(func));
+}
+
+inline Value Function::call(Runtime& runtime, const Value* args, size_t count)
+ const {
+ return runtime.call(*this, Value::undefined(), args, count);
+}
+
+inline Value Function::call(Runtime& runtime, std::initializer_list<Value> args)
+ const {
+ return call(runtime, args.begin(), args.size());
+}
+
+template <typename... Args>
+inline Value Function::call(Runtime& runtime, Args&&... args) const {
+ // A more awesome version of this would be able to create raw values
+ // which can be used directly as HermesValues, instead of having to
+ // wrap the args in Values and hvFromValue on each to unwrap them.
+ // But this will do for now.
+ return call(runtime, {detail::toValue(runtime, std::forward<Args>(args))...});
+}
+
+inline Value Function::callWithThis(
+ Runtime& runtime,
+ const Object& jsThis,
+ const Value* args,
+ size_t count) const {
+ return runtime.call(*this, Value(runtime, jsThis), args, count);
+}
+
+inline Value Function::callWithThis(
+ Runtime& runtime,
+ const Object& jsThis,
+ std::initializer_list<Value> args) const {
+ return callWithThis(runtime, jsThis, args.begin(), args.size());
+}
+
+template <typename... Args>
+inline Value Function::callWithThis(
+ Runtime& runtime,
+ const Object& jsThis,
+ Args&&... args) const {
+ // A more awesome version of this would be able to create raw values
+ // which can be used directly as HermesValues, instead of having to
+ // wrap the args in Values and hvFromValue on each to unwrap them.
+ // But this will do for now.
+ return callWithThis(
+ runtime, jsThis, {detail::toValue(runtime, std::forward<Args>(args))...});
+}
+
+template <typename... Args>
+inline Array Array::createWithElements(Runtime& runtime, Args&&... args) {
+ return createWithElements(
+ runtime, {detail::toValue(runtime, std::forward<Args>(args))...});
+}
+
+template <typename... Args>
+inline std::vector<PropNameID> PropNameID::names(
+ Runtime& runtime,
+ Args&&... args) {
+ return names({detail::toPropNameID(runtime, std::forward<Args>(args))...});
+}
+
+template <size_t N>
+inline std::vector<PropNameID> PropNameID::names(
+ PropNameID(&&propertyNames)[N]) {
+ std::vector<PropNameID> result;
+ result.reserve(N);
+ for (auto& name : propertyNames) {
+ result.push_back(std::move(name));
+ }
+ return result;
+}
+
+inline Value Function::callAsConstructor(
+ Runtime& runtime,
+ const Value* args,
+ size_t count) const {
+ return runtime.callAsConstructor(*this, args, count);
+}
+
+inline Value Function::callAsConstructor(
+ Runtime& runtime,
+ std::initializer_list<Value> args) const {
+ return callAsConstructor(runtime, args.begin(), args.size());
+}
+
+template <typename... Args>
+inline Value Function::callAsConstructor(Runtime& runtime, Args&&... args)
+ const {
+ return callAsConstructor(
+ runtime, {detail::toValue(runtime, std::forward<Args>(args))...});
+}
+
+} // namespace jsi
+} // namespace facebook

ReactCommon/jsiexecutor/Android.mk

@@ -0,0 +1,22 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := jsireact
+
+LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/jsireact/*.cpp)
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
+
+LOCAL_CFLAGS := -fexceptions -frtti -O3
+
+LOCAL_STATIC_LIBRARIES := libjsi reactnative
+LOCAL_SHARED_LIBRARIES := libfolly_json glog
+
+include $(BUILD_STATIC_LIBRARY)

ReactCommon/jsiexecutor/BUCK

@@ -0,0 +1,41 @@
+load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", "cxx_library", "react_native_xplat_dep", "react_native_xplat_target")
+
+cxx_library(
+ name = "jsiexecutor",
+ srcs = [
+ "jsireact/JSIExecutor.cpp",
+ "jsireact/JSINativeModules.cpp",
+ ],
+ header_namespace = "",
+ exported_headers = {
+ "jsireact/JSIExecutor.h": "jsireact/JSIExecutor.h",
+ "jsireact/JSINativeModules.h": "jsireact/JSINativeModules.h",
+ },
+ compiler_flags = [
+ "-fexceptions",
+ "-frtti",
+ ],
+ fbandroid_deps = [
+ "xplat//folly:molly",
+ "xplat//third-party/glog:glog",
+ "xplat//third-party/linker_lib:atomic",
+ ],
+ fbobjc_force_static = True,
+ fbobjc_header_path_prefix = "",
+ platforms = (ANDROID, APPLE),
+ preprocessor_flags = [
+ "-DLOG_TAG=\"ReactNative\"",
+ "-DWITH_FBSYSTRACE=1",
+ ],
+ visibility = [
+ "PUBLIC",
+ ],
+ xcode_public_headers_symlinks = True,
+ deps = [
+ "xplat//fbsystrace:fbsystrace",
+ react_native_xplat_dep("jsi:jsi"),
+ react_native_xplat_dep("jsi:JSIDynamic"),
+ react_native_xplat_target("cxxreact:bridge"),
+ react_native_xplat_target("cxxreact:jsbigstring"),
+ ],
+)

ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp

@@ -0,0 +1,390 @@
+// 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.
+
+#include "jsireact/JSIExecutor.h"
+
+#include <cxxreact/JSBigString.h>
+#include <cxxreact/ModuleRegistry.h>
+#include <cxxreact/ReactMarker.h>
+#include <cxxreact/SystraceSection.h>
+#include <folly/Conv.h>
+#include <folly/json.h>
+#include <glog/logging.h>
+#include <jsi/JSIDynamic.h>
+
+#include <sstream>
+#include <stdexcept>
+
+using namespace facebook::jsi;
+
+namespace facebook {
+namespace react {
+
+class JSIExecutor::NativeModuleProxy : public jsi::HostObject {
+ public:
+ NativeModuleProxy(JSIExecutor& executor) : executor_(executor) {}
+
+ Value get(Runtime& rt, const PropNameID& name) override {
+ if (name.utf8(rt) == "name") {
+ return jsi::String::createFromAscii(rt, "NativeModules");
+ }
+
+ return executor_.nativeModules_.getModule(rt, name);
+ }
+
+ void set(Runtime&, const PropNameID&, const Value&) override {
+ throw std::runtime_error(
+ "Unable to put on NativeModules: Operation unsupported");
+ }
+
+ private:
+ JSIExecutor& executor_;
+};
+
+namespace {
+
+// basename_r isn't in all iOS SDKs, so use this simple version instead.
+std::string simpleBasename(const std::string& path) {
+ size_t pos = path.rfind("/");
+ return (pos != std::string::npos) ? path.substr(pos) : path;
+}
+
+} // namespace
+
+JSIExecutor::JSIExecutor(
+ std::shared_ptr<jsi::Runtime> runtime,
+ std::shared_ptr<ExecutorDelegate> delegate,
+ Logger logger,
+ const JSIScopedTimeoutInvoker& scopedTimeoutInvoker,
+ RuntimeInstaller runtimeInstaller)
+ : runtime_(runtime),
+ delegate_(delegate),
+ nativeModules_(delegate ? delegate->getModuleRegistry() : nullptr),
+ logger_(logger),
+ scopedTimeoutInvoker_(scopedTimeoutInvoker),
+ runtimeInstaller_(runtimeInstaller) {
+ runtime_->global().setProperty(
+ *runtime, "__jsiExecutorDescription", runtime->description());
+}
+
+void JSIExecutor::loadApplicationScript(
+ std::unique_ptr<const JSBigString> script,
+ std::string sourceURL) {
+ SystraceSection s("JSIExecutor::loadApplicationScript");
+
+ // TODO: check for and use precompiled HBC
+
+ runtime_->global().setProperty(
+ *runtime_,
+ "nativeModuleProxy",
+ Object::createFromHostObject(
+ *runtime_, std::make_shared<NativeModuleProxy>(*this)));
+
+ runtime_->global().setProperty(
+ *runtime_,
+ "nativeFlushQueueImmediate",
+ Function::createFromHostFunction(
+ *runtime_,
+ PropNameID::forAscii(*runtime_, "nativeFlushQueueImmediate"),
+ 1,
+ [this](
+ jsi::Runtime&,
+ const jsi::Value&,
+ const jsi::Value* args,
+ size_t count) {
+ if (count != 1) {
+ throw std::invalid_argument(
+ "nativeFlushQueueImmediate arg count must be 1");
+ }
+ callNativeModules(args[0], false);
+ return Value::undefined();
+ }));
+
+ runtime_->global().setProperty(
+ *runtime_,
+ "nativeCallSyncHook",
+ Function::createFromHostFunction(
+ *runtime_,
+ PropNameID::forAscii(*runtime_, "nativeCallSyncHook"),
+ 1,
+ [this](
+ jsi::Runtime&,
+ const jsi::Value&,
+ const jsi::Value* args,
+ size_t count) { return nativeCallSyncHook(args, count); }));
+
+ if (logger_) {
+ // Only inject the logging function if it was supplied by the caller.
+ runtime_->global().setProperty(
+ *runtime_,
+ "nativeLoggingHook",
+ Function::createFromHostFunction(
+ *runtime_,
+ PropNameID::forAscii(*runtime_, "nativeLoggingHook"),
+ 2,
+ [this](
+ jsi::Runtime&,
+ const jsi::Value&,
+ const jsi::Value* args,
+ size_t count) {
+ if (count != 2) {
+ throw std::invalid_argument(
+ "nativeLoggingHook takes 2 arguments");
+ }
+ logger_(
+ args[0].asString(*runtime_).utf8(*runtime_),
+ folly::to<unsigned int>(args[1].asNumber()));
+ return Value::undefined();
+ }));
+ }
+
+ if (runtimeInstaller_) {
+ runtimeInstaller_(*runtime_);
+ }
+
+ bool hasLogger(ReactMarker::logTaggedMarker);
+ std::string scriptName = simpleBasename(sourceURL);
+ if (hasLogger) {
+ ReactMarker::logTaggedMarker(
+ ReactMarker::RUN_JS_BUNDLE_START, scriptName.c_str());
+ }
+ runtime_->evaluateJavaScript(
+ std::make_unique<BigStringBuffer>(std::move(script)), sourceURL);
+ flush();
+ if (hasLogger) {
+ ReactMarker::logMarker(ReactMarker::CREATE_REACT_CONTEXT_STOP);
+ ReactMarker::logTaggedMarker(
+ ReactMarker::RUN_JS_BUNDLE_STOP, scriptName.c_str());
+ }
+}
+
+void JSIExecutor::setBundleRegistry(std::unique_ptr<RAMBundleRegistry> r) {
+ if (!bundleRegistry_) {
+ runtime_->global().setProperty(
+ *runtime_,
+ "nativeRequire",
+ Function::createFromHostFunction(
+ *runtime_,
+ PropNameID::forAscii(*runtime_, "nativeRequire"),
+ 2,
+ [this](
+ Runtime& rt,
+ const facebook::jsi::Value&,
+ const facebook::jsi::Value* args,
+ size_t count) { return nativeRequire(args, count); }));
+ }
+ bundleRegistry_ = std::move(r);
+}
+
+void JSIExecutor::registerBundle(
+ uint32_t bundleId,
+ const std::string& bundlePath) {
+ const auto tag = folly::to<std::string>(bundleId);
+ ReactMarker::logTaggedMarker(
+ ReactMarker::REGISTER_JS_SEGMENT_START, tag.c_str());
+ if (bundleRegistry_) {
+ bundleRegistry_->registerBundle(bundleId, bundlePath);
+ } else {
+ auto script = JSBigFileString::fromPath(bundlePath);
+ runtime_->evaluateJavaScript(
+ std::make_unique<BigStringBuffer>(std::move(script)),
+ JSExecutor::getSyntheticBundlePath(bundleId, bundlePath));
+ }
+ ReactMarker::logTaggedMarker(
+ ReactMarker::REGISTER_JS_SEGMENT_STOP, tag.c_str());
+}
+
+void JSIExecutor::callFunction(
+ const std::string& moduleId,
+ const std::string& methodId,
+ const folly::dynamic& arguments) {
+ SystraceSection s(
+ "JSIExecutor::callFunction", "moduleId", moduleId, "methodId", methodId);
+ if (!callFunctionReturnFlushedQueue_) {
+ bindBridge();
+ }
+
+ // Construct the error message producer in case this times out.
+ // This is executed on a background thread, so it must capture its parameters
+ // by value.
+ auto errorProducer = [=] {
+ std::stringstream ss;
+ ss << "moduleID: " << moduleId << " methodID: " << methodId
+ << " arguments: " << folly::toJson(arguments);
+ return ss.str();
+ };
+
+ Value ret = Value::undefined();
+ try {
+ scopedTimeoutInvoker_(
+ [&] {
+ ret = callFunctionReturnFlushedQueue_->call(
+ *runtime_,
+ moduleId,
+ methodId,
+ valueFromDynamic(*runtime_, arguments));
+ },
+ std::move(errorProducer));
+ } catch (...) {
+ std::throw_with_nested(
+ std::runtime_error("Error calling " + moduleId + "." + methodId));
+ }
+
+ callNativeModules(ret, true);
+}
+
+void JSIExecutor::invokeCallback(
+ const double callbackId,
+ const folly::dynamic& arguments) {
+ SystraceSection s("JSIExecutor::invokeCallback", "callbackId", callbackId);
+ if (!invokeCallbackAndReturnFlushedQueue_) {
+ bindBridge();
+ }
+ Value ret;
+ try {
+ ret = invokeCallbackAndReturnFlushedQueue_->call(
+ *runtime_, callbackId, valueFromDynamic(*runtime_, arguments));
+ } catch (...) {
+ std::throw_with_nested(std::runtime_error(
+ folly::to<std::string>("Error invoking callback ", callbackId)));
+ }
+
+ callNativeModules(ret, true);
+}
+
+void JSIExecutor::setGlobalVariable(
+ std::string propName,
+ std::unique_ptr<const JSBigString> jsonValue) {
+ SystraceSection s("JSIExecutor::setGlobalVariable", "propName", propName);
+ runtime_->global().setProperty(
+ *runtime_,
+ propName.c_str(),
+ Value::createFromJsonUtf8(
+ *runtime_,
+ reinterpret_cast<const uint8_t*>(jsonValue->c_str()),
+ jsonValue->size()));
+}
+
+std::string JSIExecutor::getDescription() {
+ return "JSI " + runtime_->description();
+}
+
+void* JSIExecutor::getJavaScriptContext() {
+ return runtime_.get();
+}
+
+bool JSIExecutor::isInspectable() {
+ return runtime_->isInspectable();
+}
+
+void JSIExecutor::bindBridge() {
+ std::call_once(bindFlag_, [this] {
+ SystraceSection s("JSIExecutor::bindBridge (once)");
+ Value batchedBridgeValue =
+ runtime_->global().getProperty(*runtime_, "__fbBatchedBridge");
+ if (batchedBridgeValue.isUndefined()) {
+ Function requireBatchedBridge = runtime_->global().getPropertyAsFunction(
+ *runtime_, "__fbRequireBatchedBridge");
+ batchedBridgeValue = requireBatchedBridge.call(*runtime_);
+ if (batchedBridgeValue.isUndefined()) {
+ throw JSINativeException(
+ "Could not get BatchedBridge, make sure your bundle is packaged correctly");
+ }
+ }
+
+ Object batchedBridge = batchedBridgeValue.asObject(*runtime_);
+ callFunctionReturnFlushedQueue_ = batchedBridge.getPropertyAsFunction(
+ *runtime_, "callFunctionReturnFlushedQueue");
+ invokeCallbackAndReturnFlushedQueue_ = batchedBridge.getPropertyAsFunction(
+ *runtime_, "invokeCallbackAndReturnFlushedQueue");
+ flushedQueue_ =
+ batchedBridge.getPropertyAsFunction(*runtime_, "flushedQueue");
+ callFunctionReturnResultAndFlushedQueue_ =
+ batchedBridge.getPropertyAsFunction(
+ *runtime_, "callFunctionReturnResultAndFlushedQueue");
+ });
+}
+
+void JSIExecutor::callNativeModules(const Value& queue, bool isEndOfBatch) {
+ SystraceSection s("JSIExecutor::callNativeModules");
+ // If this fails, you need to pass a fully functional delegate with a
+ // module registry to the factory/ctor.
+ CHECK(delegate_) << "Attempting to use native modules without a delegate";
+#if 0 // maybe useful for debugging
+ std::string json = runtime_->global().getPropertyAsObject(*runtime_, "JSON")
+ .getPropertyAsFunction(*runtime_, "stringify").call(*runtime_, queue)
+ .getString(*runtime_).utf8(*runtime_);
+#endif
+ delegate_->callNativeModules(
+ *this, dynamicFromValue(*runtime_, queue), isEndOfBatch);
+}
+
+void JSIExecutor::flush() {
+ SystraceSection s("JSIExecutor::flush");
+ if (flushedQueue_) {
+ callNativeModules(flushedQueue_->call(*runtime_), true);
+ return;
+ }
+
+ // When a native module is called from JS, BatchedBridge.enqueueNativeCall()
+ // is invoked. For that to work, require('BatchedBridge') has to be called,
+ // and when that happens, __fbBatchedBridge is set as a side effect.
+ Value batchedBridge =
+ runtime_->global().getProperty(*runtime_, "__fbBatchedBridge");
+ // So here, if __fbBatchedBridge doesn't exist, then we know no native calls
+ // have happened, and we were able to determine this without forcing
+ // BatchedBridge to be loaded as a side effect.
+ if (!batchedBridge.isUndefined()) {
+ // If calls were made, we bind to the JS bridge methods, and use them to
+ // get the pending queue of native calls.
+ bindBridge();
+ callNativeModules(flushedQueue_->call(*runtime_), true);
+ } else if (delegate_) {
+ // If we have a delegate, we need to call it; we pass a null list to
+ // callNativeModules, since we know there are no native calls, without
+ // calling into JS again. If no calls were made and there's no delegate,
+ // nothing happens, which is correct.
+ callNativeModules(nullptr, true);
+ }
+}
+
+Value JSIExecutor::nativeRequire(const Value* args, size_t count) {
+ if (count > 2 || count == 0) {
+ throw std::invalid_argument("Got wrong number of args");
+ }
+
+ uint32_t moduleId = folly::to<uint32_t>(args[0].getNumber());
+ uint32_t bundleId = count == 2 ? folly::to<uint32_t>(args[1].getNumber()) : 0;
+ auto module = bundleRegistry_->getModule(bundleId, moduleId);
+
+ runtime_->evaluateJavaScript(
+ std::make_unique<StringBuffer>(module.code), module.name);
+ return facebook::jsi::Value();
+}
+
+Value JSIExecutor::nativeCallSyncHook(const Value* args, size_t count) {
+ if (count != 3) {
+ throw std::invalid_argument("nativeCallSyncHook arg count must be 3");
+ }
+
+ if (!args[2].asObject(*runtime_).isArray(*runtime_)) {
+ throw std::invalid_argument(
+ folly::to<std::string>("method parameters should be array"));
+ }
+
+ MethodCallResult result = delegate_->callSerializableNativeHook(
+ *this,
+ static_cast<unsigned int>(args[0].getNumber()), // moduleId
+ static_cast<unsigned int>(args[1].getNumber()), // methodId
+ dynamicFromValue(*runtime_, args[2])); // args
+
+ if (!result.hasValue()) {
+ return Value::undefined();
+ }
+ return valueFromDynamic(*runtime_, result.value());
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/jsiexecutor/jsireact/JSIExecutor.h

@@ -0,0 +1,135 @@
+// 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.
+
+#pragma once
+
+#include "JSINativeModules.h"
+
+#include <cxxreact/JSBigString.h>
+#include <cxxreact/JSExecutor.h>
+#include <cxxreact/RAMBundleRegistry.h>
+#include <jsi/jsi.h>
+#include <functional>
+#include <mutex>
+
+namespace facebook {
+namespace react {
+
+// A JSIScopedTimeoutInvoker is a trampoline-type function for introducing
+// timeouts. Call the TimeoutInvoker with a function to execute, the invokee.
+// The TimeoutInvoker will immediately invoke it, synchronously on the same
+// thread. If the invokee fails to return after some timeout (private to the
+// TimeoutInvoker), a soft error may be reported.
+//
+// If a soft error is reported, the second parameter errorMessageProducer will
+// be invoked to produce an error message, which will be included in the soft
+// error report. Note that the errorMessageProducer will be invoked
+// asynchronously on a different thread.
+//
+// The timeout behavior does NOT caues the invokee to aborted. If the invokee
+// blocks forever, so will the ScopedTimeoutInvoker (but the soft error may
+// still be reported).
+//
+// The invokee is passed by const ref because it is executed synchronously, but
+// the errorMessageProducer is passed by value because it must be copied or
+// moved for async execution.
+//
+// Example usage:
+//
+// int param = ...;
+// timeoutInvoker(
+// [&]{ someBigWork(param); },
+// [=] -> std::string {
+// return "someBigWork, param " + std::to_string(param);
+// })
+//
+using JSIScopedTimeoutInvoker = std::function<void(
+ const std::function<void()>& invokee,
+ std::function<std::string()> errorMessageProducer)>;
+
+class BigStringBuffer : public jsi::Buffer {
+ public:
+ BigStringBuffer(std::unique_ptr<const JSBigString> script)
+ : script_(std::move(script)) {}
+
+ size_t size() const override {
+ return script_->size();
+ }
+
+ const uint8_t* data() const override {
+ return reinterpret_cast<const uint8_t*>(script_->c_str());
+ }
+
+ private:
+ std::unique_ptr<const JSBigString> script_;
+};
+
+class JSIExecutor : public JSExecutor {
+ public:
+ using Logger =
+ std::function<void(const std::string& message, unsigned int logLevel)>;
+
+ using RuntimeInstaller = std::function<void(jsi::Runtime& runtime)>;
+
+ JSIExecutor(
+ std::shared_ptr<jsi::Runtime> runtime,
+ std::shared_ptr<ExecutorDelegate> delegate,
+ Logger logger,
+ const JSIScopedTimeoutInvoker& timeoutInvoker,
+ RuntimeInstaller runtimeInstaller);
+ void loadApplicationScript(
+ std::unique_ptr<const JSBigString> script,
+ std::string sourceURL) override;
+ void setBundleRegistry(std::unique_ptr<RAMBundleRegistry>) override;
+ void registerBundle(uint32_t bundleId, const std::string& bundlePath)
+ override;
+ void callFunction(
+ const std::string& moduleId,
+ const std::string& methodId,
+ const folly::dynamic& arguments) override;
+ void invokeCallback(const double callbackId, const folly::dynamic& arguments)
+ override;
+ void setGlobalVariable(
+ std::string propName,
+ std::unique_ptr<const JSBigString> jsonValue) override;
+ std::string getDescription() override;
+ void* getJavaScriptContext() override;
+ bool isInspectable() override;
+
+ // An implementation of JSIScopedTimeoutInvoker that simply runs the
+ // invokee, with no timeout.
+ static void defaultTimeoutInvoker(
+ const std::function<void()>& invokee,
+ std::function<std::string()> errorMessageProducer) {
+ (void)errorMessageProducer;
+ invokee();
+ }
+
+ private:
+ class NativeModuleProxy;
+
+ void flush();
+ void bindBridge();
+ void callNativeModules(const jsi::Value& queue, bool isEndOfBatch);
+ jsi::Value nativeCallSyncHook(const jsi::Value* args, size_t count);
+ jsi::Value nativeRequire(const jsi::Value* args, size_t count);
+
+ std::shared_ptr<jsi::Runtime> runtime_;
+ std::shared_ptr<ExecutorDelegate> delegate_;
+ JSINativeModules nativeModules_;
+ std::once_flag bindFlag_;
+ std::unique_ptr<RAMBundleRegistry> bundleRegistry_;
+ Logger logger_;
+ JSIScopedTimeoutInvoker scopedTimeoutInvoker_;
+ RuntimeInstaller runtimeInstaller_;
+
+ folly::Optional<jsi::Function> callFunctionReturnFlushedQueue_;
+ folly::Optional<jsi::Function> invokeCallbackAndReturnFlushedQueue_;
+ folly::Optional<jsi::Function> flushedQueue_;
+ folly::Optional<jsi::Function> callFunctionReturnResultAndFlushedQueue_;
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/jsiexecutor/jsireact/JSINativeModules.cpp

@@ -0,0 +1,89 @@
+// 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.
+
+#include "jsireact/JSINativeModules.h"
+
+#include <cxxreact/ReactMarker.h>
+
+#include <jsi/JSIDynamic.h>
+
+#include <string>
+
+using namespace facebook::jsi;
+
+namespace facebook {
+namespace react {
+
+JSINativeModules::JSINativeModules(
+ std::shared_ptr<ModuleRegistry> moduleRegistry)
+ : m_moduleRegistry(std::move(moduleRegistry)) {}
+
+Value JSINativeModules::getModule(Runtime& rt, const PropNameID& name) {
+ if (!m_moduleRegistry) {
+ return nullptr;
+ }
+
+ std::string moduleName = name.utf8(rt);
+
+ const auto it = m_objects.find(moduleName);
+ if (it != m_objects.end()) {
+ return Value(rt, it->second);
+ }
+
+ auto module = createModule(rt, moduleName);
+ if (!module.hasValue()) {
+ // Allow lookup to continue in the objects own properties, which allows for
+ // overrides of NativeModules
+ return nullptr;
+ }
+
+ auto result =
+ m_objects.emplace(std::move(moduleName), std::move(*module)).first;
+ return Value(rt, result->second);
+}
+
+void JSINativeModules::reset() {
+ m_genNativeModuleJS = folly::none;
+ m_objects.clear();
+}
+
+folly::Optional<Object> JSINativeModules::createModule(
+ Runtime& rt,
+ const std::string& name) {
+ bool hasLogger(ReactMarker::logTaggedMarker);
+ if (hasLogger) {
+ ReactMarker::logTaggedMarker(
+ ReactMarker::NATIVE_MODULE_SETUP_START, name.c_str());
+ }
+
+ if (!m_genNativeModuleJS) {
+ m_genNativeModuleJS =
+ rt.global().getPropertyAsFunction(rt, "__fbGenNativeModule");
+ }
+
+ auto result = m_moduleRegistry->getConfig(name);
+ if (!result.hasValue()) {
+ return folly::none;
+ }
+
+ Value moduleInfo = m_genNativeModuleJS->call(
+ rt,
+ valueFromDynamic(rt, result->config),
+ static_cast<double>(result->index));
+ CHECK(!moduleInfo.isNull()) << "Module returned from genNativeModule is null";
+
+ folly::Optional<Object> module(
+ moduleInfo.asObject(rt).getPropertyAsObject(rt, "module"));
+
+ if (hasLogger) {
+ ReactMarker::logTaggedMarker(
+ ReactMarker::NATIVE_MODULE_SETUP_STOP, name.c_str());
+ }
+
+ return module;
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/jsiexecutor/jsireact/JSINativeModules.h

@@ -0,0 +1,38 @@
+// 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.
+
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include <cxxreact/ModuleRegistry.h>
+#include <folly/Optional.h>
+#include <jsi/jsi.h>
+
+namespace facebook {
+namespace react {
+
+/**
+ * Holds and creates JS representations of the modules in ModuleRegistry
+ */
+class JSINativeModules {
+ public:
+ explicit JSINativeModules(std::shared_ptr<ModuleRegistry> moduleRegistry);
+ jsi::Value getModule(jsi::Runtime& rt, const jsi::PropNameID& name);
+ void reset();
+
+ private:
+ folly::Optional<jsi::Function> m_genNativeModuleJS;
+ std::shared_ptr<ModuleRegistry> m_moduleRegistry;
+ std::unordered_map<std::string, jsi::Object> m_objects;
+
+ folly::Optional<jsi::Object> createModule(
+ jsi::Runtime& rt,
+ const std::string& name);
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/jsinspector/Android.mk

@@ -1,11 +1,15 @@
+# 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.
+
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := jsinspector
-LOCAL_SRC_FILES := \
- InspectorInterfaces.cpp
+LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/..
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)

ReactCommon/jsinspector/BUCK

@@ -1,4 +1,4 @@
-load("@xplat//tools/build_defs:glob_defs.bzl", "subdir_glob")
+load("@fbsource//tools/build_defs:glob_defs.bzl", "subdir_glob")
load("//tools/build_defs/oss:rn_defs.bzl", "rn_xplat_cxx_library")
EXPORTED_HEADERS = [

ReactCommon/jsinspector/InspectorInterfaces.cpp

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.

ReactCommon/jsinspector/InspectorInterfaces.h

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2016-present, Facebook, Inc.
+ * 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.

ReactCommon/microprofiler/MicroProfiler.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.
@@ -6,6 +6,7 @@
#include <algorithm>
#include <chrono>
#include <mutex>
+#include <sstream>
#include <vector>
#include <time.h>
@@ -17,7 +18,7 @@
// we can get rid of this
#if defined(__APPLE__)
#define MICRO_PROFILER_STUB_IMPLEMENTATION 1
-#else
+#elif !defined(MICRO_PROFILER_STUB_IMPLEMENTATION)
#define MICRO_PROFILER_STUB_IMPLEMENTATION 0
#endif

ReactCommon/microprofiler/MicroProfiler.h

@@ -1,4 +1,4 @@
-// Copyright (c) 2004-present, Facebook, Inc.
+// 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.

ReactCommon/privatedata/Android.mk

@@ -1,18 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := privatedata
-
-LOCAL_SRC_FILES := \
- PrivateDataBase.cpp \
-
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/..
-LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
-
-LOCAL_CFLAGS := \
- -DLOG_TAG=\"ReactNative\"
-
-LOCAL_CFLAGS += -fexceptions -frtti
-
-include $(BUILD_SHARED_LIBRARY)

ReactCommon/privatedata/BUCK

@@ -1,24 +0,0 @@
-load("@xplat//tools/build_defs:glob_defs.bzl", "subdir_glob")
-load("//tools/build_defs/oss:rn_defs.bzl", "rn_xplat_cxx_library")
-
-rn_xplat_cxx_library(
- name = "privatedata",
- srcs = glob(["**/*.cpp"]),
- header_namespace = "",
- exported_headers = subdir_glob(
- [
- ("", "**/*.h"),
- ],
- prefix = "privatedata",
- ),
- compiler_flags = [
- "-Wall",
- "-fexceptions",
- "-frtti",
- "-fvisibility=hidden",
- "-std=c++1y",
- ],
- visibility = [
- "PUBLIC",
- ],
-)

ReactCommon/privatedata/PrivateDataBase.cpp

@@ -1,13 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#include "PrivateDataBase.h"
-
-namespace facebook {
-namespace react {
-
-PrivateDataBase::~PrivateDataBase() {}
-
-} }

ReactCommon/privatedata/PrivateDataBase.h

@@ -1,45 +0,0 @@
-// Copyright (c) 2004-present, Facebook, Inc.
-
-// This source code is licensed under the MIT license found in the
-// LICENSE file in the root directory of this source tree.
-
-#pragma once
-
-#include <cassert>
-#include <cstdlib>
-#include <type_traits>
-
-#ifndef RN_EXPORT
-#define RN_EXPORT __attribute__((visibility("default")))
-#endif
-
-namespace facebook {
-namespace react {
-
-// Base class for private data used to implement hybrid JS-native objects. A common root class,
-// rtti and dynamic_cast allow us to do some runtime type checking that makes it possible
-// for multiple hybrid object implementations to co-exist.
-class RN_EXPORT PrivateDataBase {
- public:
- virtual ~PrivateDataBase();
-
- // Casts given void* to PrivateDataBase and performs dynamic_cast to desired type. Returns null on
- // failure.
- template <typename T>
- static typename std::enable_if<std::is_base_of<PrivateDataBase, T>::value, T>::type* tryCast(void* ptr) {
- return dynamic_cast<T*>(reinterpret_cast<PrivateDataBase*>(ptr));
- }
-
- // Like tryCast, but aborts on failure.
- template <typename T>
- static typename std::enable_if<std::is_base_of<PrivateDataBase, T>::value, T>::type* cast(void* ptr) {
- auto result = tryCast<T>(ptr);
- if (!result) {
- assert(false && "could not cast to desired type");
- abort();
- }
- return result;
- }
-};
-
-} }

ReactCommon/turbomodule/core/BUCK

@@ -0,0 +1,83 @@
+load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "OBJC_ARC_PREPROCESSOR_FLAGS", "get_debug_preprocessor_flags", "get_static_library_ios_flags")
+load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", "react_native_target", "react_native_xplat_target", "rn_xplat_cxx_library", "subdir_glob")
+
+rn_xplat_cxx_library(
+ name = "core",
+ srcs = glob(["*.cpp"]),
+ header_namespace = "",
+ exported_headers = subdir_glob(
+ [
+ ("", "*.h"),
+ ],
+ prefix = "jsireact",
+ ),
+ compiler_flags = [
+ "-fexceptions",
+ "-frtti",
+ "-std=c++14",
+ "-Wall",
+ ],
+ fbandroid_deps = [
+ react_native_target("jni/react/jni:jni"),
+ ],
+ fbandroid_exported_headers = subdir_glob(
+ [
+ ("platform/android", "*.h"),
+ ],
+ prefix = "jsireact",
+ ),
+ fbandroid_srcs = glob(
+ [
+ "platform/android/**/*.cpp",
+ ],
+ ),
+ fbobjc_compiler_flags = [
+ "-Wall",
+ "-fobjc-arc-exceptions",
+ ],
+ fbobjc_inherited_buck_flags = get_static_library_ios_flags(),
+ fbobjc_preprocessor_flags = OBJC_ARC_PREPROCESSOR_FLAGS + get_debug_preprocessor_flags(),
+ force_static = True,
+ ios_deps = [
+ "xplat//FBBaseLite:FBBaseLite",
+ "xplat//js/react-native-github:RCTCxxBridge",
+ "xplat//js/react-native-github:RCTCxxModule",
+ "xplat//js/react-native-github:ReactInternal",
+ ],
+ ios_exported_headers = subdir_glob(
+ [
+ ("platform/ios", "*.h"),
+ ],
+ prefix = "jsireact",
+ ),
+ ios_frameworks = [
+ "$SDKROOT/System/Library/Frameworks/Foundation.framework",
+ ],
+ ios_srcs = glob(
+ [
+ "platform/ios/**/*.cpp",
+ "platform/ios/**/*.mm",
+ ],
+ ),
+ platforms = (ANDROID, APPLE),
+ preprocessor_flags = [
+ "-DLOG_TAG=\"ReactNative\"",
+ "-DWITH_FBSYSTRACE=1",
+ ],
+ visibility = [
+ "PUBLIC",
+ ],
+ deps = [
+ "xplat//fbsystrace:fbsystrace",
+ "xplat//folly:headers_only",
+ "xplat//folly:memory",
+ "xplat//folly:molly",
+ "xplat//jsi:JSIDynamic",
+ "xplat//third-party/glog:glog",
+ react_native_xplat_target("cxxreact:bridge"),
+ react_native_xplat_target("cxxreact:module"),
+ ],
+ exported_deps = [
+ "xplat//jsi:jsi",
+ ],
+)

ReactCommon/turbomodule/core/JSCallInvoker.cpp

@@ -0,0 +1,27 @@
+/**
+ * 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.
+ */
+
+#include "JSCallInvoker.h"
+
+#include <cxxreact/MessageQueueThread.h>
+
+namespace facebook {
+namespace react {
+
+JSCallInvoker::JSCallInvoker(std::shared_ptr<MessageQueueThread> jsThread)
+ : jsThread_(jsThread) {}
+
+void JSCallInvoker::invokeAsync(std::function<void()>&& func) {
+ jsThread_->runOnQueue(std::move(func));
+}
+
+void JSCallInvoker::invokeSync(std::function<void()>&& func) {
+ jsThread_->runOnQueueSync(std::move(func));
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/turbomodule/core/JSCallInvoker.h

@@ -0,0 +1,38 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <functional>
+#include <memory>
+
+namespace facebook {
+namespace react {
+
+class MessageQueueThread;
+
+/**
+ * A generic native-to-JS call invoker. It guarantees that any calls from any
+ * thread are queued on the right JS thread.
+ *
+ * For now, this is a thin-wrapper around existing MessageQueueThread. Eventually,
+ * it should be consolidated with Fabric implementation so there's only one
+ * API to call JS from native, whether synchronously or asynchronously.
+ */
+class JSCallInvoker {
+public:
+ JSCallInvoker(std::shared_ptr<MessageQueueThread> jsThread);
+
+ void invokeAsync(std::function<void()>&& func);
+ void invokeSync(std::function<void()>&& func);
+
+private:
+ std::shared_ptr<MessageQueueThread> jsThread_;
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/turbomodule/core/LongLivedObject.cpp

@@ -0,0 +1,49 @@
+/**
+ * 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.
+ */
+
+#include "LongLivedObject.h"
+
+namespace facebook {
+namespace react {
+
+// LongLivedObjectCollection
+LongLivedObjectCollection& LongLivedObjectCollection::get() {
+ static LongLivedObjectCollection instance;
+ return instance;
+}
+
+LongLivedObjectCollection::LongLivedObjectCollection() {}
+
+void LongLivedObjectCollection::add(std::shared_ptr<LongLivedObject> so) {
+ collection_.insert(so);
+}
+
+void LongLivedObjectCollection::remove(const LongLivedObject *o) {
+ auto p = collection_.begin();
+ for (; p != collection_.end(); p++) {
+ if (p->get() == o) {
+ break;
+ }
+ }
+ if (p != collection_.end()) {
+ collection_.erase(p);
+ }
+}
+
+void LongLivedObjectCollection::clear() {
+ collection_.clear();
+}
+
+// LongLivedObject
+LongLivedObject::LongLivedObject() {}
+
+void LongLivedObject::allowRelease() {
+ LongLivedObjectCollection::get().remove(this);
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/turbomodule/core/LongLivedObject.h

@@ -0,0 +1,52 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <unordered_set>
+
+namespace facebook {
+namespace react {
+
+/**
+ * A simple wrapper class that can be registered to a collection that keep it alive for extended period of time.
+ * This object can be removed from the collection when needed.
+ *
+ * The subclass of this class must be created using std::make_shared<T>().
+ * After creation, add it to the `LongLivedObjectCollection`.
+ * When done with the object, call `allowRelease()` to allow the OS to release it.
+ */
+class LongLivedObject {
+public:
+ void allowRelease();
+
+protected:
+ LongLivedObject();
+};
+
+/**
+ * A singleton collection for the `LongLivedObject`s.
+ */
+class LongLivedObjectCollection {
+public:
+ static LongLivedObjectCollection& get();
+
+ LongLivedObjectCollection(LongLivedObjectCollection const&) = delete;
+ void operator=(LongLivedObjectCollection const&) = delete;
+
+ void add(std::shared_ptr<LongLivedObject> o);
+ void remove(const LongLivedObject *o);
+ void clear();
+
+private:
+ LongLivedObjectCollection();
+ std::unordered_set<std::shared_ptr<LongLivedObject>> collection_;
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/turbomodule/core/platform/android/JavaTurboModule.cpp

@@ -0,0 +1,199 @@
+/**
+ * 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.
+ */
+
+#include <memory>
+#include <string>
+
+#include <fb/fbjni.h>
+#include <jsi/jsi.h>
+
+#include <jsireact/TurboModule.h>
+#import <jsireact/TurboModuleUtils.h>
+
+#include <jsi/JSIDynamic.h>
+#include <react/jni/ReadableNativeMap.h>
+#include <react/jni/WritableNativeMap.h>
+#include <react/jni/NativeMap.h>
+#include <react/jni/JCallback.h>
+
+#include "JavaTurboModule.h"
+
+namespace facebook {
+namespace react {
+
+JavaTurboModule::JavaTurboModule(const std::string &name, jni::global_ref<JTurboModule> instance, std::shared_ptr<JSCallInvoker> jsInvoker)
+ : TurboModule(name, jsInvoker), instance_(instance) {}
+
+// fnjni already does this conversion, but since we are using plain JNI, this needs to be done again
+// TODO (axe) Reuse existing implementation as needed - the exist in MethodInvoker.cpp
+// TODO (axe) If at runtime, JS sends incorrect arguments and this is not typechecked, conversion here will fail. Check for that case (OSS)
+std::unique_ptr<jvalue[]> convertFromJValueArgsToJNIArgs(
+ JNIEnv *env,
+ jsi::Runtime &rt,
+ const jsi::Value *args,
+ size_t count,
+ std::shared_ptr<JSCallInvoker> jsInvoker
+ ) {
+ auto jargs = std::make_unique<jvalue[]>(count);
+ for (size_t i = 0; i < count; i++) {
+ const jsi::Value *arg = &args[i];
+ if (arg->isBool()) {
+ jargs[i].z = arg->getBool();
+ } else if (arg->isNumber()) {
+ jargs[i].d = arg->getNumber();
+ } else if (arg->isNull() || arg->isUndefined()) {
+ // What happens if Java is expecting a bool or a number, and JS sends a null or undefined?
+ jargs[i].l = nullptr;
+ } else if (arg->isString()) {
+ // We are basically creating a whole new string here
+ // TODO (axe) Is there a way to copy this instead of creating a whole new string ?
+ jargs[i].l = env->NewStringUTF(arg->getString(rt).utf8(rt).c_str());
+ } else if (arg->isObject()) {
+ auto objectArg = arg->getObject(rt);
+ // We are currently using folly:dynamic to convert JSON to Writable Map
+ // TODO (axe) Don't use folly:dynamic, instead construct Java map directly
+ if (objectArg.isArray(rt)) {
+ auto dynamicFromValue = jsi::dynamicFromValue(rt, args[i]);
+ auto jParams = ReadableNativeArray::newObjectCxxArgs(std::move(dynamicFromValue));
+ jargs[i].l = jParams.release();
+ } else if (objectArg.isFunction(rt)) {
+ auto wrapper = std::make_shared<react::CallbackWrapper>(objectArg.getFunction(rt), rt, jsInvoker);
+ std::function<void(folly::dynamic)> fn = [wrapper](folly::dynamic responses){
+ if (wrapper == nullptr) {
+ throw std::runtime_error("callback arg cannot be called more than once");
+ }
+ std::shared_ptr<react::CallbackWrapper> rw = wrapper;
+ wrapper->jsInvoker->invokeAsync([rw, responses]() {
+ // TODO (axe) valueFromDynamic already returns a Value array. Don't iterate again
+ jsi::Value args = jsi::valueFromDynamic(rw->runtime, responses);
+ auto argsArray = args.getObject(rw->runtime).asArray(rw->runtime);
+ std::vector<jsi::Value> result;
+ for (size_t i = 0; i < argsArray.size(rw->runtime); i++) {
+ result.emplace_back(rw->runtime, argsArray.getValueAtIndex(rw->runtime, i));
+ }
+ rw->callback.call(rw->runtime, (const jsi::Value *)result.data(), result.size());
+ });
+ };
+ wrapper = nullptr;
+ // TODO Use our own implementation of callback instead of relying on JCxxCallbackImpl
+ auto callback = JCxxCallbackImpl::newObjectCxxArgs(fn);
+ jargs[i].l = callback.release();
+ } else {
+ auto dynamicFromValue = jsi::dynamicFromValue(rt, args[i]);
+ auto jParams = ReadableNativeMap::createWithContents(std::move(dynamicFromValue));
+ jargs[i].l = jParams.release();
+ }
+ }
+ }
+ return jargs;
+}
+
+jsi::Value convertFromJMapToValue(JNIEnv *env, jsi::Runtime &rt, jobject arg) {
+ // We currently use Java Argument.makeNativeMap() method to do this conversion
+ // This could also be done purely in C++, but iterative over map methods
+ // but those may end up calling reflection methods anyway
+ // TODO (axe) Investigate the best way to convert Java Map to Value
+ static jclass jArguments = env->FindClass("com/facebook/react/bridge/Arguments");
+ static jmethodID jMakeNativeMap = env->GetStaticMethodID(jArguments, "makeNativeMap", "(Ljava/util/Map;)Lcom/facebook/react/bridge/WritableNativeMap;");
+ auto constants = (jobject) env->CallStaticObjectMethod(jArguments, jMakeNativeMap, arg);
+ auto jResult = jni::adopt_local(constants);
+ auto result = jni::static_ref_cast<NativeMap::jhybridobject>(jResult);
+ return jsi::valueFromDynamic(rt, result->cthis()->consume());
+}
+
+jsi::Value JavaTurboModule::get(jsi::Runtime& runtime, const jsi::PropNameID& propName) {
+ std::string propNameUtf8 = propName.utf8(runtime);
+ if (propNameUtf8 == "getConstants") {
+ // This is the special method to get the constants from the module.
+ // Since `getConstants` in Java only returns a Map, this function takes the map
+ // and converts it to a WritableMap.
+ return jsi::Function::createFromHostFunction(
+ runtime,
+ propName,
+ 0,
+ [this](jsi::Runtime &rt, const jsi::Value &thisVal, const jsi::Value *args, size_t count) {
+ JNIEnv *env = jni::Environment::current();
+ jclass cls = env->FindClass(jClassName_.c_str());
+ static jmethodID methodID = env->GetMethodID(cls, "getConstants", "()Ljava/util/Map;");
+ auto constantsMap = (jobject) env->CallObjectMethod(instance_.get(), methodID);
+ if (constantsMap == nullptr) {
+ return jsi::Value::undefined();
+ }
+ return convertFromJMapToValue(env, rt, constantsMap);
+ }
+ );
+ } else {
+ return TurboModule::get(runtime, propName);
+ }
+}
+
+jsi::Value JavaTurboModule::invokeJavaMethod(
+ jsi::Runtime &rt,
+ TurboModuleMethodValueKind valueKind,
+ const std::string &methodName,
+ const std::string &methodSignature,
+ const jsi::Value *args,
+ size_t count) {
+
+ // We are using JNI directly instead of fbjni since we don't want template functiosn
+ // when finding methods.
+ JNIEnv *env = jni::Environment::current();
+ // TODO (axe) Memoize this class, so that we don't have to find it for every calls
+ jclass cls = env->FindClass(jClassName_.c_str());
+
+ // TODO (axe) Memoize method call, so we don't look it up each time the method is called
+ jmethodID methodID = env->GetMethodID(cls, methodName.c_str(), methodSignature.c_str());
+
+ std::unique_ptr<jvalue[]>jargs = convertFromJValueArgsToJNIArgs(env, rt, args, count, jsInvoker_);
+ auto instance = instance_.get();
+
+ switch (valueKind) {
+ case VoidKind: {
+ env->CallVoidMethodA(instance, methodID, jargs.get());
+ return jsi::Value::undefined();
+ }
+ case BooleanKind: {
+ return jsi::Value((bool)env->CallBooleanMethodA(instance, methodID, jargs.get()));
+ }
+ case NumberKind: {
+ return jsi::Value((double)env->CallDoubleMethodA(instance, methodID, jargs.get()));
+ }
+ case StringKind: {
+ auto returnString = (jstring) env->CallObjectMethodA(instance, methodID, jargs.get());
+ if (returnString == nullptr) {
+ return jsi::Value::null();
+ }
+ const char *js = env->GetStringUTFChars(returnString, nullptr);
+ std::string result = js;
+ env->ReleaseStringUTFChars(returnString, js);
+ return jsi::Value(rt, jsi::String::createFromUtf8(rt, result));
+ }
+ case ObjectKind: {
+ auto returnObject = (jobject) env->CallObjectMethodA(instance, methodID, jargs.get());
+ if (returnObject == nullptr) {
+ return jsi::Value::null();
+ }
+ auto jResult = jni::adopt_local(returnObject);
+ auto result = jni::static_ref_cast<NativeMap::jhybridobject>(jResult);
+ return jsi::valueFromDynamic(rt, result->cthis()->consume());
+ }
+ case ArrayKind: {
+ auto returnObject = (jobject) env->CallObjectMethodA(instance, methodID, jargs.get());
+ if (returnObject == nullptr) {
+ return jsi::Value::null();
+ }
+ auto jResult = jni::adopt_local(returnObject);
+ auto result = jni::static_ref_cast<NativeArray::jhybridobject>(jResult);
+ return jsi::valueFromDynamic(rt, result->cthis()->consume());
+ }
+ default:
+ throw std::runtime_error("Unable to find method module: " + methodName + "(" + methodSignature + ")" + "in module " + jClassName_);
+ }
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/turbomodule/core/platform/android/JavaTurboModule.h

@@ -0,0 +1,45 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <fb/fbjni.h>
+#include <jsi/jsi.h>
+#include <jsireact/TurboModule.h>
+
+namespace facebook {
+namespace react {
+
+struct JTurboModule : jni::JavaClass<JTurboModule> {
+ static auto constexpr kJavaDescriptor = "Lcom/facebook/react/turbomodule/core/interfaces/TurboModule;";
+};
+
+class JSI_EXPORT JavaTurboModule : public TurboModule {
+public:
+ JavaTurboModule(const std::string &name, jni::global_ref<JTurboModule> instance, std::shared_ptr<JSCallInvoker> jsInvoker);
+ jsi::Value invokeJavaMethod(
+ jsi::Runtime &runtime,
+ TurboModuleMethodValueKind valueKind,
+ const std::string &methodName,
+ const std::string &methodSignature,
+ const jsi::Value *args,
+ size_t count);
+
+ virtual facebook::jsi::Value get(facebook::jsi::Runtime& runtime, const facebook::jsi::PropNameID& propName) override;
+
+protected:
+ // TODO (axe) Specify class name as kJavaDescriptor instead of a class variable
+ std::string jClassName_;
+private:
+ jni::global_ref<JTurboModule> instance_;
+ jclass findClass(JNIEnv *env) const;
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/turbomodule/core/platform/ios/RCTTurboModule.h

@@ -0,0 +1,66 @@
+/**
+ * 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.
+ */
+
+#import <memory>
+
+#import <Foundation/Foundation.h>
+
+#import <React/RCTBridge.h>
+#import <React/RCTBridgeModule.h>
+#import <cxxreact/MessageQueueThread.h>
+#import <jsireact/JSCallInvoker.h>
+#import <jsireact/TurboModule.h>
+
+#define RCT_IS_TURBO_MODULE_CLASS(klass) ((RCTTurboModuleEnabled() && [(klass) conformsToProtocol:@protocol(RCTTurboModule)]))
+#define RCT_IS_TURBO_MODULE_INSTANCE(module) RCT_IS_TURBO_MODULE_CLASS([(module) class])
+
+namespace facebook {
+namespace react {
+
+/**
+ * ObjC++ specific TurboModule base class.
+ */
+class JSI_EXPORT ObjCTurboModule : public TurboModule {
+public:
+ ObjCTurboModule(const std::string &name, id<RCTTurboModule> instance, std::shared_ptr<JSCallInvoker> jsInvoker);
+
+ virtual jsi::Value invokeMethod(
+ jsi::Runtime &runtime,
+ TurboModuleMethodValueKind valueKind,
+ const std::string &methodName,
+ const jsi::Value *args,
+ size_t count) override;
+
+ id<RCTTurboModule> instance_;
+};
+
+} // namespace react
+} // namespace facebook
+
+@protocol RCTTurboModule <NSObject>
+@optional
+/**
+ * Used by TurboModules to get access to other TurboModules.
+ *
+ * Usage:
+ * Place `@synthesize turboModuleLookupDelegate = _turboModuleLookupDelegate`
+ * in the @implementation section of your TurboModule.
+ */
+@property (nonatomic, weak) id<RCTTurboModuleLookupDelegate> turboModuleLookupDelegate;
+
+@optional
+// This should be required, after migration is done.
+- (std::shared_ptr<facebook::react::TurboModule>)getTurboModuleWithJsInvoker:(std::shared_ptr<facebook::react::JSCallInvoker>)jsInvoker;
+
+@end
+
+// TODO: Consolidate this extension with the one in RCTSurfacePresenter.
+@interface RCTBridge ()
+
+- (std::shared_ptr<facebook::react::MessageQueueThread>)jsMessageThread;
+
+@end

ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.h

@@ -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.
+ */
+
+#import "RCTTurboModule.h"
+
+@protocol RCTTurboModuleManagerDelegate <NSObject>
+
+// TODO: Move to xplat codegen.
+- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
+ instance:(id<RCTTurboModule>)instance
+ jsInvoker:(std::shared_ptr<facebook::react::JSCallInvoker>)jsInvoker;
+
+@optional
+
+/**
+ * Given a module name, return its actual class. If not provided, basic ObjC class lookup is performed.
+ */
+- (Class)getModuleClassFromName:(const char *)name;
+
+/**
+ * Given a module class, provide an instance for it. If not provided, default initializer is used.
+ */
+- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass;
+
+/**
+ * Create an instance of a TurboModule without relying on any ObjC++ module instance.
+ */
+- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
+ jsInvoker:(std::shared_ptr<facebook::react::JSCallInvoker>)jsInvoker;
+
+@end
+
+@interface RCTTurboModuleManager : NSObject<RCTTurboModuleLookupDelegate>
+
+- (instancetype)initWithRuntime:(facebook::jsi::Runtime *)runtime
+ bridge:(RCTBridge *)bridge
+ delegate:(id<RCTTurboModuleManagerDelegate>)delegate;
+
+- (void)installJSBinding;
+
+- (std::shared_ptr<facebook::react::TurboModule>)getModule:(const std::string &)name;
+
+@end

ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm

@@ -0,0 +1,274 @@
+/**
+ * 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.
+ */
+
+#import "RCTTurboModuleManager.h"
+
+#import <cassert>
+
+#import <React/RCTBridgeModule.h>
+#import <React/RCTCxxModule.h>
+#import <React/RCTLog.h>
+#import <jsireact/TurboCxxModule.h>
+#import <jsireact/TurboModuleBinding.h>
+
+using namespace facebook;
+
+// Fallback lookup since RCT class prefix is sometimes stripped in the existing NativeModule system.
+// This will be removed in the future.
+static Class getFallbackClassFromName(const char *name) {
+ Class moduleClass = NSClassFromString([NSString stringWithUTF8String:name]);
+ if (!moduleClass) {
+ moduleClass = NSClassFromString([NSString stringWithFormat:@"RCT%s", name]);
+ }
+ return moduleClass;
+}
+
+@implementation RCTTurboModuleManager
+{
+ jsi::Runtime *_runtime;
+ std::shared_ptr<facebook::react::JSCallInvoker> _jsInvoker;
+ std::shared_ptr<react::TurboModuleBinding> _binding;
+ __weak id<RCTTurboModuleManagerDelegate> _delegate;
+ __weak RCTBridge *_bridge;
+ /**
+ * TODO(rsnara):
+ * All modules are currently long-lived.
+ * We need to come up with a mechanism to allow modules to specify whether
+ * they want to be long-lived or short-lived.
+ */
+ std::unordered_map<std::string, id<RCTTurboModule>> _rctTurboModuleCache;
+ std::unordered_map<std::string, std::shared_ptr<react::TurboModule>> _turboModuleCache;
+}
+
+- (instancetype)initWithRuntime:(jsi::Runtime *)runtime
+ bridge:(RCTBridge *)bridge
+ delegate:(id<RCTTurboModuleManagerDelegate>)delegate
+{
+ if (self = [super init]) {
+ _runtime = runtime;
+ _jsInvoker = std::make_shared<react::JSCallInvoker>(bridge.jsMessageThread);
+ _delegate = delegate;
+ _bridge = bridge;
+
+ // Necessary to allow NativeModules to lookup TurboModules
+ [bridge setRCTTurboModuleLookupDelegate:self];
+
+ __weak __typeof(self) weakSelf = self;
+
+ auto moduleProvider = [weakSelf](const std::string &name) -> std::shared_ptr<react::TurboModule> {
+ if (!weakSelf) {
+ return nullptr;
+ }
+
+ __strong __typeof(self) strongSelf = weakSelf;
+
+ /**
+ * By default, all TurboModules are long-lived.
+ * Additionally, if a TurboModule with the name `name` isn't found, then we
+ * trigger an assertion failure.
+ */
+ return [strongSelf provideTurboModule: name.c_str()];
+ };
+
+ _binding = std::make_shared<react::TurboModuleBinding>(moduleProvider);
+ }
+ return self;
+}
+
+/**
+ * Given a name for a TurboModule, return a C++ object which is the instance
+ * of that TurboModule C++ class. This class wraps the TurboModule's ObjC instance.
+ * If no TurboModule ObjC class exist with the provided name, abort program.
+ *
+ * Note: All TurboModule instances are cached, which means they're all long-lived
+ * (for now).
+ */
+
+- (std::shared_ptr<react::TurboModule>)provideTurboModule:(const char*)moduleName
+{
+ auto turboModuleLookup = _turboModuleCache.find(moduleName);
+ if (turboModuleLookup != _turboModuleCache.end()) {
+ return turboModuleLookup->second;
+ }
+
+ /**
+ * Step 1: Look for pure C++ modules.
+ * Pure C++ modules get priority.
+ */
+ if ([_delegate respondsToSelector:@selector(getTurboModule:jsInvoker:)]) {
+ auto turboModule = [_delegate getTurboModule:moduleName jsInvoker:_jsInvoker];
+ if (turboModule != nullptr) {
+ _turboModuleCache.insert({moduleName, turboModule});
+ return turboModule;
+ }
+ }
+
+ /**
+ * Step 2: Look for platform-specific modules.
+ */
+ id<RCTTurboModule> module = [self provideRCTTurboModule:moduleName];
+
+ // If we request that a TurboModule be created, its respective ObjC class must exist
+ // If the class doesn't exist, then provideRCTTurboModule returns nil
+ if (!module) {
+ return nullptr;
+ }
+
+ Class moduleClass = [module class];
+
+ // If RCTTurboModule supports creating its own C++ TurboModule object,
+ // allow it to do so.
+ if ([module respondsToSelector:@selector(getTurboModuleWithJsInvoker:)]) {
+ auto turboModule = [module getTurboModuleWithJsInvoker:_jsInvoker];
+ assert(turboModule != nullptr);
+ _turboModuleCache.insert({moduleName, turboModule});
+ return turboModule;
+ }
+
+ /**
+ * Step 2c: If the moduleClass is a legacy CxxModule, return a TurboCxxModule instance that
+ * wraps CxxModule.
+ */
+ if ([moduleClass isSubclassOfClass:RCTCxxModule.class]) {
+ // Use TurboCxxModule compat class to wrap the CxxModule instance.
+ // This is only for migration convenience, despite less performant.
+ auto turboModule = std::make_shared<react::TurboCxxModule>([((RCTCxxModule *)module) createModule], _jsInvoker);
+ _turboModuleCache.insert({moduleName, turboModule});
+ return turboModule;
+ }
+
+ /**
+ * Step 2d: Return an exact sub-class of ObjC TurboModule
+ */
+ auto turboModule = [_delegate getTurboModule:moduleName instance:module jsInvoker:_jsInvoker];
+ if (turboModule != nullptr) {
+ _turboModuleCache.insert({moduleName, turboModule});
+ }
+ return turboModule;
+}
+
+/**
+ * Given a name for a TurboModule, return an ObjC object which is the instance
+ * of that TurboModule ObjC class. If no TurboModule exist with the provided name,
+ * return nil.
+ *
+ * Note: All TurboModule instances are cached, which means they're all long-lived
+ * (for now).
+ */
+- (id<RCTTurboModule>)provideRCTTurboModule:(const char*)moduleName
+{
+ auto rctTurboModuleCacheLookup = _rctTurboModuleCache.find(moduleName);
+ if (rctTurboModuleCacheLookup != _rctTurboModuleCache.end()) {
+ return rctTurboModuleCacheLookup->second;
+ }
+
+ /**
+ * Step 2a: Resolve platform-specific class.
+ */
+ Class moduleClass;
+ if ([_delegate respondsToSelector:@selector(getModuleClassFromName:)]) {
+ moduleClass = [_delegate getModuleClassFromName:moduleName];
+ } else {
+ moduleClass = getFallbackClassFromName(moduleName);
+ }
+
+ if (![moduleClass conformsToProtocol:@protocol(RCTTurboModule)]) {
+ return nil;
+ }
+
+ /**
+ * Step 2b: Ask hosting application/delegate to instantiate this class
+ */
+ id<RCTTurboModule> module = nil;
+ if ([_delegate respondsToSelector:@selector(getModuleInstanceFromClass:)]) {
+ module = [_delegate getModuleInstanceFromClass:moduleClass];
+ } else {
+ module = [moduleClass new];
+ }
+
+ /**
+ * It is reasonable for NativeModules to not want/need the bridge.
+ * In such cases, they won't have `@synthesize bridge = _bridge` in their
+ * implementation, and a `- (RCTBridge *) bridge { ... }` method won't be
+ * generated by the ObjC runtime. The property will also not be backed
+ * by an ivar, which makes writing to it unsafe. Therefore, we check if
+ * this method exists to know if we can safely set the bridge to the
+ * NativeModule.
+ */
+ if ([module respondsToSelector:@selector(bridge)] && _bridge) {
+ /**
+ * Just because a NativeModule has the `bridge` method, it doesn't mean
+ * that it has synthesized the bridge in its implementation. Therefore,
+ * we need to surround the code that sets the bridge to the NativeModule
+ * inside a try/catch. This catches the cases where the NativeModule
+ * author specifies a `bridge` method manually.
+ */
+ @try {
+ /**
+ * RCTBridgeModule declares the bridge property as readonly.
+ * Therefore, when authors of NativeModules synthesize the bridge
+ * via @synthesize bridge = bridge;, the ObjC runtime generates
+ * only a - (RCTBridge *) bridge: { ... } method. No setter is
+ * generated, so we have have to rely on the KVC API of ObjC to set
+ * the bridge property of these NativeModules.
+ */
+ [(id)module setValue:_bridge forKey:@"bridge"];
+ }
+ @catch (NSException *exception) {
+ RCTLogError(@"%@ has no setter or ivar for its bridge, which is not "
+ "permitted. You must either @synthesize the bridge property, "
+ "or provide your own setter method.", RCTBridgeModuleNameForClass(module));
+ }
+ }
+
+ if ([module respondsToSelector:@selector(setTurboModuleLookupDelegate:)]) {
+ [module setTurboModuleLookupDelegate:self];
+ }
+
+ _rctTurboModuleCache.insert({moduleName, module});
+ return module;
+}
+
+- (void)installJSBinding
+{
+ if (!_runtime) {
+ // jsi::Runtime doesn't exist when attached to Chrome debugger.
+ return;
+ }
+
+ react::TurboModuleBinding::install(*_runtime, _binding);
+}
+
+- (std::shared_ptr<facebook::react::TurboModule>)getModule:(const std::string &)name
+{
+ return _binding->getModule(name);
+}
+
+#pragma mark RCTTurboModuleLookupDelegate
+
+- (id)moduleForName:(const char *)moduleName
+{
+ return [self moduleForName:moduleName warnOnLookupFailure:YES];
+}
+
+- (id)moduleForName:(const char *)moduleName warnOnLookupFailure:(BOOL)warnOnLookupFailure
+{
+ id<RCTTurboModule> module = [self provideRCTTurboModule:moduleName];
+
+ if (warnOnLookupFailure && !module) {
+ RCTLogError(@"Unable to find module for %@", [NSString stringWithUTF8String:moduleName]);
+ }
+
+ return module;
+}
+
+- (BOOL)moduleIsInitialized:(const char *)moduleName
+{
+ return _rctTurboModuleCache.find(std::string(moduleName)) != _rctTurboModuleCache.end();
+}
+
+@end

ReactCommon/turbomodule/core/platform/ios/RCTTurboModule.mm

@@ -0,0 +1,468 @@
+/**
+ * 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.
+ */
+
+#import "RCTTurboModule.h"
+
+#import <objc/runtime.h>
+#import <sstream>
+#import <vector>
+
+#import <React/RCTBridgeModule.h>
+#import <React/RCTUtils.h>
+#import <jsireact/JSCallInvoker.h>
+#import <jsireact/LongLivedObject.h>
+#import <jsireact/TurboModule.h>
+#import <jsireact/TurboModuleUtils.h>
+
+using namespace facebook;
+
+/**
+ * All static helper functions are ObjC++ specific.
+ */
+static jsi::Value convertNSNumberToJSIBoolean(jsi::Runtime &runtime, NSNumber *value) {
+ return jsi::Value((bool)[value boolValue]);
+}
+
+static jsi::Value convertNSNumberToJSINumber(jsi::Runtime &runtime, NSNumber *value) {
+ return jsi::Value([value doubleValue]);
+}
+
+static jsi::String convertNSStringToJSIString(jsi::Runtime &runtime, NSString *value) {
+ return jsi::String::createFromUtf8(runtime, [value UTF8String] ?: "");
+}
+
+static jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value);
+static jsi::Object convertNSDictionaryToJSIObject(jsi::Runtime &runtime, NSDictionary *value) {
+ jsi::Object result = jsi::Object(runtime);
+ for (NSString *k in value) {
+ result.setProperty(runtime, [k UTF8String], convertObjCObjectToJSIValue(runtime, value[k]));
+ }
+ return result;
+}
+
+static jsi::Array convertNSArrayToJSIArray(jsi::Runtime &runtime, NSArray *value) {
+ jsi::Array result = jsi::Array(runtime, value.count);
+ for (size_t i = 0; i < value.count; i++) {
+ result.setValueAtIndex(runtime, i, convertObjCObjectToJSIValue(runtime, value[i]));
+ }
+ return result;
+}
+
+static std::vector<jsi::Value> convertNSArrayToStdVector(jsi::Runtime &runtime, NSArray *value) {
+ std::vector<jsi::Value> result;
+ for (size_t i = 0; i < value.count; i++) {
+ result.emplace_back(convertObjCObjectToJSIValue(runtime, value[i]));
+ }
+ return result;
+}
+
+static jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value) {
+ if ([value isKindOfClass:[NSString class]]) {
+ return convertNSStringToJSIString(runtime, (NSString *)value);
+ } else if ([value isKindOfClass:[NSNumber class]]) {
+ if ([value isKindOfClass:[@YES class]]) {
+ return convertNSNumberToJSIBoolean(runtime, (NSNumber *)value);
+ }
+ return convertNSNumberToJSINumber(runtime, (NSNumber *)value);
+ } else if ([value isKindOfClass:[NSDictionary class]]) {
+ return convertNSDictionaryToJSIObject(runtime, (NSDictionary *)value);
+ } else if ([value isKindOfClass:[NSArray class]]) {
+ return convertNSArrayToJSIArray(runtime, (NSArray *)value);
+ } else if (value == (id)kCFNull) {
+ return jsi::Value::null();
+ }
+ return jsi::Value::undefined();
+}
+
+static id convertJSIValueToObjCObject(jsi::Runtime &runtime, const jsi::Value &value, std::shared_ptr<react::JSCallInvoker> jsInvoker);
+static NSString *convertJSIStringToNSString(jsi::Runtime &runtime, const jsi::String &value) {
+ return [NSString stringWithUTF8String:value.utf8(runtime).c_str()];
+}
+
+static NSArray *convertJSIArrayToNSArray(jsi::Runtime &runtime, const jsi::Array &value, std::shared_ptr<react::JSCallInvoker> jsInvoker) {
+ size_t size = value.size(runtime);
+ NSMutableArray *result = [NSMutableArray new];
+ for (size_t i = 0; i < size; i++) {
+ [result addObject:convertJSIValueToObjCObject(runtime, value.getValueAtIndex(runtime, i), jsInvoker) ?: (id)kCFNull];
+ }
+ return [result copy];
+}
+
+static NSDictionary *convertJSIObjectToNSDictionary(jsi::Runtime &runtime, const jsi::Object &value, std::shared_ptr<react::JSCallInvoker> jsInvoker) {
+ jsi::Array propertyNames = value.getPropertyNames(runtime);
+ size_t size = propertyNames.size(runtime);
+ NSMutableDictionary *result = [NSMutableDictionary new];
+ for (size_t i = 0; i < size; i++) {
+ jsi::String name = propertyNames.getValueAtIndex(runtime, i).getString(runtime);
+ NSString *k = convertJSIStringToNSString(runtime, name);
+ id v = convertJSIValueToObjCObject(runtime, value.getProperty(runtime, name), jsInvoker) ?: (id)kCFNull;
+ result[k] = v;
+ }
+ return [result copy];
+}
+
+static RCTResponseSenderBlock convertJSIFunctionToCallback(jsi::Runtime &runtime, const jsi::Function &value, std::shared_ptr<react::JSCallInvoker> jsInvoker);
+static id convertJSIValueToObjCObject(jsi::Runtime &runtime, const jsi::Value &value, std::shared_ptr<react::JSCallInvoker> jsInvoker) {
+ if (value.isUndefined() || value.isNull()) {
+ return nil;
+ }
+ if (value.isBool()) {
+ return @(value.getBool());
+ }
+ if (value.isNumber()) {
+ return @(value.getNumber());
+ }
+ if (value.isString()) {
+ return convertJSIStringToNSString(runtime, value.getString(runtime));
+ }
+ if (value.isObject()) {
+ jsi::Object o = value.getObject(runtime);
+ if (o.isArray(runtime)) {
+ return convertJSIArrayToNSArray(runtime, o.getArray(runtime), jsInvoker);
+ }
+ if (o.isFunction(runtime)) {
+ return convertJSIFunctionToCallback(runtime, std::move(o.getFunction(runtime)), jsInvoker);
+ }
+ return convertJSIObjectToNSDictionary(runtime, o, jsInvoker);
+ }
+
+ throw std::runtime_error("Unsupported jsi::jsi::Value kind");
+}
+
+static RCTResponseSenderBlock convertJSIFunctionToCallback(jsi::Runtime &runtime, const jsi::Function &value, std::shared_ptr<react::JSCallInvoker> jsInvoker) {
+ __block auto wrapper = std::make_shared<react::CallbackWrapper>(value.getFunction(runtime), runtime, jsInvoker);
+ return ^(NSArray *responses) {
+ if (wrapper == nullptr) {
+ throw std::runtime_error("callback arg cannot be called more than once");
+ }
+
+ std::shared_ptr<react::CallbackWrapper> rw = wrapper;
+ wrapper->jsInvoker->invokeAsync([rw, responses]() {
+ std::vector<jsi::Value> args = convertNSArrayToStdVector(rw->runtime, responses);
+ rw->callback.call(rw->runtime, (const jsi::Value *)args.data(), args.size());
+ });
+
+ // The callback is single-use, so force release it here.
+ // Doing this also releases the jsi::jsi::Function early, since this block may not get released by ARC for a while,
+ // because the method invocation isn't guarded with @autoreleasepool.
+ wrapper = nullptr;
+ };
+}
+
+// Helper for creating Promise object.
+struct PromiseWrapper : public react::LongLivedObject {
+ static std::shared_ptr<PromiseWrapper> create(
+ jsi::Function resolve,
+ jsi::Function reject,
+ jsi::Runtime &runtime,
+ std::shared_ptr<react::JSCallInvoker> jsInvoker) {
+ auto instance = std::make_shared<PromiseWrapper>(std::move(resolve), std::move(reject), runtime, jsInvoker);
+ // This instance needs to live longer than the caller's scope, since the resolve/reject functions may not
+ // be called immediately. Doing so keeps it alive at least until resolve/reject is called, or when the
+ // collection is cleared (e.g. when JS reloads).
+ react::LongLivedObjectCollection::get().add(instance);
+ return instance;
+ }
+
+ PromiseWrapper(
+ jsi::Function resolve,
+ jsi::Function reject,
+ jsi::Runtime &runtime,
+ std::shared_ptr<react::JSCallInvoker> jsInvoker)
+ : resolveWrapper(std::make_shared<react::CallbackWrapper>(std::move(resolve), runtime, jsInvoker)),
+ rejectWrapper(std::make_shared<react::CallbackWrapper>(std::move(reject), runtime, jsInvoker)),
+ runtime(runtime),
+ jsInvoker(jsInvoker) {}
+
+ RCTPromiseResolveBlock resolveBlock() {
+ return ^(id result) {
+ if (resolveWrapper == nullptr) {
+ throw std::runtime_error("Promise resolve arg cannot be called more than once");
+ }
+
+ // Retain the resolveWrapper so that it stays alive inside the lambda.
+ std::shared_ptr<react::CallbackWrapper> retainedWrapper = resolveWrapper;
+ jsInvoker->invokeAsync([retainedWrapper, result]() {
+ jsi::Runtime &rt = retainedWrapper->runtime;
+ jsi::Value arg = convertObjCObjectToJSIValue(rt, result);
+ retainedWrapper->callback.call(rt, arg);
+ });
+
+ // Prevent future invocation of the same resolve() function.
+ cleanup();
+ };
+ }
+
+ RCTPromiseRejectBlock rejectBlock() {
+ return ^(NSString *code, NSString *message, NSError *error) {
+ // TODO: There is a chance `this` is no longer valid when this block executes.
+ if (rejectWrapper == nullptr) {
+ throw std::runtime_error("Promise reject arg cannot be called more than once");
+ }
+
+ // Retain the resolveWrapper so that it stays alive inside the lambda.
+ std::shared_ptr<react::CallbackWrapper> retainedWrapper = rejectWrapper;
+ NSDictionary *jsError = RCTJSErrorFromCodeMessageAndNSError(code, message, error);
+ jsInvoker->invokeAsync([retainedWrapper, jsError]() {
+ jsi::Runtime &rt = retainedWrapper->runtime;
+ jsi::Value arg = convertNSDictionaryToJSIObject(rt, jsError);
+ retainedWrapper->callback.call(rt, arg);
+ });
+
+ // Prevent future invocation of the same resolve() function.
+ cleanup();
+ };
+ }
+
+ void cleanup() {
+ resolveWrapper = nullptr;
+ rejectWrapper = nullptr;
+ allowRelease();
+ }
+
+ // CallbackWrapper is used here instead of just holding on the jsi jsi::Function in order to force release it after either
+ // the resolve() or the reject() is called. jsi jsi::Function does not support explicit releasing, so we need an extra
+ // mechanism to control that lifecycle.
+ std::shared_ptr<react::CallbackWrapper> resolveWrapper;
+ std::shared_ptr<react::CallbackWrapper> rejectWrapper;
+ jsi::Runtime &runtime;
+ std::shared_ptr<react::JSCallInvoker> jsInvoker;
+};
+
+using PromiseInvocationBlock = void (^)(jsi::Runtime& rt, std::shared_ptr<PromiseWrapper> wrapper);
+static jsi::Value createPromise(jsi::Runtime &runtime, std::shared_ptr<react::JSCallInvoker> jsInvoker, PromiseInvocationBlock invoke) {
+ if (!invoke) {
+ return jsi::Value::undefined();
+ }
+
+ jsi::Function Promise = runtime.global().getPropertyAsFunction(runtime, "Promise");
+
+ // Note: the passed invoke() block is not retained by default, so let's retain it here to help keep it longer.
+ // Otherwise, there's a risk of it getting released before the promise function below executes.
+ PromiseInvocationBlock invokeCopy = [invoke copy];
+ jsi::Function fn = jsi::Function::createFromHostFunction(
+ runtime,
+ jsi::PropNameID::forAscii(runtime, "fn"),
+ 2,
+ [invokeCopy, jsInvoker](jsi::Runtime &rt, const jsi::Value &thisVal, const jsi::Value *args, size_t count) {
+ if (count != 2) {
+ throw std::invalid_argument("Promise fn arg count must be 2");
+ }
+ if (!invokeCopy) {
+ return jsi::Value::undefined();
+ }
+ jsi::Function resolve = args[0].getObject(rt).getFunction(rt);
+ jsi::Function reject = args[1].getObject(rt).getFunction(rt);
+ auto wrapper = PromiseWrapper::create(std::move(resolve), std::move(reject), rt, jsInvoker);
+ invokeCopy(rt, wrapper);
+ return jsi::Value::undefined();
+ });
+
+ return Promise.callAsConstructor(runtime, fn);
+}
+
+namespace facebook {
+namespace react {
+
+namespace {
+
+SEL resolveMethodSelector(
+ TurboModuleMethodValueKind valueKind,
+ id<RCTTurboModule> module,
+ std::string moduleName,
+ std::string methodName,
+ size_t argCount) {
+ // Assume the instance is properly bound to the right class at this point.
+ SEL selector = nil;
+
+ // PromiseKind expects 2 additional function args for resolve() and reject()
+ size_t adjustedCount = valueKind == PromiseKind ? argCount + 2 : argCount;
+ NSString *baseMethodName = [NSString stringWithUTF8String:methodName.c_str()];
+
+ if (adjustedCount == 0) {
+ selector = NSSelectorFromString(baseMethodName);
+ if (![module respondsToSelector:selector]) {
+ throw std::runtime_error("Unable to find method: " + methodName + " for module: " + moduleName + ". Make sure the module is installed correctly.");
+ }
+ } else if (adjustedCount == 1) {
+ selector = NSSelectorFromString([NSString stringWithFormat:@"%@:", baseMethodName]);
+ if (![module respondsToSelector:selector]) {
+ throw std::runtime_error("Unable to find method: " + methodName + " for module: " + moduleName + ". Make sure the module is installed correctly.");
+ }
+ } else {
+ // TODO: This may be expensive lookup. The codegen output should specify the exact selector name.
+ unsigned int numberOfMethods;
+ Method *methods = class_copyMethodList([module class], &numberOfMethods);
+ if (methods) {
+ for (unsigned int i = 0; i < numberOfMethods; i++) {
+ SEL s = method_getName(methods[i]);
+ if ([NSStringFromSelector(s) hasPrefix:[NSString stringWithFormat:@"%@:", baseMethodName]]) {
+ selector = s;
+ break;
+ }
+ }
+ free(methods);
+ }
+ if (!selector) {
+ throw std::runtime_error("Unable to find method: " + methodName + " for module: " + moduleName + ". Make sure the module is installed correctly.");
+ }
+ }
+
+ return selector;
+}
+
+NSInvocation *getMethodInvocation(
+ jsi::Runtime &runtime,
+ TurboModuleMethodValueKind valueKind,
+ const id<RCTTurboModule> module,
+ std::shared_ptr<JSCallInvoker> jsInvoker,
+ SEL selector,
+ const jsi::Value *args,
+ size_t count) {
+ NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[[module class] instanceMethodSignatureForSelector:selector]];
+ [inv setSelector:selector];
+ for (size_t i = 0; i < count; i++) {
+ const jsi::Value *arg = &args[i];
+ if (arg->isBool()) {
+ bool v = arg->getBool();
+ [inv setArgument:(void *)&v atIndex:i + 2];
+ } else if (arg->isNumber()) {
+ double v = arg->getNumber();
+ [inv setArgument:(void *)&v atIndex:i + 2];
+ } else {
+ id v = convertJSIValueToObjCObject(runtime, *arg, jsInvoker);
+ [inv setArgument:(void *)&v atIndex:i + 2];
+ }
+ }
+ [inv retainArguments];
+ return inv;
+}
+
+/**
+ * Perform method invocation on a specific queue as configured by the module class.
+ * This serves as a backward-compatible support for RCTBridgeModule's methodQueue API.
+ *
+ * In the future:
+ * - This methodQueue support may be removed for simplicity and consistency with Android.
+ * - ObjC module methods will be always be called from JS thread.
+ * They may decide to dispatch to a different queue as needed.
+ */
+void performMethodInvocation(
+ jsi::Runtime &runtime,
+ NSInvocation *inv,
+ TurboModuleMethodValueKind valueKind,
+ const id<RCTTurboModule> module,
+ std::shared_ptr<JSCallInvoker> jsInvoker,
+ jsi::Value *result) {
+ *result = jsi::Value::undefined();
+ jsi::Runtime *rt = &runtime;
+ void (^block)() = ^{
+ [inv invokeWithTarget:module];
+
+ if (valueKind == VoidKind) {
+ return;
+ }
+
+ void *rawResult = NULL;
+ [inv getReturnValue:&rawResult];
+
+ // TODO: Re-use value conversion logic from existing impl, if possible.
+ switch (valueKind) {
+ case BooleanKind:
+ *result = convertNSNumberToJSIBoolean(*rt, (__bridge NSNumber *)rawResult);
+ break;
+ case NumberKind:
+ *result = convertNSNumberToJSINumber(*rt, (__bridge NSNumber *)rawResult);
+ break;
+ case StringKind:
+ *result = convertNSStringToJSIString(*rt, (__bridge NSString *)rawResult);
+ break;
+ case ObjectKind:
+ *result = convertNSDictionaryToJSIObject(*rt, (__bridge NSDictionary *)rawResult);
+ break;
+ case ArrayKind:
+ *result = convertNSArrayToJSIArray(*rt, (__bridge NSArray *)rawResult);
+ break;
+ case FunctionKind:
+ throw std::runtime_error("doInvokeTurboModuleMethod: FunctionKind is not supported yet.");
+ case PromiseKind:
+ throw std::runtime_error("doInvokeTurboModuleMethod: PromiseKind wasn't handled properly.");
+ case VoidKind:
+ throw std::runtime_error("doInvokeTurboModuleMethod: VoidKind wasn't handled properly.");
+ }
+ };
+
+ // Backward-compatibility layer for calling module methods on specific queue.
+ dispatch_queue_t methodQueue = NULL;
+ if ([module conformsToProtocol:@protocol(RCTBridgeModule)] && [module respondsToSelector:@selector(methodQueue)]) {
+ methodQueue = [module performSelector:@selector(methodQueue)];
+ }
+
+ if (methodQueue == NULL || methodQueue == RCTJSThread) {
+ // This is the default mode of execution: on JS thread.
+ block();
+ } else if (methodQueue == dispatch_get_main_queue()) {
+ if (valueKind == VoidKind) {
+ // Void methods are treated as async for now, so there's no need to block here.
+ RCTExecuteOnMainQueue(block);
+ } else {
+ // This is not ideal, but provides the simplest mechanism for now.
+ // Eventually, methods should be responsible to queue things up to different queue if they need to.
+ // TODO: consider adding timer to warn if this method invocation takes too long.
+ RCTUnsafeExecuteOnMainQueueSync(block);
+ }
+ } else {
+ if (valueKind == VoidKind) {
+ dispatch_async(methodQueue, block);
+ } else {
+ dispatch_sync(methodQueue, block);
+ }
+ }
+}
+
+} // namespace
+
+ObjCTurboModule::ObjCTurboModule(
+ const std::string &name,
+ id<RCTTurboModule> instance,
+ std::shared_ptr<JSCallInvoker> jsInvoker)
+ : TurboModule(name, jsInvoker),
+ instance_(instance) {}
+
+jsi::Value ObjCTurboModule::invokeMethod(
+ jsi::Runtime &runtime,
+ TurboModuleMethodValueKind valueKind,
+ const std::string &methodName,
+ const jsi::Value *args,
+ size_t count) {
+ SEL selector = resolveMethodSelector(valueKind, instance_, name_, methodName, count);
+ NSInvocation *inv = getMethodInvocation(runtime, valueKind, instance_, jsInvoker_, selector, args, count);
+
+ if (valueKind == PromiseKind) {
+ // Promise return type is special cased today, i.e. it needs extra 2 function args for resolve() and reject(), to
+ // be passed to the actual ObjC++ class method.
+ return createPromise(
+ runtime,
+ jsInvoker_,
+ ^(jsi::Runtime &rt, std::shared_ptr<PromiseWrapper> wrapper) {
+ RCTPromiseResolveBlock resolveBlock = wrapper->resolveBlock();
+ RCTPromiseRejectBlock rejectBlock = wrapper->rejectBlock();
+ [inv setArgument:(void *)&resolveBlock atIndex:count + 2];
+ [inv setArgument:(void *)&rejectBlock atIndex:count + 3];
+ // The return type becomes void in the ObjC side.
+ jsi::Value result;
+ performMethodInvocation(rt, inv, VoidKind, instance_, jsInvoker_, &result);
+ });
+ }
+
+ jsi::Value result;
+ performMethodInvocation(runtime, inv, valueKind, instance_, jsInvoker_, &result);
+ return result;
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/turbomodule/core/TurboCxxModule.cpp

@@ -0,0 +1,147 @@
+/**
+ * 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.
+ */
+
+#include "TurboCxxModule.h"
+
+#include <vector>
+
+#include <jsi/JSIDynamic.h>
+#include <jsireact/TurboModuleUtils.h>
+
+using namespace facebook;
+using namespace facebook::xplat::module;
+
+namespace facebook {
+namespace react {
+
+static CxxModule::Callback makeTurboCxxModuleCallback(
+ jsi::Runtime &runtime,
+ std::shared_ptr<CallbackWrapper> callbackWrapper) {
+ return [callbackWrapper](std::vector<folly::dynamic> args) {
+ callbackWrapper->jsInvoker->invokeAsync([callbackWrapper, args]() {
+ std::vector<jsi::Value> innerArgs;
+ for (auto &a : args) {
+ innerArgs.push_back(jsi::valueFromDynamic(callbackWrapper->runtime, a));
+ }
+ callbackWrapper->callback.call(callbackWrapper->runtime, (const jsi::Value *)innerArgs.data(), innerArgs.size());
+ });
+ };
+}
+
+TurboCxxModule::TurboCxxModule(std::unique_ptr<CxxModule> cxxModule, std::shared_ptr<JSCallInvoker> jsInvoker)
+ : TurboModule(cxxModule->getName(), jsInvoker),
+ cxxMethods_(cxxModule->getMethods()),
+ cxxModule_(std::move(cxxModule)) {}
+
+jsi::Value TurboCxxModule::get(jsi::Runtime& runtime, const jsi::PropNameID& propName) {
+ std::string propNameUtf8 = propName.utf8(runtime);
+
+ if (propNameUtf8 == "getConstants") {
+ // This is special cased because `getConstants()` is already a part of CxxModule.
+ return jsi::Function::createFromHostFunction(
+ runtime,
+ propName,
+ 0,
+ [this](jsi::Runtime &rt, const jsi::Value &thisVal, const jsi::Value *args, size_t count) {
+ jsi::Object result(rt);
+ auto constants = cxxModule_->getConstants();
+ for (auto &pair : constants) {
+ result.setProperty(rt, pair.first.c_str(), jsi::valueFromDynamic(rt, pair.second));
+ }
+ return result;
+ });
+ }
+
+ for (auto &method : cxxMethods_) {
+ if (method.name == propNameUtf8) {
+ return jsi::Function::createFromHostFunction(
+ runtime,
+ propName,
+ 0,
+ [this, propNameUtf8](jsi::Runtime &rt, const jsi::Value &thisVal, const jsi::Value *args, size_t count) {
+ return invokeMethod(rt, VoidKind, propNameUtf8, args, count);
+ });
+ }
+ }
+
+ throw std::runtime_error("Function '" + propNameUtf8 + "' cannot be found on cxxmodule: " + name_);
+}
+
+jsi::Value TurboCxxModule::invokeMethod(
+ jsi::Runtime &runtime,
+ TurboModuleMethodValueKind valueKind,
+ const std::string &methodName,
+ const jsi::Value *args,
+ size_t count) {
+
+ auto it = cxxMethods_.begin();
+ for (; it != cxxMethods_.end(); it++) {
+ auto method = *it;
+ if (method.name == methodName) {
+ break;
+ }
+ }
+
+ if (it == cxxMethods_.end()) {
+ throw std::runtime_error("Function '" + methodName + "' cannot be found on cxxmodule: " + name_);
+ }
+
+ auto method = *it;
+
+ if (method.syncFunc) {
+ auto innerArgs = folly::dynamic::array();
+ for (size_t i = 0; i < count; i++) {
+ innerArgs.push_back(jsi::dynamicFromValue(runtime, args[i]));
+ }
+ return jsi::valueFromDynamic(runtime, method.syncFunc(std::move(innerArgs)));
+ } else if (method.func && !method.isPromise) {
+ // Async method.
+ CxxModule::Callback first;
+ CxxModule::Callback second;
+
+ if (count < method.callbacks) {
+ throw std::invalid_argument(folly::to<std::string>("Expected ", method.callbacks,
+ " callbacks, but only ", count, " parameters provided"));
+ }
+
+ if (method.callbacks == 1) {
+ auto wrapper = std::make_shared<CallbackWrapper>(args[count - 1].getObject(runtime).getFunction(runtime), runtime, jsInvoker_);
+ first = makeTurboCxxModuleCallback(runtime, wrapper);
+ } else if (method.callbacks == 2) {
+ auto wrapper1 = std::make_shared<CallbackWrapper>(args[count - 2].getObject(runtime).getFunction(runtime), runtime, jsInvoker_);
+ auto wrapper2 = std::make_shared<CallbackWrapper>(args[count - 1].getObject(runtime).getFunction(runtime), runtime, jsInvoker_);
+ first = makeTurboCxxModuleCallback(runtime, wrapper1);
+ second = makeTurboCxxModuleCallback(runtime, wrapper2);
+ }
+
+ auto innerArgs = folly::dynamic::array();
+ for (size_t i = 0; i < count - method.callbacks; i++) {
+ innerArgs.push_back(jsi::dynamicFromValue(runtime, args[i]));
+ }
+
+ method.func(std::move(innerArgs), first, second);
+ } else if (method.isPromise) {
+ return createPromiseAsJSIValue(runtime, [method, args, count, this](jsi::Runtime &rt, std::shared_ptr<Promise> promise) {
+ auto resolveWrapper = std::make_shared<CallbackWrapper>(promise->resolve_.getFunction(rt), rt, jsInvoker_);
+ auto rejectWrapper = std::make_shared<CallbackWrapper>(promise->reject_.getFunction(rt), rt, jsInvoker_);
+ CxxModule::Callback resolve = makeTurboCxxModuleCallback(rt, resolveWrapper);
+ CxxModule::Callback reject = makeTurboCxxModuleCallback(rt, rejectWrapper);
+
+ auto innerArgs = folly::dynamic::array();
+ for (size_t i = 0; i < count; i++) {
+ innerArgs.push_back(jsi::dynamicFromValue(rt, args[i]));
+ }
+
+ method.func(std::move(innerArgs), resolve, reject);
+ });
+ }
+
+ return jsi::Value::undefined();
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/turbomodule/core/TurboCxxModule.h

@@ -0,0 +1,44 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include <cxxreact/CxxModule.h>
+
+#include "TurboModule.h"
+
+namespace facebook {
+namespace react {
+
+/**
+ * A helper class to convert the legacy CxxModule instance to a TurboModule instance.
+ * This should be used only for migration purpose (to TurboModule), since it's not very performant
+ * due to a lot of back-and-forth value conversions between folly::dynamic and jsi::Value.
+ */
+class JSI_EXPORT TurboCxxModule : public TurboModule {
+public:
+ TurboCxxModule(std::unique_ptr<facebook::xplat::module::CxxModule> cxxModule, std::shared_ptr<JSCallInvoker> jsInvoker);
+
+ virtual facebook::jsi::Value get(facebook::jsi::Runtime& runtime, const facebook::jsi::PropNameID& propName) override;
+
+ virtual jsi::Value invokeMethod(
+ jsi::Runtime &runtime,
+ TurboModuleMethodValueKind valueKind,
+ const std::string &methodName,
+ const jsi::Value *args,
+ size_t count) override;
+
+private:
+ std::vector<facebook::xplat::module::CxxModule::Method> cxxMethods_;
+ std::unique_ptr<facebook::xplat::module::CxxModule> cxxModule_;
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/turbomodule/core/TurboModuleBinding.cpp

@@ -0,0 +1,72 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include "TurboModuleBinding.h"
+
+#include <string>
+
+#include <cxxreact/SystraceSection.h>
+
+using namespace facebook;
+
+namespace facebook {
+namespace react {
+
+/**
+ * Public API to install the TurboModule system.
+ */
+TurboModuleBinding::TurboModuleBinding(const TurboModuleProviderFunctionType &moduleProvider)
+ : moduleProvider_(moduleProvider) {}
+
+void TurboModuleBinding::install(
+ jsi::Runtime &runtime,
+ std::shared_ptr<TurboModuleBinding> binding) {
+ runtime.global().setProperty(
+ runtime,
+ "__turboModuleProxy",
+ jsi::Function::createFromHostFunction(
+ runtime,
+ jsi::PropNameID::forAscii(runtime, "__turboModuleProxy"),
+ 1,
+ [binding](jsi::Runtime& rt, const jsi::Value& thisVal, const jsi::Value* args, size_t count) {
+ return binding->jsProxy(rt, thisVal, args, count);
+ }));
+}
+
+void TurboModuleBinding::invalidate() const {
+ // Nothing for now.
+}
+
+std::shared_ptr<TurboModule> TurboModuleBinding::getModule(const std::string &name) {
+ std::shared_ptr<TurboModule> module = nullptr;
+ {
+ SystraceSection s("TurboModuleBinding::getModule", "module", name);
+ module = moduleProvider_(name);
+ }
+ return module;
+}
+
+jsi::Value TurboModuleBinding::jsProxy(
+ jsi::Runtime& runtime,
+ const jsi::Value& thisVal,
+ const jsi::Value* args,
+ size_t count) {
+ if (count != 1) {
+ throw std::invalid_argument("TurboModuleBinding::jsProxy arg count must be 1");
+ }
+ std::string moduleName = args[0].getString(runtime).utf8(runtime);
+ std::shared_ptr<TurboModule> module = getModule(moduleName);
+
+ if (module == nullptr) {
+ return jsi::Value::null();
+ }
+
+ return jsi::Object::createFromHostObject(runtime, std::move(module));
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/turbomodule/core/TurboModuleBinding.h

@@ -0,0 +1,61 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <jsi/jsi.h>
+#include <jsireact/TurboModule.h>
+
+namespace facebook {
+namespace react {
+
+class JSCallInvoker;
+
+/**
+ * Represents the JavaScript binding for the TurboModule system.
+ */
+class TurboModuleBinding {
+public:
+ /*
+ * Installs TurboModuleBinding into JavaScript runtime.
+ * Thread synchronization must be enforced externally.
+ */
+ static void install(
+ jsi::Runtime &runtime,
+ std::shared_ptr<TurboModuleBinding> binding);
+
+ TurboModuleBinding(const TurboModuleProviderFunctionType &moduleProvider);
+
+ /*
+ * Invalidates the binding.
+ * Can be called in any thread.
+ */
+ void invalidate() const;
+
+ /**
+ * Get an TurboModule instance for the given module name.
+ */
+ std::shared_ptr<TurboModule> getModule(const std::string &name);
+
+private:
+ /**
+ * A lookup function exposed to JS to get an instance of a TurboModule
+ * for the given name.
+ */
+ jsi::Value jsProxy(
+ jsi::Runtime& runtime,
+ const jsi::Value& thisVal,
+ const jsi::Value* args,
+ size_t count);
+
+ TurboModuleProviderFunctionType moduleProvider_;
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/turbomodule/core/TurboModule.cpp

@@ -0,0 +1,51 @@
+/**
+ * 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.
+ */
+
+#include "TurboModule.h"
+
+using namespace facebook;
+
+namespace facebook {
+namespace react {
+
+TurboModule::TurboModule(const std::string &name, std::shared_ptr<JSCallInvoker> jsInvoker)
+ : name_(name),
+ jsInvoker_(jsInvoker) {}
+
+TurboModule::~TurboModule() {
+ invalidate();
+}
+
+void TurboModule::invalidate() {}
+
+jsi::Value TurboModule::get(jsi::Runtime& runtime, const jsi::PropNameID& propName) {
+ std::string propNameUtf8 = propName.utf8(runtime);
+ auto p = methodMap_.find(propNameUtf8);
+ if (p == methodMap_.end()) {
+ throw std::runtime_error("Function '" + propNameUtf8 + "' cannot be found on module: " + name_);
+ }
+ MethodMetadata meta = p->second;
+ return jsi::Function::createFromHostFunction(
+ runtime,
+ propName,
+ meta.argCount,
+ [this, meta](facebook::jsi::Runtime &rt, const facebook::jsi::Value &thisVal, const facebook::jsi::Value *args, size_t count) {
+ return meta.invoker(rt, *this, args, count);
+ });
+}
+
+jsi::Value TurboModule::invokeMethod(
+ jsi::Runtime &runtime,
+ TurboModuleMethodValueKind valueKind,
+ const std::string &methodName,
+ const jsi::Value *args,
+ size_t count) {
+ return jsi::Value::undefined();
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/turbomodule/core/TurboModule.h

@@ -0,0 +1,84 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <string>
+#include <unordered_map>
+
+#include <jsi/jsi.h>
+
+#include "JSCallInvoker.h"
+
+namespace facebook {
+namespace react {
+
+/**
+ * For now, support the same set of return types as existing impl.
+ * This can be improved to support richer typed objects.
+ */
+enum TurboModuleMethodValueKind {
+ VoidKind,
+ BooleanKind,
+ NumberKind,
+ StringKind,
+ ObjectKind,
+ ArrayKind,
+ FunctionKind,
+ PromiseKind,
+};
+
+/**
+ * Base HostObject class for every module to be exposed to JS
+ */
+class JSI_EXPORT TurboModule : public facebook::jsi::HostObject {
+public:
+ TurboModule(const std::string &name, std::shared_ptr<JSCallInvoker> jsInvoker);
+ virtual ~TurboModule();
+
+ /**
+ * Instruct this module to invalidate itself.
+ */
+ virtual void invalidate();
+
+ virtual facebook::jsi::Value get(facebook::jsi::Runtime& runtime, const facebook::jsi::PropNameID& propName) override;
+
+ /**
+ * General method invocation mechanism.
+ * Each subclass decides how the invocation should be, and whether it should be platform-specific.
+ */
+ virtual jsi::Value invokeMethod(
+ jsi::Runtime &runtime,
+ TurboModuleMethodValueKind valueKind,
+ const std::string &methodName,
+ const jsi::Value *args,
+ size_t count);
+
+ const std::string name_;
+ std::shared_ptr<JSCallInvoker> jsInvoker_;
+
+protected:
+ struct MethodMetadata {
+ size_t argCount;
+ facebook::jsi::Value (*invoker)(
+ facebook::jsi::Runtime& rt,
+ TurboModule &turboModule,
+ const facebook::jsi::Value* args,
+ size_t count);
+ };
+
+ std::unordered_map<std::string, MethodMetadata> methodMap_;
+};
+
+/**
+ * An app/platform-specific provider function to get an instance of a module given a name.
+ */
+using TurboModuleProviderFunctionType = std::function<std::shared_ptr<TurboModule>(
+ const std::string &name)>;
+
+} // namespace react
+} // namespace facebook

ReactCommon/turbomodule/core/TurboModuleUtils.cpp

@@ -0,0 +1,98 @@
+/**
+ * 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.
+ */
+
+#include "TurboModuleUtils.h"
+
+namespace facebook {
+namespace react {
+
+static jsi::Value deepCopyJSIValue(jsi::Runtime &rt, const jsi::Value &value) {
+ if (value.isNull()) {
+ return jsi::Value::null();
+ }
+
+ if (value.isBool()) {
+ return jsi::Value(value.getBool());
+ }
+
+ if (value.isNumber()) {
+ return jsi::Value(value.getNumber());
+ }
+
+ if (value.isString()) {
+ return value.getString(rt);
+ }
+
+ if (value.isObject()) {
+ jsi::Object o = value.getObject(rt);
+ if (o.isArray(rt)) {
+ return deepCopyJSIArray(rt, o.getArray(rt));
+ }
+ if (o.isFunction(rt)) {
+ return o.getFunction(rt);
+ }
+ return deepCopyJSIObject(rt, o);
+ }
+
+ return jsi::Value::undefined();
+}
+
+jsi::Object deepCopyJSIObject(jsi::Runtime &rt, const jsi::Object &obj) {
+ jsi::Object copy(rt);
+ jsi::Array propertyNames = obj.getPropertyNames(rt);
+ size_t size = propertyNames.size(rt);
+ for (size_t i = 0; i < size; i++) {
+ jsi::String name = propertyNames.getValueAtIndex(rt, i).getString(rt);
+ jsi::Value value = obj.getProperty(rt, name);
+ copy.setProperty(rt, name, deepCopyJSIValue(rt, value));
+ }
+ return copy;
+}
+
+jsi::Array deepCopyJSIArray(jsi::Runtime &rt, const jsi::Array &arr) {
+ size_t size = arr.size(rt);
+ jsi::Array copy(rt, size);
+ for (size_t i = 0; i < size; i++) {
+ copy.setValueAtIndex(rt, i, deepCopyJSIValue(rt, arr.getValueAtIndex(rt, i)));
+ }
+ return copy;
+}
+
+Promise::Promise(jsi::Runtime &rt, jsi::Function resolve, jsi::Function reject)
+ : runtime_(rt),
+ resolve_(std::move(resolve)),
+ reject_(std::move(reject)) {}
+
+void Promise::resolve(const jsi::Value &result) {
+ resolve_.call(runtime_, result);
+}
+
+void Promise::reject(const std::string &message) {
+ jsi::Object error(runtime_);
+ error.setProperty(runtime_, "message", jsi::String::createFromUtf8(runtime_, message));
+ reject_.call(runtime_, error);
+}
+
+jsi::Value createPromiseAsJSIValue(jsi::Runtime &rt, const PromiseSetupFunctionType func) {
+ jsi::Function JSPromise = rt.global().getPropertyAsFunction(rt, "Promise");
+ jsi::Function fn = jsi::Function::createFromHostFunction(
+ rt,
+ jsi::PropNameID::forAscii(rt, "fn"),
+ 2,
+ [func](jsi::Runtime &rt2, const jsi::Value &thisVal, const jsi::Value *args, size_t count) {
+ jsi::Function resolve = args[0].getObject(rt2).getFunction(rt2);
+ jsi::Function reject = args[1].getObject(rt2).getFunction(rt2);
+ auto wrapper = std::make_shared<Promise>(rt2, std::move(resolve), std::move(reject));
+ func(rt2, wrapper);
+ return jsi::Value::undefined();
+ });
+
+ return JSPromise.callAsConstructor(rt, fn);
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/turbomodule/core/TurboModuleUtils.h

@@ -0,0 +1,50 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <jsi/jsi.h>
+
+#include "JSCallInvoker.h"
+
+using namespace facebook;
+
+namespace facebook {
+namespace react {
+
+jsi::Object deepCopyJSIObject(jsi::Runtime &rt, const jsi::Object &obj);
+jsi::Array deepCopyJSIArray(jsi::Runtime &rt, const jsi::Array &arr);
+
+struct Promise {
+ Promise(jsi::Runtime &rt, jsi::Function resolve, jsi::Function reject);
+
+ void resolve(const jsi::Value &result);
+ void reject(const std::string &error);
+
+ jsi::Runtime &runtime_;
+ jsi::Function resolve_;
+ jsi::Function reject_;
+};
+
+using PromiseSetupFunctionType = std::function<void(jsi::Runtime &rt, std::shared_ptr<Promise>)>;
+jsi::Value createPromiseAsJSIValue(jsi::Runtime &rt, const PromiseSetupFunctionType func);
+
+// Helper for passing jsi::Function arg to other methods.
+struct CallbackWrapper {
+ CallbackWrapper(jsi::Function callback, jsi::Runtime &runtime, std::shared_ptr<react::JSCallInvoker> jsInvoker)
+ : callback(std::move(callback)),
+ runtime(runtime),
+ jsInvoker(jsInvoker) {}
+ jsi::Function callback;
+ jsi::Runtime &runtime;
+ std::shared_ptr<react::JSCallInvoker> jsInvoker;
+};
+
+} // namespace react
+} // namespace facebook

ReactCommon/utils/BUCK

@@ -0,0 +1,27 @@
+load("@fbsource//tools/build_defs:glob_defs.bzl", "subdir_glob")
+load("//tools/build_defs/oss:rn_defs.bzl", "get_apple_compiler_flags", "rn_xplat_cxx_library")
+
+CXX_LIBRARY_COMPILER_FLAGS = [
+ "-std=c++14",
+ "-Wall",
+]
+
+rn_xplat_cxx_library(
+ name = "utils",
+ header_namespace = "",
+ exported_headers = subdir_glob(
+ [
+ ("", "FloatComparison.h"),
+ ],
+ prefix = "react/utils",
+ ),
+ compiler_flags = CXX_LIBRARY_COMPILER_FLAGS + [
+ "-fexceptions",
+ "-frtti",
+ ],
+ fbobjc_compiler_flags = get_apple_compiler_flags(),
+ force_static = True,
+ visibility = [
+ "PUBLIC",
+ ],
+)

ReactCommon/utils/FloatComparison.h

@@ -0,0 +1,18 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+namespace facebook {
+namespace react {
+
+inline bool floatEquality (float a, float b, float epsilon = 0.005f) {
+ return (std::isnan(a) && std::isnan(b)) || (!std::isnan(a) && !std::isnan(b) && fabs(a - b) < epsilon);
+}
+
+} // namespace react
+} // namespace facebook

ReactCommon/yoga/Android.mk

@@ -1,3 +1,8 @@
+# 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.
+
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

ReactCommon/yoga/yoga/CompactValue.h

@@ -0,0 +1,187 @@
+/**
+ * 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.
+ */
+#pragma once
+
+#include "YGValue.h"
+
+#include <cmath>
+#include <cstdint>
+#include <limits>
+
+static_assert(
+ std::numeric_limits<float>::is_iec559,
+ "facebook::yoga::detail::CompactValue only works with IEEE754 floats");
+
+#ifdef YOGA_COMPACT_VALUE_TEST
+#define VISIBLE_FOR_TESTING public:
+#else
+#define VISIBLE_FOR_TESTING private:
+#endif
+
+namespace facebook {
+namespace yoga {
+namespace detail {
+
+// This class stores YGValue in 32 bits.
+// - The value does not matter for Undefined and Auto. NaNs are used for their
+// representation.
+// - To differentiate between Point and Percent, one exponent bit is used.
+// Supported the range [0x40, 0xbf] (0xbf is inclusive for point, but
+// exclusive for percent).
+// - Value ranges:
+// points: 1.08420217e-19f to 36893485948395847680
+// 0x00000000 0x3fffffff
+// percent: 1.08420217e-19f to 18446742974197923840
+// 0x40000000 0x7f7fffff
+// - Zero is supported, negative zero is not
+// - values outside of the representable range are clamped
+class CompactValue {
+ friend constexpr bool operator==(CompactValue, CompactValue) noexcept;
+
+public:
+ static constexpr auto LOWER_BOUND = 1.08420217e-19f;
+ static constexpr auto UPPER_BOUND_POINT = 36893485948395847680.0f;
+ static constexpr auto UPPER_BOUND_PERCENT = 18446742974197923840.0f;
+
+ template <YGUnit Unit>
+ static CompactValue of(float value) noexcept {
+ if (value == 0.0f || (value < LOWER_BOUND && value > -LOWER_BOUND)) {
+ constexpr auto zero =
+ Unit == YGUnitPercent ? ZERO_BITS_PERCENT : ZERO_BITS_POINT;
+ return {Payload{zero}};
+ }
+
+ constexpr auto upperBound =
+ Unit == YGUnitPercent ? UPPER_BOUND_PERCENT : UPPER_BOUND_POINT;
+ if (value > upperBound || value < -upperBound) {
+ value = copysignf(upperBound, value);
+ }
+
+ uint32_t unitBit = Unit == YGUnitPercent ? PERCENT_BIT : 0;
+ auto data = Payload{value};
+ data.repr -= BIAS;
+ data.repr |= unitBit;
+ return {data};
+ }
+
+ template <YGUnit Unit>
+ static CompactValue ofMaybe(float value) noexcept {
+ return std::isnan(value) || std::isinf(value) ? ofUndefined()
+ : of<Unit>(value);
+ }
+
+ static constexpr CompactValue ofZero() noexcept {
+ return CompactValue{Payload{ZERO_BITS_POINT}};
+ }
+
+ static constexpr CompactValue ofUndefined() noexcept {
+ return CompactValue{};
+ }
+
+ static constexpr CompactValue ofAuto() noexcept {
+ return CompactValue{Payload{AUTO_BITS}};
+ }
+
+ constexpr CompactValue() noexcept
+ : payload_(std::numeric_limits<float>::quiet_NaN()) {}
+
+ CompactValue(const YGValue& x) noexcept : payload_(uint32_t{0}) {
+ switch (x.unit) {
+ case YGUnitUndefined:
+ *this = ofUndefined();
+ break;
+ case YGUnitAuto:
+ *this = ofAuto();
+ break;
+ case YGUnitPoint:
+ *this = of<YGUnitPoint>(x.value);
+ break;
+ case YGUnitPercent:
+ *this = of<YGUnitPercent>(x.value);
+ break;
+ }
+ }
+
+ operator YGValue() const noexcept {
+ switch (payload_.repr) {
+ case AUTO_BITS:
+ return YGValueAuto;
+ case ZERO_BITS_POINT:
+ return YGValue{0.0f, YGUnitPoint};
+ case ZERO_BITS_PERCENT:
+ return YGValue{0.0f, YGUnitPercent};
+ }
+
+ if (std::isnan(payload_.value)) {
+ return YGValueUndefined;
+ }
+
+ auto data = payload_;
+ data.repr &= ~PERCENT_BIT;
+ data.repr += BIAS;
+
+ return YGValue{data.value,
+ payload_.repr & 0x40000000 ? YGUnitPercent : YGUnitPoint};
+ }
+
+ bool isUndefined() const noexcept {
+ return (
+ payload_.repr != AUTO_BITS && payload_.repr != ZERO_BITS_POINT &&
+ payload_.repr != ZERO_BITS_PERCENT && std::isnan(payload_.value));
+ }
+
+ bool isAuto() const noexcept {
+ return payload_.repr == AUTO_BITS;
+ }
+
+private:
+ union Payload {
+ float value;
+ uint32_t repr;
+ Payload() = delete;
+ constexpr Payload(uint32_t r) : repr(r) {}
+ constexpr Payload(float v) : value(v) {}
+ };
+
+ static constexpr uint32_t BIAS = 0x20000000;
+ static constexpr uint32_t PERCENT_BIT = 0x40000000;
+
+ // these are signaling NaNs with specific bit pattern as payload they will be
+ // silenced whenever going through an FPU operation on ARM + x86
+ static constexpr uint32_t AUTO_BITS = 0x7faaaaaa;
+ static constexpr uint32_t ZERO_BITS_POINT = 0x7f8f0f0f;
+ static constexpr uint32_t ZERO_BITS_PERCENT = 0x7f80f0f0;
+
+ constexpr CompactValue(Payload data) noexcept : payload_(data) {}
+
+ Payload payload_;
+
+ VISIBLE_FOR_TESTING uint32_t repr() {
+ return payload_.repr;
+ }
+};
+
+template <>
+CompactValue CompactValue::of<YGUnitUndefined>(float) noexcept = delete;
+template <>
+CompactValue CompactValue::of<YGUnitAuto>(float) noexcept = delete;
+template <>
+CompactValue CompactValue::ofMaybe<YGUnitUndefined>(float) noexcept = delete;
+template <>
+CompactValue CompactValue::ofMaybe<YGUnitAuto>(float) noexcept = delete;
+
+constexpr bool operator==(CompactValue a, CompactValue b) noexcept {
+ return a.payload_.repr == b.payload_.repr;
+}
+
+constexpr bool operator!=(CompactValue a, CompactValue b) noexcept {
+ return !(a == b);
+}
+
+} // namespace detail
+} // namespace yoga
+} // namespace facebook

ReactCommon/yoga/yoga/instrumentation.h

@@ -0,0 +1,60 @@
+/**
+ * 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.
+ */
+#include "YGConfig.h"
+#include "YGMarker.h"
+#include "YGNode.h"
+
+namespace facebook {
+namespace yoga {
+namespace marker {
+
+template <YGMarker MarkerType>
+class MarkerSection {
+private:
+ using Data = detail::MarkerData<MarkerType>;
+
+public:
+ MarkerSection(YGNodeRef node) : MarkerSection{node, node->getConfig()} {}
+ ~MarkerSection() {
+ if (endMarker_) {
+ endMarker_(MarkerType, node_, markerData(&data), userData_);
+ }
+ }
+
+ typename Data::type data = {};
+
+ template <typename Ret, typename... Args>
+ static Ret wrap(YGNodeRef node, Ret (*fn)(Args...), Args... args) {
+ MarkerSection<MarkerType> section{node};
+ return fn(std::forward<Args>(args)...);
+ }
+
+private:
+ decltype(YGMarkerCallbacks{}.endMarker) endMarker_;
+ YGNodeRef node_;
+ void* userData_;
+
+ MarkerSection(YGNodeRef node, YGConfigRef config)
+ : MarkerSection{node, config ? &config->markerCallbacks : nullptr} {}
+ MarkerSection(YGNodeRef node, YGMarkerCallbacks* callbacks)
+ : endMarker_{callbacks ? callbacks->endMarker : nullptr},
+ node_{node},
+ userData_{
+ callbacks && callbacks->startMarker
+ ? callbacks->startMarker(MarkerType, node, markerData(&data))
+ : nullptr} {}
+
+ static YGMarkerData markerData(typename Data::type* d) {
+ YGMarkerData markerData = {};
+ Data::get(markerData) = d;
+ return markerData;
+ }
+};
+
+} // namespace marker
+} // namespace yoga
+} // namespace facebook

ReactCommon/yoga/yoga/Utils.cpp

@@ -1,9 +1,8 @@
-/*
- * Copyright (c) 2014-present, Facebook, Inc.
+/**
+ * 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.
- *
*/
#include "Utils.h"
@@ -52,19 +51,16 @@
return yoga::isUndefined(a) && yoga::isUndefined(b);
}
-float YGFloatSanitize(const float& val) {
+float YGFloatSanitize(const float val) {
return yoga::isUndefined(val) ? 0 : val;
}
-float YGUnwrapFloatOptional(const YGFloatOptional& op) {
- return op.isUndefined() ? YGUndefined : op.getValue();
-}
-
-YGFloatOptional YGFloatOptionalMax(
- const YGFloatOptional& op1,
- const YGFloatOptional& op2) {
- if (!op1.isUndefined() && !op2.isUndefined()) {
- return op1.getValue() > op2.getValue() ? op1 : op2;
+YGFloatOptional YGFloatOptionalMax(YGFloatOptional op1, YGFloatOptional op2) {
+ if (op1 >= op2) {
+ return op1;
+ }
+ if (op2 > op1) {
+ return op2;
}
return op1.isUndefined() ? op2 : op1;
}

ReactCommon/yoga/yoga/Utils.h

@@ -1,16 +1,16 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.
+ * This source code is licensed under the MIT license found in the LICENSE
+ * file in the root directory of this source tree.
*/
-
#pragma once
#include "YGNode.h"
#include "Yoga-internal.h"
+#include "CompactValue.h"
-// This struct is an helper model to hold the data for step 4 of flexbox
-// algo, which is collecting the flex items in a line.
+// This struct is an helper model to hold the data for step 4 of flexbox algo,
+// which is collecting the flex items in a line.
//
// - itemsOnLine: Number of items which can fit in a line considering the
// available Inner dimension, the flex items computed flexbasis and their
@@ -18,9 +18,9 @@
// indicates because we skip over absolute-positioned items.
//
// - sizeConsumedOnCurrentLine: It is accumulation of the dimensions and margin
-// of all the children on the current line. This will be used in order to either
-// set the dimensions of the node if none already exist or to compute the
-// remaining space left for the flexible children.
+// of all the children on the current line. This will be used in order to
+// either set the dimensions of the node if none already exist or to compute
+// the remaining space left for the flexible children.
//
// - totalFlexGrowFactors: total flex grow factors of flex items which are to be
// layed in the current line
@@ -58,22 +58,12 @@
// difference between two floats is less than 0.0001f or both are undefined.
bool YGFloatsEqual(const float a, const float b);
-// We need custom max function, since we want that, if one argument is
-// YGUndefined then the max funtion should return the other argument as the max
-// value. We wouldn't have needed a custom max function if YGUndefined was NAN
-// as fmax has the same behaviour, but with NAN we cannot use `-ffast-math`
-// compiler flag.
float YGFloatMax(const float a, const float b);
YGFloatOptional YGFloatOptionalMax(
- const YGFloatOptional& op1,
- const YGFloatOptional& op2);
+ const YGFloatOptional op1,
+ const YGFloatOptional op2);
-// We need custom min function, since we want that, if one argument is
-// YGUndefined then the min funtion should return the other argument as the min
-// value. We wouldn't have needed a custom min function if YGUndefined was NAN
-// as fmin has the same behaviour, but with NAN we cannot use `-ffast-math`
-// compiler flag.
float YGFloatMin(const float a, const float b);
// This custom float comparision function compares the array of float with
@@ -91,12 +81,7 @@
}
// This function returns 0 if YGFloatIsUndefined(val) is true and val otherwise
-float YGFloatSanitize(const float& val);
-
-// This function unwraps optional and returns YGUndefined if not defined or
-// op.value otherwise
-// TODO: Get rid off this function
-float YGUnwrapFloatOptional(const YGFloatOptional& op);
+float YGFloatSanitize(const float val);
YGFlexDirection YGFlexDirectionCross(
const YGFlexDirection flexDirection,
@@ -107,18 +92,17 @@
flexDirection == YGFlexDirectionRowReverse;
}
-inline YGFloatOptional YGResolveValue(const YGValue value, const float ownerSize) {
+inline YGFloatOptional YGResolveValue(
+ const YGValue value,
+ const float ownerSize) {
switch (value.unit) {
- case YGUnitUndefined:
- case YGUnitAuto:
- return YGFloatOptional();
case YGUnitPoint:
- return YGFloatOptional(value.value);
+ return YGFloatOptional{value.value};
case YGUnitPercent:
- return YGFloatOptional(
- static_cast<float>(value.value * ownerSize * 0.01));
+ return YGFloatOptional{value.value * ownerSize * 0.01f};
+ default:
+ return YGFloatOptional{};
}
- return YGFloatOptional();
}
inline bool YGFlexDirectionIsColumn(const YGFlexDirection flexDirection) {
@@ -140,9 +124,8 @@
return flexDirection;
}
-static inline YGFloatOptional YGResolveValueMargin(
- const YGValue value,
+inline YGFloatOptional YGResolveValueMargin(
+ yoga::detail::CompactValue value,
const float ownerSize) {
- return value.unit == YGUnitAuto ? YGFloatOptional(0)
- : YGResolveValue(value, ownerSize);
+ return value.isAuto() ? YGFloatOptional{0} : YGResolveValue(value, ownerSize);
}

ReactCommon/yoga/yoga/YGConfig.cpp

@@ -1,19 +1,9 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.
+ * This source code is licensed under the MIT license found in the LICENSE
+ * file in the root directory of this source tree.
*/
-
#include "YGConfig.h"
-const std::array<bool, YGExperimentalFeatureCount>
- kYGDefaultExperimentalFeatures = {{false}};
-
-YGConfig::YGConfig(YGLogger logger)
- : experimentalFeatures(kYGDefaultExperimentalFeatures),
- useWebDefaults(false),
- useLegacyStretchBehaviour(false),
- shouldDiffLayoutWithoutLegacyStretchBehaviour(false),
- pointScaleFactor(1.0f), logger(logger), cloneNodeCallback(nullptr),
- context(nullptr) {}
+YGConfig::YGConfig(YGLogger logger) : logger(logger) {}

ReactCommon/yoga/yoga/YGConfig.h

@@ -1,23 +1,26 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.
+ * This source code is licensed under the MIT license found in the LICENSE
+ * file in the root directory of this source tree.
*/
-
#pragma once
+#include "YGMarker.h"
#include "Yoga-internal.h"
#include "Yoga.h"
struct YGConfig {
- std::array<bool, YGExperimentalFeatureCount> experimentalFeatures;
- bool useWebDefaults;
- bool useLegacyStretchBehaviour;
- bool shouldDiffLayoutWithoutLegacyStretchBehaviour;
- float pointScaleFactor;
+ std::array<bool, facebook::yoga::enums::count<YGExperimentalFeature>()>
+ experimentalFeatures = {};
+ bool useWebDefaults = false;
+ bool useLegacyStretchBehaviour = false;
+ bool shouldDiffLayoutWithoutLegacyStretchBehaviour = false;
+ bool printTree = false;
+ float pointScaleFactor = 1.0f;
YGLogger logger;
- YGCloneNodeFunc cloneNodeCallback;
- void* context;
+ YGCloneNodeFunc cloneNodeCallback = nullptr;
+ void* context = nullptr;
+ YGMarkerCallbacks markerCallbacks = {nullptr, nullptr};
YGConfig(YGLogger logger);
};

ReactCommon/yoga/yoga/YGEnums.cpp

@@ -1,14 +1,13 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.
+ * This source code is licensed under the MIT license found in the LICENSE
+ * file in the root directory of this source tree.
*/
-
#include "YGEnums.h"
-const char *YGAlignToString(const YGAlign value){
- switch(value){
+const char* YGAlignToString(const YGAlign value) {
+ switch (value) {
case YGAlignAuto:
return "auto";
case YGAlignFlexStart:
@@ -29,8 +28,8 @@
return "unknown";
}
-const char *YGDimensionToString(const YGDimension value){
- switch(value){
+const char* YGDimensionToString(const YGDimension value) {
+ switch (value) {
case YGDimensionWidth:
return "width";
case YGDimensionHeight:
@@ -39,8 +38,8 @@
return "unknown";
}
-const char *YGDirectionToString(const YGDirection value){
- switch(value){
+const char* YGDirectionToString(const YGDirection value) {
+ switch (value) {
case YGDirectionInherit:
return "inherit";
case YGDirectionLTR:
@@ -51,8 +50,8 @@
return "unknown";
}
-const char *YGDisplayToString(const YGDisplay value){
- switch(value){
+const char* YGDisplayToString(const YGDisplay value) {
+ switch (value) {
case YGDisplayFlex:
return "flex";
case YGDisplayNone:
@@ -61,8 +60,8 @@
return "unknown";
}
-const char *YGEdgeToString(const YGEdge value){
- switch(value){
+const char* YGEdgeToString(const YGEdge value) {
+ switch (value) {
case YGEdgeLeft:
return "left";
case YGEdgeTop:
@@ -85,16 +84,16 @@
return "unknown";
}
-const char *YGExperimentalFeatureToString(const YGExperimentalFeature value){
- switch(value){
+const char* YGExperimentalFeatureToString(const YGExperimentalFeature value) {
+ switch (value) {
case YGExperimentalFeatureWebFlexBasis:
return "web-flex-basis";
}
return "unknown";
}
-const char *YGFlexDirectionToString(const YGFlexDirection value){
- switch(value){
+const char* YGFlexDirectionToString(const YGFlexDirection value) {
+ switch (value) {
case YGFlexDirectionColumn:
return "column";
case YGFlexDirectionColumnReverse:
@@ -107,8 +106,8 @@
return "unknown";
}
-const char *YGJustifyToString(const YGJustify value){
- switch(value){
+const char* YGJustifyToString(const YGJustify value) {
+ switch (value) {
case YGJustifyFlexStart:
return "flex-start";
case YGJustifyCenter:
@@ -125,8 +124,8 @@
return "unknown";
}
-const char *YGLogLevelToString(const YGLogLevel value){
- switch(value){
+const char* YGLogLevelToString(const YGLogLevel value) {
+ switch (value) {
case YGLogLevelError:
return "error";
case YGLogLevelWarn:
@@ -143,8 +142,8 @@
return "unknown";
}
-const char *YGMeasureModeToString(const YGMeasureMode value){
- switch(value){
+const char* YGMeasureModeToString(const YGMeasureMode value) {
+ switch (value) {
case YGMeasureModeUndefined:
return "undefined";
case YGMeasureModeExactly:
@@ -155,8 +154,8 @@
return "unknown";
}
-const char *YGNodeTypeToString(const YGNodeType value){
- switch(value){
+const char* YGNodeTypeToString(const YGNodeType value) {
+ switch (value) {
case YGNodeTypeDefault:
return "default";
case YGNodeTypeText:
@@ -165,8 +164,8 @@
return "unknown";
}
-const char *YGOverflowToString(const YGOverflow value){
- switch(value){
+const char* YGOverflowToString(const YGOverflow value) {
+ switch (value) {
case YGOverflowVisible:
return "visible";
case YGOverflowHidden:
@@ -177,8 +176,8 @@
return "unknown";
}
-const char *YGPositionTypeToString(const YGPositionType value){
- switch(value){
+const char* YGPositionTypeToString(const YGPositionType value) {
+ switch (value) {
case YGPositionTypeRelative:
return "relative";
case YGPositionTypeAbsolute:
@@ -187,8 +186,8 @@
return "unknown";
}
-const char *YGPrintOptionsToString(const YGPrintOptions value){
- switch(value){
+const char* YGPrintOptionsToString(const YGPrintOptions value) {
+ switch (value) {
case YGPrintOptionsLayout:
return "layout";
case YGPrintOptionsStyle:
@@ -199,8 +198,8 @@
return "unknown";
}
-const char *YGUnitToString(const YGUnit value){
- switch(value){
+const char* YGUnitToString(const YGUnit value) {
+ switch (value) {
case YGUnitUndefined:
return "undefined";
case YGUnitPoint:
@@ -213,8 +212,8 @@
return "unknown";
}
-const char *YGWrapToString(const YGWrap value){
- switch(value){
+const char* YGWrapToString(const YGWrap value) {
+ switch (value) {
case YGWrapNoWrap:
return "no-wrap";
case YGWrapWrap:

ReactCommon/yoga/yoga/YGEnums.h

@@ -1,18 +1,60 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.
+ * This source code is licensed under the MIT license found in the LICENSE
+ * file in the root directory of this source tree.
*/
-
#pragma once
#include "YGMacros.h"
+#ifdef __cplusplus
+namespace facebook {
+namespace yoga {
+namespace enums {
+
+template <typename T>
+constexpr int count(); // can't use `= delete` due to a defect in clang < 3.9
+
+namespace detail {
+template <int... xs>
+constexpr int n() {
+ return sizeof...(xs);
+}
+} // namespace detail
+
+} // namespace enums
+} // namespace yoga
+} // namespace facebook
+#endif
+
+#define YG_ENUM_DECL(NAME, ...) \
+ typedef YG_ENUM_BEGIN(NAME){__VA_ARGS__} YG_ENUM_END(NAME); \
+ WIN_EXPORT const char* NAME##ToString(NAME);
+
+#ifdef __cplusplus
+#define YG_ENUM_SEQ_DECL(NAME, ...) \
+ YG_ENUM_DECL(NAME, __VA_ARGS__) \
+ YG_EXTERN_C_END \
+ namespace facebook { \
+ namespace yoga { \
+ namespace enums { \
+ template <> \
+ constexpr int count<NAME>() { \
+ return detail::n<__VA_ARGS__>(); \
+ } \
+ } \
+ } \
+ } \
+ YG_EXTERN_C_BEGIN
+#else
+#define YG_ENUM_SEQ_DECL YG_ENUM_DECL
+#endif
+
YG_EXTERN_C_BEGIN
-#define YGAlignCount 8
-typedef YG_ENUM_BEGIN(YGAlign) {
+YG_ENUM_SEQ_DECL(
+ YGAlign,
YGAlignAuto,
YGAlignFlexStart,
YGAlignCenter,
@@ -20,34 +62,20 @@
YGAlignStretch,
YGAlignBaseline,
YGAlignSpaceBetween,
- YGAlignSpaceAround,
-} YG_ENUM_END(YGAlign);
-WIN_EXPORT const char *YGAlignToString(const YGAlign value);
-
-#define YGDimensionCount 2
-typedef YG_ENUM_BEGIN(YGDimension) {
- YGDimensionWidth,
- YGDimensionHeight,
-} YG_ENUM_END(YGDimension);
-WIN_EXPORT const char *YGDimensionToString(const YGDimension value);
+ YGAlignSpaceAround);
+
+YG_ENUM_SEQ_DECL(YGDimension, YGDimensionWidth, YGDimensionHeight)
-#define YGDirectionCount 3
-typedef YG_ENUM_BEGIN(YGDirection) {
+YG_ENUM_SEQ_DECL(
+ YGDirection,
YGDirectionInherit,
YGDirectionLTR,
- YGDirectionRTL,
-} YG_ENUM_END(YGDirection);
-WIN_EXPORT const char *YGDirectionToString(const YGDirection value);
-
-#define YGDisplayCount 2
-typedef YG_ENUM_BEGIN(YGDisplay) {
- YGDisplayFlex,
- YGDisplayNone,
-} YG_ENUM_END(YGDisplay);
-WIN_EXPORT const char *YGDisplayToString(const YGDisplay value);
+ YGDirectionRTL)
-#define YGEdgeCount 9
-typedef YG_ENUM_BEGIN(YGEdge) {
+YG_ENUM_SEQ_DECL(YGDisplay, YGDisplayFlex, YGDisplayNone)
+
+YG_ENUM_SEQ_DECL(
+ YGEdge,
YGEdgeLeft,
YGEdgeTop,
YGEdgeRight,
@@ -56,100 +84,67 @@
YGEdgeEnd,
YGEdgeHorizontal,
YGEdgeVertical,
- YGEdgeAll,
-} YG_ENUM_END(YGEdge);
-WIN_EXPORT const char *YGEdgeToString(const YGEdge value);
-
-#define YGExperimentalFeatureCount 1
-typedef YG_ENUM_BEGIN(YGExperimentalFeature) {
- YGExperimentalFeatureWebFlexBasis,
-} YG_ENUM_END(YGExperimentalFeature);
-WIN_EXPORT const char *YGExperimentalFeatureToString(const YGExperimentalFeature value);
+ YGEdgeAll)
+
+YG_ENUM_SEQ_DECL(YGExperimentalFeature, YGExperimentalFeatureWebFlexBasis)
-#define YGFlexDirectionCount 4
-typedef YG_ENUM_BEGIN(YGFlexDirection) {
+YG_ENUM_SEQ_DECL(
+ YGFlexDirection,
YGFlexDirectionColumn,
YGFlexDirectionColumnReverse,
YGFlexDirectionRow,
- YGFlexDirectionRowReverse,
-} YG_ENUM_END(YGFlexDirection);
-WIN_EXPORT const char *YGFlexDirectionToString(const YGFlexDirection value);
+ YGFlexDirectionRowReverse)
-#define YGJustifyCount 6
-typedef YG_ENUM_BEGIN(YGJustify){
+YG_ENUM_SEQ_DECL(
+ YGJustify,
YGJustifyFlexStart,
YGJustifyCenter,
YGJustifyFlexEnd,
YGJustifySpaceBetween,
YGJustifySpaceAround,
- YGJustifySpaceEvenly,
-} YG_ENUM_END(YGJustify);
-WIN_EXPORT const char *YGJustifyToString(const YGJustify value);
+ YGJustifySpaceEvenly)
-#define YGLogLevelCount 6
-typedef YG_ENUM_BEGIN(YGLogLevel) {
+YG_ENUM_SEQ_DECL(
+ YGLogLevel,
YGLogLevelError,
YGLogLevelWarn,
YGLogLevelInfo,
YGLogLevelDebug,
YGLogLevelVerbose,
- YGLogLevelFatal,
-} YG_ENUM_END(YGLogLevel);
-WIN_EXPORT const char *YGLogLevelToString(const YGLogLevel value);
+ YGLogLevelFatal)
-#define YGMeasureModeCount 3
-typedef YG_ENUM_BEGIN(YGMeasureMode) {
+YG_ENUM_SEQ_DECL(
+ YGMeasureMode,
YGMeasureModeUndefined,
YGMeasureModeExactly,
- YGMeasureModeAtMost,
-} YG_ENUM_END(YGMeasureMode);
-WIN_EXPORT const char *YGMeasureModeToString(const YGMeasureMode value);
-
-#define YGNodeTypeCount 2
-typedef YG_ENUM_BEGIN(YGNodeType) {
- YGNodeTypeDefault,
- YGNodeTypeText,
-} YG_ENUM_END(YGNodeType);
-WIN_EXPORT const char *YGNodeTypeToString(const YGNodeType value);
+ YGMeasureModeAtMost)
-#define YGOverflowCount 3
-typedef YG_ENUM_BEGIN(YGOverflow) {
+YG_ENUM_SEQ_DECL(YGNodeType, YGNodeTypeDefault, YGNodeTypeText)
+
+YG_ENUM_SEQ_DECL(
+ YGOverflow,
YGOverflowVisible,
YGOverflowHidden,
- YGOverflowScroll,
-} YG_ENUM_END(YGOverflow);
-WIN_EXPORT const char *YGOverflowToString(const YGOverflow value);
-
-#define YGPositionTypeCount 2
-typedef YG_ENUM_BEGIN(YGPositionType) {
- YGPositionTypeRelative,
- YGPositionTypeAbsolute,
-} YG_ENUM_END(YGPositionType);
-WIN_EXPORT const char *YGPositionTypeToString(const YGPositionType value);
+ YGOverflowScroll)
+
+YG_ENUM_SEQ_DECL(YGPositionType, YGPositionTypeRelative, YGPositionTypeAbsolute)
-#define YGPrintOptionsCount 3
-typedef YG_ENUM_BEGIN(YGPrintOptions) {
+YG_ENUM_DECL(
+ YGPrintOptions,
YGPrintOptionsLayout = 1,
YGPrintOptionsStyle = 2,
- YGPrintOptionsChildren = 4,
-} YG_ENUM_END(YGPrintOptions);
-WIN_EXPORT const char *YGPrintOptionsToString(const YGPrintOptions value);
+ YGPrintOptionsChildren = 4)
-#define YGUnitCount 4
-typedef YG_ENUM_BEGIN(YGUnit) {
+YG_ENUM_SEQ_DECL(
+ YGUnit,
YGUnitUndefined,
YGUnitPoint,
YGUnitPercent,
- YGUnitAuto,
-} YG_ENUM_END(YGUnit);
-WIN_EXPORT const char *YGUnitToString(const YGUnit value);
-
-#define YGWrapCount 3
-typedef YG_ENUM_BEGIN(YGWrap) {
- YGWrapNoWrap,
- YGWrapWrap,
- YGWrapWrapReverse,
-} YG_ENUM_END(YGWrap);
-WIN_EXPORT const char *YGWrapToString(const YGWrap value);
+ YGUnitAuto)
+
+YG_ENUM_SEQ_DECL(YGWrap, YGWrapNoWrap, YGWrapWrap, YGWrapWrapReverse)
YG_EXTERN_C_END
+
+#undef YG_ENUM_DECL
+#undef YG_ENUM_SEQ_DECL

ReactCommon/yoga/yoga/YGFloatOptional.cpp

@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 2014-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the LICENSE
- * file in the root directory of this source tree.
- *
- */
-#include "YGFloatOptional.h"
-#include <cstdlib>
-#include <iostream>
-#include "Yoga.h"
-#include "Yoga-internal.h"
-
-using namespace facebook;
-
-YGFloatOptional::YGFloatOptional(float value) {
- if (yoga::isUndefined(value)) {
- isUndefined_ = true;
- value_ = 0;
- } else {
- value_ = value;
- isUndefined_ = false;
- }
-}
-
-float YGFloatOptional::getValue() const {
- if (isUndefined_) {
- // Abort, accessing a value of an undefined float optional
- std::cerr << "Tried to get value of an undefined YGFloatOptional\n";
- std::exit(EXIT_FAILURE);
- }
- return value_;
-}
-
-bool YGFloatOptional::operator==(const YGFloatOptional& op) const {
- if (isUndefined_ == op.isUndefined()) {
- return isUndefined_ || value_ == op.getValue();
- }
- return false;
-}
-
-bool YGFloatOptional::operator!=(const YGFloatOptional& op) const {
- return !(*this == op);
-}
-
-bool YGFloatOptional::operator==(float val) const {
- if (yoga::isUndefined(val) == isUndefined_) {
- return isUndefined_ || val == value_;
- }
- return false;
-}
-
-bool YGFloatOptional::operator!=(float val) const {
- return !(*this == val);
-}
-
-YGFloatOptional YGFloatOptional::operator+(const YGFloatOptional& op) {
- if (!isUndefined_ && !op.isUndefined_) {
- return YGFloatOptional(value_ + op.value_);
- }
- return YGFloatOptional();
-}
-
-bool YGFloatOptional::operator>(const YGFloatOptional& op) const {
- if (isUndefined_ || op.isUndefined_) {
- return false;
- }
- return value_ > op.value_;
-}
-
-bool YGFloatOptional::operator<(const YGFloatOptional& op) const {
- if (isUndefined_ || op.isUndefined_) {
- return false;
- }
- return value_ < op.value_;
-}
-
-bool YGFloatOptional::operator>=(const YGFloatOptional& op) const {
- return *this == op || *this > op;
-}
-
-bool YGFloatOptional::operator<=(const YGFloatOptional& op) const {
- return *this == op || *this < op;
-}

ReactCommon/yoga/yoga/YGFloatOptional.h

@@ -1,44 +1,58 @@
-/*
- * Copyright (c) 2014-present, Facebook, Inc.
+/**
+ * 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.
- *
*/
#pragma once
+#include <cmath>
+#include <limits>
+#include "Yoga-internal.h"
+
struct YGFloatOptional {
- private:
- float value_;
- bool isUndefined_;
-
- public:
- explicit YGFloatOptional(float value);
- explicit YGFloatOptional() : value_(0), isUndefined_(true) {}
-
- // Program will terminate if the value of an undefined is accessed. Please
- // make sure to check if the optional is defined before calling this function.
- // To check if float optional is defined, use `isUndefined()`.
- float getValue() const;
-
- // Sets the value of float optional, and thus isUndefined is assigned false.
- void setValue(float val) {
- value_ = val;
- isUndefined_ = false;
+private:
+ float value_ = std::numeric_limits<float>::quiet_NaN();
+
+public:
+ explicit constexpr YGFloatOptional(float value) : value_(value) {}
+ constexpr YGFloatOptional() = default;
+
+ // returns the wrapped value, or a value x with YGIsUndefined(x) == true
+ constexpr float unwrap() const {
+ return value_;
}
bool isUndefined() const {
- return isUndefined_;
+ return std::isnan(value_);
}
- YGFloatOptional operator+(const YGFloatOptional& op);
- bool operator>(const YGFloatOptional& op) const;
- bool operator<(const YGFloatOptional& op) const;
- bool operator>=(const YGFloatOptional& op) const;
- bool operator<=(const YGFloatOptional& op) const;
- bool operator==(const YGFloatOptional& op) const;
- bool operator!=(const YGFloatOptional& op) const;
+ YGFloatOptional operator+(YGFloatOptional op) const {
+ return YGFloatOptional{value_ + op.value_};
+ }
+ bool operator>(YGFloatOptional op) const {
+ return value_ > op.value_;
+ }
+ bool operator<(YGFloatOptional op) const {
+ return value_ < op.value_;
+ }
+ bool operator>=(YGFloatOptional op) const {
+ return *this > op || *this == op;
+ }
+ bool operator<=(YGFloatOptional op) const {
+ return *this < op || *this == op;
+ }
+ bool operator==(YGFloatOptional op) const {
+ return value_ == op.value_ || (isUndefined() && op.isUndefined());
+ }
+ bool operator!=(YGFloatOptional op) const {
+ return !(*this == op);
+ }
- bool operator==(float val) const;
- bool operator!=(float val) const;
+ bool operator==(float val) const {
+ return value_ == val || (isUndefined() && yoga::isUndefined(val));
+ }
+ bool operator!=(float val) const {
+ return !(*this == val);
+ }
};

ReactCommon/yoga/yoga/YGLayout.cpp

@@ -1,37 +1,14 @@
-/*
- * Copyright (c) 2014-present, Facebook, Inc.
+/**
+ * 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.
- *
*/
#include "YGLayout.h"
#include "Utils.h"
using namespace facebook;
-const std::array<float, 2> kYGDefaultDimensionValues = {
- {YGUndefined, YGUndefined}};
-
-YGLayout::YGLayout()
- : position(),
- dimensions(kYGDefaultDimensionValues),
- margin(),
- border(),
- padding(),
- direction(YGDirectionInherit),
- computedFlexBasisGeneration(0),
- computedFlexBasis(YGFloatOptional()),
- hadOverflow(false),
- generationCount(0),
- lastOwnerDirection((YGDirection)-1),
- nextCachedMeasurementsIndex(0),
- cachedMeasurements(),
- measuredDimensions(kYGDefaultDimensionValues),
- cachedLayout(YGCachedMeasurement()),
- didUseLegacyFlag(false),
- doesLegacyStretchFlagAffectsLayout(false) {}
-
bool YGLayout::operator==(YGLayout layout) const {
bool isEqual = YGFloatArrayEqual(position, layout.position) &&
YGFloatArrayEqual(dimensions, layout.dimensions) &&

ReactCommon/yoga/yoga/YGLayout.h

@@ -1,41 +1,47 @@
-/*
- * Copyright (c) 2014-present, Facebook, Inc.
+/**
+ * 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.
- *
*/
#pragma once
#include "YGFloatOptional.h"
#include "Yoga-internal.h"
+constexpr std::array<float, 2> kYGDefaultDimensionValues = {
+ {YGUndefined, YGUndefined}};
+
struct YGLayout {
- std::array<float, 4> position;
- std::array<float, 2> dimensions;
- std::array<float, 6> margin;
- std::array<float, 6> border;
- std::array<float, 6> padding;
- YGDirection direction;
-
- uint32_t computedFlexBasisGeneration;
- YGFloatOptional computedFlexBasis;
- bool hadOverflow;
-
- // Instead of recomputing the entire layout every single time, we
- // cache some information to break early when nothing changed
- uint32_t generationCount;
- YGDirection lastOwnerDirection;
+ std::array<float, 4> position = {};
+ std::array<float, 2> dimensions = kYGDefaultDimensionValues;
+ std::array<float, 6> margin = {};
+ std::array<float, 6> border = {};
+ std::array<float, 6> padding = {};
+ YGDirection direction : 2;
+ bool didUseLegacyFlag : 1;
+ bool doesLegacyStretchFlagAffectsLayout : 1;
+ bool hadOverflow : 1;
+
+ uint32_t computedFlexBasisGeneration = 0;
+ YGFloatOptional computedFlexBasis = {};
+
+ // Instead of recomputing the entire layout every single time, we cache some
+ // information to break early when nothing changed
+ uint32_t generationCount = 0;
+ YGDirection lastOwnerDirection = (YGDirection) -1;
- uint32_t nextCachedMeasurementsIndex;
+ uint32_t nextCachedMeasurementsIndex = 0;
std::array<YGCachedMeasurement, YG_MAX_CACHED_RESULT_COUNT>
- cachedMeasurements;
- std::array<float, 2> measuredDimensions;
+ cachedMeasurements = {};
+ std::array<float, 2> measuredDimensions = kYGDefaultDimensionValues;
- YGCachedMeasurement cachedLayout;
- bool didUseLegacyFlag;
- bool doesLegacyStretchFlagAffectsLayout;
+ YGCachedMeasurement cachedLayout = YGCachedMeasurement();
- YGLayout();
+ YGLayout()
+ : direction(YGDirectionInherit),
+ didUseLegacyFlag(false),
+ doesLegacyStretchFlagAffectsLayout(false),
+ hadOverflow(false) {}
bool operator==(YGLayout layout) const;
bool operator!=(YGLayout layout) const {

ReactCommon/yoga/yoga/YGMacros.h

@@ -1,10 +1,9 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.
+ * This source code is licensed under the MIT license found in the LICENSE
+ * file in the root directory of this source tree.
*/
-
#pragma once
#ifdef __cplusplus
@@ -21,18 +20,10 @@
#define WIN_EXPORT
#endif
-#ifdef WINARMDLL
-#define WIN_STRUCT(type) type *
-#define WIN_STRUCT_REF(value) &value
-#else
-#define WIN_STRUCT(type) type
-#define WIN_STRUCT_REF(value) value
-#endif
-
#ifdef NS_ENUM
-// Cannot use NSInteger as NSInteger has a different size than int (which is the default type of a
-// enum).
-// Therefor when linking the Yoga C library into obj-c the header is a missmatch for the Yoga ABI.
+// Cannot use NSInteger as NSInteger has a different size than int (which is the
+// default type of a enum). Therefor when linking the Yoga C library into obj-c
+// the header is a missmatch for the Yoga ABI.
#define YG_ENUM_BEGIN(name) NS_ENUM(int, name)
#define YG_ENUM_END(name)
#else

ReactCommon/yoga/yoga/YGMarker.cpp

@@ -0,0 +1,14 @@
+/**
+ * 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.
+ */
+#include "YGMarker.h"
+#include "YGConfig.h"
+
+void YGConfigSetMarkerCallbacks(
+ YGConfigRef config,
+ YGMarkerCallbacks markerCallbacks) {
+ config->markerCallbacks = markerCallbacks;
+}

ReactCommon/yoga/yoga/YGMarker.h

@@ -0,0 +1,94 @@
+/**
+ * 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.
+ */
+#pragma once
+
+#include "YGMacros.h"
+
+YG_EXTERN_C_BEGIN
+
+typedef struct YGNode* YGNodeRef;
+typedef struct YGConfig* YGConfigRef;
+
+typedef YG_ENUM_BEGIN(YGMarker){
+ YGMarkerLayout,
+ YGMarkerMeasure,
+ YGMarkerBaselineFn,
+} YG_ENUM_END(YGMarker);
+
+typedef struct {
+ int layouts;
+ int measures;
+ int maxMeasureCache;
+ int cachedLayouts;
+ int cachedMeasures;
+} YGMarkerLayoutData;
+
+typedef struct {
+ bool _unused;
+} YGMarkerNoData;
+
+typedef union {
+ YGMarkerLayoutData* layout;
+ YGMarkerNoData* noData;
+} YGMarkerData;
+
+typedef struct {
+ // accepts marker type, a node ref, and marker data (depends on marker type)
+ // can return a handle or id that Yoga will pass to endMarker
+ void* (*startMarker)(YGMarker, YGNodeRef, YGMarkerData);
+ // accepts marker type, a node ref, marker data, and marker id as returned by
+ // startMarker
+ void (*endMarker)(YGMarker, YGNodeRef, YGMarkerData, void* id);
+} YGMarkerCallbacks;
+
+void YGConfigSetMarkerCallbacks(YGConfigRef, YGMarkerCallbacks);
+
+YG_EXTERN_C_END
+
+#ifdef __cplusplus
+
+namespace facebook {
+namespace yoga {
+namespace marker {
+namespace detail {
+
+template <YGMarker M>
+struct MarkerData;
+
+template <>
+struct MarkerData<YGMarkerLayout> {
+ using type = YGMarkerLayoutData;
+ static type*& get(YGMarkerData& d) {
+ return d.layout;
+ }
+};
+
+struct NoMarkerData {
+ using type = YGMarkerNoData;
+ static type*& get(YGMarkerData& d) {
+ return d.noData;
+ }
+};
+
+template <>
+struct MarkerData<YGMarkerMeasure> : NoMarkerData {};
+
+template <>
+struct MarkerData<YGMarkerBaselineFn> : NoMarkerData {};
+
+} // namespace detail
+
+template <YGMarker M>
+typename detail::MarkerData<M>::type* data(YGMarkerData d) {
+ return detail::MarkerData<M>::get(d);
+}
+
+} // namespace marker
+} // namespace yoga
+} // namespace facebook
+
+#endif // __cplusplus

ReactCommon/yoga/yoga/YGNode.cpp

@@ -1,99 +1,103 @@
-/*
- * Copyright (c) 2014-present, Facebook, Inc.
+/**
+ * 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.
- *
*/
#include "YGNode.h"
#include <iostream>
+#include "CompactValue.h"
#include "Utils.h"
using namespace facebook;
+using facebook::yoga::detail::CompactValue;
YGFloatOptional YGNode::getLeadingPosition(
- const YGFlexDirection& axis,
- const float& axisSize) const {
+ const YGFlexDirection axis,
+ const float axisSize) const {
if (YGFlexDirectionIsRow(axis)) {
- const YGValue* leadingPosition =
- YGComputedEdgeValue(style_.position, YGEdgeStart, &YGValueUndefined);
- if (leadingPosition->unit != YGUnitUndefined) {
- return YGResolveValue(*leadingPosition, axisSize);
+ auto leadingPosition = YGComputedEdgeValue(
+ style_.position, YGEdgeStart, CompactValue::ofUndefined());
+ if (!leadingPosition.isUndefined()) {
+ return YGResolveValue(leadingPosition, axisSize);
}
}
- const YGValue* leadingPosition =
- YGComputedEdgeValue(style_.position, leading[axis], &YGValueUndefined);
+ auto leadingPosition = YGComputedEdgeValue(
+ style_.position, leading[axis], CompactValue::ofUndefined());
- return leadingPosition->unit == YGUnitUndefined
- ? YGFloatOptional(0)
- : YGResolveValue(*leadingPosition, axisSize);
+ return leadingPosition.isUndefined()
+ ? YGFloatOptional{0}
+ : YGResolveValue(leadingPosition, axisSize);
}
YGFloatOptional YGNode::getTrailingPosition(
- const YGFlexDirection& axis,
- const float& axisSize) const {
+ const YGFlexDirection axis,
+ const float axisSize) const {
if (YGFlexDirectionIsRow(axis)) {
- const YGValue* trailingPosition =
- YGComputedEdgeValue(style_.position, YGEdgeEnd, &YGValueUndefined);
- if (trailingPosition->unit != YGUnitUndefined) {
- return YGResolveValue(*trailingPosition, axisSize);
+ auto trailingPosition = YGComputedEdgeValue(
+ style_.position, YGEdgeEnd, CompactValue::ofUndefined());
+ if (!trailingPosition.isUndefined()) {
+ return YGResolveValue(trailingPosition, axisSize);
}
}
- const YGValue* trailingPosition =
- YGComputedEdgeValue(style_.position, trailing[axis], &YGValueUndefined);
+ auto trailingPosition = YGComputedEdgeValue(
+ style_.position, trailing[axis], CompactValue::ofUndefined());
- return trailingPosition->unit == YGUnitUndefined
- ? YGFloatOptional(0)
- : YGResolveValue(*trailingPosition, axisSize);
+ return trailingPosition.isUndefined()
+ ? YGFloatOptional{0}
+ : YGResolveValue(trailingPosition, axisSize);
}
-bool YGNode::isLeadingPositionDefined(const YGFlexDirection& axis) const {
+bool YGNode::isLeadingPositionDefined(const YGFlexDirection axis) const {
return (YGFlexDirectionIsRow(axis) &&
- YGComputedEdgeValue(style_.position, YGEdgeStart, &YGValueUndefined)
- ->unit != YGUnitUndefined) ||
- YGComputedEdgeValue(style_.position, leading[axis], &YGValueUndefined)
- ->unit != YGUnitUndefined;
+ !YGComputedEdgeValue(
+ style_.position, YGEdgeStart, CompactValue::ofUndefined())
+ .isUndefined()) ||
+ !YGComputedEdgeValue(
+ style_.position, leading[axis], CompactValue::ofUndefined())
+ .isUndefined();
}
-bool YGNode::isTrailingPosDefined(const YGFlexDirection& axis) const {
+bool YGNode::isTrailingPosDefined(const YGFlexDirection axis) const {
return (YGFlexDirectionIsRow(axis) &&
- YGComputedEdgeValue(style_.position, YGEdgeEnd, &YGValueUndefined)
- ->unit != YGUnitUndefined) ||
- YGComputedEdgeValue(style_.position, trailing[axis], &YGValueUndefined)
- ->unit != YGUnitUndefined;
+ !YGComputedEdgeValue(
+ style_.position, YGEdgeEnd, CompactValue::ofUndefined())
+ .isUndefined()) ||
+ !YGComputedEdgeValue(
+ style_.position, trailing[axis], CompactValue::ofUndefined())
+ .isUndefined();
}
YGFloatOptional YGNode::getLeadingMargin(
- const YGFlexDirection& axis,
- const float& widthSize) const {
- if (YGFlexDirectionIsRow(axis) &&
- style_.margin[YGEdgeStart].unit != YGUnitUndefined) {
+ const YGFlexDirection axis,
+ const float widthSize) const {
+ if (YGFlexDirectionIsRow(axis) && !style_.margin[YGEdgeStart].isUndefined()) {
return YGResolveValueMargin(style_.margin[YGEdgeStart], widthSize);
}
return YGResolveValueMargin(
- *YGComputedEdgeValue(style_.margin, leading[axis], &YGValueZero),
+ YGComputedEdgeValue(style_.margin, leading[axis], CompactValue::ofZero()),
widthSize);
}
YGFloatOptional YGNode::getTrailingMargin(
- const YGFlexDirection& axis,
- const float& widthSize) const {
- if (YGFlexDirectionIsRow(axis) &&
- style_.margin[YGEdgeEnd].unit != YGUnitUndefined) {
+ const YGFlexDirection axis,
+ const float widthSize) const {
+ if (YGFlexDirectionIsRow(axis) && !style_.margin[YGEdgeEnd].isUndefined()) {
return YGResolveValueMargin(style_.margin[YGEdgeEnd], widthSize);
}
return YGResolveValueMargin(
- *YGComputedEdgeValue(style_.margin, trailing[axis], &YGValueZero),
+ YGComputedEdgeValue(
+ style_.margin, trailing[axis], CompactValue::ofZero()),
widthSize);
}
YGFloatOptional YGNode::getMarginForAxis(
- const YGFlexDirection& axis,
- const float& widthSize) const {
+ const YGFlexDirection axis,
+ const float widthSize) const {
return getLeadingMargin(axis, widthSize) + getTrailingMargin(axis, widthSize);
}
@@ -109,7 +113,8 @@
YGAssertWithNode(
this,
children_.size() == 0,
- "Cannot set measure function: Nodes with measure functions cannot have children.");
+ "Cannot set measure function: Nodes with measure functions cannot have "
+ "children.");
measure_ = measureFunc;
// TODO: t18095186 Move nodeType to opt-in function and mark appropriate
// places in Litho
@@ -176,7 +181,7 @@
}
void YGNode::setLayoutComputedFlexBasis(
- const YGFloatOptional& computedFlexBasis) {
+ const YGFloatOptional computedFlexBasis) {
layout_.computedFlexBasis = computedFlexBasis;
}
@@ -201,18 +206,18 @@
layout_.dimensions[index] = dimension;
}
-// If both left and right are defined, then use left. Otherwise return
-// +left or -right depending on which is defined.
+// If both left and right are defined, then use left. Otherwise return +left or
+// -right depending on which is defined.
YGFloatOptional YGNode::relativePosition(
- const YGFlexDirection& axis,
- const float& axisSize) const {
+ const YGFlexDirection axis,
+ const float axisSize) const {
if (isLeadingPositionDefined(axis)) {
return getLeadingPosition(axis, axisSize);
}
YGFloatOptional trailingPosition = getTrailingPosition(axis, axisSize);
if (!trailingPosition.isUndefined()) {
- trailingPosition.setValue(-1 * trailingPosition.getValue());
+ trailingPosition = YGFloatOptional{-1 * trailingPosition.unwrap()};
}
return trailingPosition;
}
@@ -237,20 +242,18 @@
relativePosition(crossAxis, crossSize);
setLayoutPosition(
- YGUnwrapFloatOptional(
- getLeadingMargin(mainAxis, ownerWidth) + relativePositionMain),
+ (getLeadingMargin(mainAxis, ownerWidth) + relativePositionMain).unwrap(),
leading[mainAxis]);
setLayoutPosition(
- YGUnwrapFloatOptional(
- getTrailingMargin(mainAxis, ownerWidth) + relativePositionMain),
+ (getTrailingMargin(mainAxis, ownerWidth) + relativePositionMain).unwrap(),
trailing[mainAxis]);
setLayoutPosition(
- YGUnwrapFloatOptional(
- getLeadingMargin(crossAxis, ownerWidth) + relativePositionCross),
+ (getLeadingMargin(crossAxis, ownerWidth) + relativePositionCross)
+ .unwrap(),
leading[crossAxis]);
setLayoutPosition(
- YGUnwrapFloatOptional(
- getTrailingMargin(crossAxis, ownerWidth) + relativePositionCross),
+ (getTrailingMargin(crossAxis, ownerWidth) + relativePositionCross)
+ .unwrap(),
trailing[crossAxis]);
}
@@ -283,8 +286,7 @@
}
YGValue YGNode::marginLeadingValue(const YGFlexDirection axis) const {
- if (YGFlexDirectionIsRow(axis) &&
- style_.margin[YGEdgeStart].unit != YGUnitUndefined) {
+ if (YGFlexDirectionIsRow(axis) && !style_.margin[YGEdgeStart].isUndefined()) {
return style_.margin[YGEdgeStart];
} else {
return style_.margin[leading[axis]];
@@ -292,8 +294,7 @@
}
YGValue YGNode::marginTrailingValue(const YGFlexDirection axis) const {
- if (YGFlexDirectionIsRow(axis) &&
- style_.margin[YGEdgeEnd].unit != YGUnitUndefined) {
+ if (YGFlexDirectionIsRow(axis) && !style_.margin[YGEdgeEnd].isUndefined()) {
return style_.margin[YGEdgeEnd];
} else {
return style_.margin[trailing[axis]];
@@ -305,15 +306,16 @@
if (flexBasis.unit != YGUnitAuto && flexBasis.unit != YGUnitUndefined) {
return flexBasis;
}
- if (!style_.flex.isUndefined() && style_.flex.getValue() > 0.0f) {
+ if (!style_.flex.isUndefined() && style_.flex.unwrap() > 0.0f) {
return config_->useWebDefaults ? YGValueAuto : YGValueZero;
}
return YGValueAuto;
}
void YGNode::resolveDimension() {
- for (uint32_t dim = YGDimensionWidth; dim < YGDimensionCount; dim++) {
- if (getStyle().maxDimensions[dim].unit != YGUnitUndefined &&
+ using namespace yoga;
+ for (int dim = YGDimensionWidth; dim < enums::count<YGDimension>(); dim++) {
+ if (!getStyle().maxDimensions[dim].isUndefined() &&
YGValueEqual(
getStyle().maxDimensions[dim], style_.minDimensions[dim])) {
resolvedDimensions_[dim] = style_.maxDimensions[dim];
@@ -396,10 +398,10 @@
return 0.0;
}
if (!style_.flexGrow.isUndefined()) {
- return style_.flexGrow.getValue();
+ return style_.flexGrow.unwrap();
}
- if (!style_.flex.isUndefined() && style_.flex.getValue() > 0.0f) {
- return style_.flex.getValue();
+ if (!style_.flex.isUndefined() && style_.flex.unwrap() > 0.0f) {
+ return style_.flex.unwrap();
}
return kDefaultFlexGrow;
}
@@ -409,11 +411,11 @@
return 0.0;
}
if (!style_.flexShrink.isUndefined()) {
- return style_.flexShrink.getValue();
+ return style_.flexShrink.unwrap();
}
if (!config_->useWebDefaults && !style_.flex.isUndefined() &&
- style_.flex.getValue() < 0.0f) {
- return -style_.flex.getValue();
+ style_.flex.unwrap() < 0.0f) {
+ return -style_.flex.unwrap();
}
return config_->useWebDefaults ? kWebDefaultFlexShrink : kDefaultFlexShrink;
}
@@ -424,77 +426,80 @@
(resolveFlexGrow() != 0 || resolveFlexShrink() != 0));
}
-float YGNode::getLeadingBorder(const YGFlexDirection& axis) const {
- if (YGFlexDirectionIsRow(axis) &&
- style_.border[YGEdgeStart].unit != YGUnitUndefined &&
- !yoga::isUndefined(style_.border[YGEdgeStart].value) &&
- style_.border[YGEdgeStart].value >= 0.0f) {
- return style_.border[YGEdgeStart].value;
+float YGNode::getLeadingBorder(const YGFlexDirection axis) const {
+ YGValue leadingBorder;
+ if (YGFlexDirectionIsRow(axis) && !style_.border[YGEdgeStart].isUndefined()) {
+ leadingBorder = style_.border[YGEdgeStart];
+ if (leadingBorder.value >= 0) {
+ return leadingBorder.value;
+ }
}
- float computedEdgeValue =
- YGComputedEdgeValue(style_.border, leading[axis], &YGValueZero)->value;
- return YGFloatMax(computedEdgeValue, 0.0f);
+ leadingBorder =
+ YGComputedEdgeValue(style_.border, leading[axis], CompactValue::ofZero());
+ return YGFloatMax(leadingBorder.value, 0.0f);
}
-float YGNode::getTrailingBorder(const YGFlexDirection& flexDirection) const {
+float YGNode::getTrailingBorder(const YGFlexDirection flexDirection) const {
+ YGValue trailingBorder;
if (YGFlexDirectionIsRow(flexDirection) &&
- style_.border[YGEdgeEnd].unit != YGUnitUndefined &&
- !yoga::isUndefined(style_.border[YGEdgeEnd].value) &&
- style_.border[YGEdgeEnd].value >= 0.0f) {
- return style_.border[YGEdgeEnd].value;
+ !style_.border[YGEdgeEnd].isUndefined()) {
+ trailingBorder = style_.border[YGEdgeEnd];
+ if (trailingBorder.value >= 0.0f) {
+ return trailingBorder.value;
+ }
}
- float computedEdgeValue =
- YGComputedEdgeValue(style_.border, trailing[flexDirection], &YGValueZero)
- ->value;
- return YGFloatMax(computedEdgeValue, 0.0f);
+ trailingBorder = YGComputedEdgeValue(
+ style_.border, trailing[flexDirection], CompactValue::ofZero());
+ return YGFloatMax(trailingBorder.value, 0.0f);
}
YGFloatOptional YGNode::getLeadingPadding(
- const YGFlexDirection& axis,
- const float& widthSize) const {
- const YGFloatOptional& paddingEdgeStart =
+ const YGFlexDirection axis,
+ const float widthSize) const {
+ const YGFloatOptional paddingEdgeStart =
YGResolveValue(style_.padding[YGEdgeStart], widthSize);
if (YGFlexDirectionIsRow(axis) &&
- style_.padding[YGEdgeStart].unit != YGUnitUndefined &&
- !paddingEdgeStart.isUndefined() && paddingEdgeStart.getValue() > 0.0f) {
+ !style_.padding[YGEdgeStart].isUndefined() &&
+ !paddingEdgeStart.isUndefined() && paddingEdgeStart.unwrap() >= 0.0f) {
return paddingEdgeStart;
}
YGFloatOptional resolvedValue = YGResolveValue(
- *YGComputedEdgeValue(style_.padding, leading[axis], &YGValueZero),
+ YGComputedEdgeValue(
+ style_.padding, leading[axis], CompactValue::ofZero()),
widthSize);
return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f));
}
YGFloatOptional YGNode::getTrailingPadding(
- const YGFlexDirection& axis,
- const float& widthSize) const {
- if (YGFlexDirectionIsRow(axis) &&
- style_.padding[YGEdgeEnd].unit != YGUnitUndefined &&
- !YGResolveValue(style_.padding[YGEdgeEnd], widthSize).isUndefined() &&
- YGResolveValue(style_.padding[YGEdgeEnd], widthSize).getValue() >= 0.0f) {
- return YGResolveValue(style_.padding[YGEdgeEnd], widthSize);
+ const YGFlexDirection axis,
+ const float widthSize) const {
+ const YGFloatOptional paddingEdgeEnd =
+ YGResolveValue(style_.padding[YGEdgeEnd], widthSize);
+ if (YGFlexDirectionIsRow(axis) && paddingEdgeEnd >= YGFloatOptional{0.0f}) {
+ return paddingEdgeEnd;
}
YGFloatOptional resolvedValue = YGResolveValue(
- *YGComputedEdgeValue(style_.padding, trailing[axis], &YGValueZero),
+ YGComputedEdgeValue(
+ style_.padding, trailing[axis], CompactValue::ofZero()),
widthSize);
return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f));
}
YGFloatOptional YGNode::getLeadingPaddingAndBorder(
- const YGFlexDirection& axis,
- const float& widthSize) const {
+ const YGFlexDirection axis,
+ const float widthSize) const {
return getLeadingPadding(axis, widthSize) +
YGFloatOptional(getLeadingBorder(axis));
}
YGFloatOptional YGNode::getTrailingPaddingAndBorder(
- const YGFlexDirection& axis,
- const float& widthSize) const {
+ const YGFlexDirection axis,
+ const float widthSize) const {
return getTrailingPadding(axis, widthSize) +
YGFloatOptional(getTrailingBorder(axis));
}

ReactCommon/yoga/yoga/YGNode.h

@@ -1,9 +1,8 @@
-/*
- * Copyright (c) 2014-present, Facebook, Inc.
+/**
+ * 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.
- *
*/
#pragma once
#include <stdio.h>
@@ -13,11 +12,13 @@
#include "Yoga-internal.h"
struct YGNode {
- private:
+private:
void* context_ = nullptr;
YGPrintFunc print_ = nullptr;
- bool hasNewLayout_ = true;
- YGNodeType nodeType_ = YGNodeTypeDefault;
+ bool hasNewLayout_ : 1;
+ bool isReferenceBaseline_ : 1;
+ bool isDirty_ : 1;
+ YGNodeType nodeType_ : 1;
YGMeasureFunc measure_ = nullptr;
YGBaselineFunc baseline_ = nullptr;
YGDirtiedFunc dirtied_ = nullptr;
@@ -27,16 +28,19 @@
YGNodeRef owner_ = nullptr;
YGVector children_ = {};
YGConfigRef config_ = nullptr;
- bool isDirty_ = false;
std::array<YGValue, 2> resolvedDimensions_ = {
{YGValueUndefined, YGValueUndefined}};
YGFloatOptional relativePosition(
- const YGFlexDirection& axis,
- const float& axisSize) const;
+ const YGFlexDirection axis,
+ const float axisSize) const;
- public:
- YGNode() = default;
+public:
+ YGNode()
+ : hasNewLayout_(true),
+ isReferenceBaseline_(false),
+ isDirty_(false),
+ nodeType_(YGNodeTypeDefault) {}
~YGNode() = default; // cleanup of owner/children relationships in YGNodeFree
explicit YGNode(const YGConfigRef newConfig) : config_(newConfig){};
YGNode(const YGNode& node) = default;
@@ -93,11 +97,14 @@
return lineIndex_;
}
+ bool isReferenceBaseline() {
+ return isReferenceBaseline_;
+ }
+
// returns the YGNodeRef that owns this YGNode. An owner is used to identify
- // the YogaTree that a YGNode belongs to.
- // This method will return the parent of the YGNode when a YGNode only belongs
- // to one YogaTree or nullptr when the YGNode is shared between two or more
- // YogaTrees.
+ // the YogaTree that a YGNode belongs to. This method will return the parent
+ // of the YGNode when a YGNode only belongs to one YogaTree or nullptr when
+ // the YGNode is shared between two or more YogaTrees.
YGNodeRef getOwner() const {
return owner_;
}
@@ -133,36 +140,36 @@
// Methods related to positions, margin, padding and border
YGFloatOptional getLeadingPosition(
- const YGFlexDirection& axis,
- const float& axisSize) const;
- bool isLeadingPositionDefined(const YGFlexDirection& axis) const;
- bool isTrailingPosDefined(const YGFlexDirection& axis) const;
+ const YGFlexDirection axis,
+ const float axisSize) const;
+ bool isLeadingPositionDefined(const YGFlexDirection axis) const;
+ bool isTrailingPosDefined(const YGFlexDirection axis) const;
YGFloatOptional getTrailingPosition(
- const YGFlexDirection& axis,
- const float& axisSize) const;
+ const YGFlexDirection axis,
+ const float axisSize) const;
YGFloatOptional getLeadingMargin(
- const YGFlexDirection& axis,
- const float& widthSize) const;
+ const YGFlexDirection axis,
+ const float widthSize) const;
YGFloatOptional getTrailingMargin(
- const YGFlexDirection& axis,
- const float& widthSize) const;
- float getLeadingBorder(const YGFlexDirection& flexDirection) const;
- float getTrailingBorder(const YGFlexDirection& flexDirection) const;
+ const YGFlexDirection axis,
+ const float widthSize) const;
+ float getLeadingBorder(const YGFlexDirection flexDirection) const;
+ float getTrailingBorder(const YGFlexDirection flexDirection) const;
YGFloatOptional getLeadingPadding(
- const YGFlexDirection& axis,
- const float& widthSize) const;
+ const YGFlexDirection axis,
+ const float widthSize) const;
YGFloatOptional getTrailingPadding(
- const YGFlexDirection& axis,
- const float& widthSize) const;
+ const YGFlexDirection axis,
+ const float widthSize) const;
YGFloatOptional getLeadingPaddingAndBorder(
- const YGFlexDirection& axis,
- const float& widthSize) const;
+ const YGFlexDirection axis,
+ const float widthSize) const;
YGFloatOptional getTrailingPaddingAndBorder(
- const YGFlexDirection& axis,
- const float& widthSize) const;
+ const YGFlexDirection axis,
+ const float widthSize) const;
YGFloatOptional getMarginForAxis(
- const YGFlexDirection& axis,
- const float& widthSize) const;
+ const YGFlexDirection axis,
+ const float widthSize) const;
// Setters
void setContext(void* context) {
@@ -211,6 +218,10 @@
lineIndex_ = lineIndex;
}
+ void setIsReferenceBaseline(bool isReferenceBaseline) {
+ isReferenceBaseline_ = isReferenceBaseline;
+ }
+
void setOwner(YGNodeRef owner) {
owner_ = owner;
}
@@ -227,7 +238,7 @@
void setDirty(bool isDirty);
void setLayoutLastOwnerDirection(YGDirection direction);
- void setLayoutComputedFlexBasis(const YGFloatOptional& computedFlexBasis);
+ void setLayoutComputedFlexBasis(const YGFloatOptional computedFlexBasis);
void setLayoutComputedFlexBasisGeneration(
uint32_t computedFlexBasisGeneration);
void setLayoutMeasuredDimension(float measuredDimension, int index);

ReactCommon/yoga/yoga/YGNodePrint.cpp

@@ -1,10 +1,9 @@
-/*
- * Copyright (c) 2017-present, Facebook, Inc.
+/**
+ * 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.
+ * This source code is licensed under the MIT license found in the LICENSE
+ * file in the root directory of this source tree.
*/
-
#include "YGNodePrint.h"
#include <stdarg.h>
#include "YGEnums.h"
@@ -15,18 +14,18 @@
namespace yoga {
typedef std::string string;
-static void indent(string* base, uint32_t level) {
+static void indent(string& base, uint32_t level) {
for (uint32_t i = 0; i < level; ++i) {
- base->append(" ");
+ base.append(" ");
}
}
-static bool areFourValuesEqual(const std::array<YGValue, YGEdgeCount>& four) {
+static bool areFourValuesEqual(const YGStyle::Edges& four) {
return YGValueEqual(four[0], four[1]) && YGValueEqual(four[0], four[2]) &&
YGValueEqual(four[0], four[3]);
}
-static void appendFormatedString(string* str, const char* fmt, ...) {
+static void appendFormatedString(string& str, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
va_list argsCopy;
@@ -36,25 +35,25 @@
vsnprintf(buf.data(), buf.size(), fmt, argsCopy);
va_end(argsCopy);
string result = string(buf.begin(), buf.end() - 1);
- str->append(result);
+ str.append(result);
}
static void appendFloatOptionalIfDefined(
- string* base,
+ string& base,
const string key,
const YGFloatOptional num) {
if (!num.isUndefined()) {
- appendFormatedString(base, "%s: %g; ", key.c_str(), num.getValue());
+ appendFormatedString(base, "%s: %g; ", key.c_str(), num.unwrap());
}
}
static void appendNumberIfNotUndefined(
- string* base,
+ string& base,
const string key,
const YGValue number) {
if (number.unit != YGUnitUndefined) {
if (number.unit == YGUnitAuto) {
- base->append(key + ": auto; ");
+ base.append(key + ": auto; ");
} else {
string unit = number.unit == YGUnitPoint ? "px" : "%%";
appendFormatedString(
@@ -63,27 +62,30 @@
}
}
-static void
-appendNumberIfNotAuto(string* base, const string& key, const YGValue number) {
+static void appendNumberIfNotAuto(
+ string& base,
+ const string& key,
+ const YGValue number) {
if (number.unit != YGUnitAuto) {
appendNumberIfNotUndefined(base, key, number);
}
}
-static void
-appendNumberIfNotZero(string* base, const string& str, const YGValue number) {
-
+static void appendNumberIfNotZero(
+ string& base,
+ const string& str,
+ const YGValue number) {
if (number.unit == YGUnitAuto) {
- base->append(str + ": auto; ");
+ base.append(str + ": auto; ");
} else if (!YGFloatsEqual(number.value, 0)) {
appendNumberIfNotUndefined(base, str, number);
}
}
static void appendEdges(
- string* base,
+ string& base,
const string& key,
- const std::array<YGValue, YGEdgeCount>& edges) {
+ const YGStyle::Edges& edges) {
if (areFourValuesEqual(edges)) {
appendNumberIfNotZero(base, key, edges[YGEdgeLeft]);
} else {
@@ -95,16 +97,18 @@
}
static void appendEdgeIfNotUndefined(
- string* base,
+ string& base,
const string& str,
- const std::array<YGValue, YGEdgeCount>& edges,
+ const YGStyle::Edges& edges,
const YGEdge edge) {
appendNumberIfNotUndefined(
- base, str, *YGComputedEdgeValue(edges, edge, &YGValueUndefined));
+ base,
+ str,
+ YGComputedEdgeValue(edges, edge, detail::CompactValue::ofUndefined()));
}
void YGNodeToString(
- std::string* str,
+ std::string& str,
YGNodeRef node,
YGPrintOptions options,
uint32_t level) {

ReactCommon/yoga/yoga/YGNodePrint.h

@@ -1,8 +1,8 @@
/**
- * Copyright (c) 2014-present, Facebook, Inc.
+ * 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.
+ * This source code is licensed under the MIT license found in the LICENSE
+ * file in the root directory of this source tree.
*/
#pragma once
#include <string>
@@ -13,7 +13,7 @@
namespace yoga {
void YGNodeToString(
- std::string* str,
+ std::string& str,
YGNodeRef node,
YGPrintOptions options,
uint32_t level);

ReactCommon/yoga/yoga/YGStyle.cpp

@@ -1,99 +1,50 @@
-/*
- * Copyright (c) 2014-present, Facebook, Inc.
+/**
+ * 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.
- *
*/
#include "YGStyle.h"
-const YGValue kYGValueUndefined = {0, YGUnitUndefined};
-
-const YGValue kYGValueAuto = {0, YGUnitAuto};
-
-const std::array<YGValue, YGEdgeCount> kYGDefaultEdgeValuesUnit = {
- {kYGValueUndefined,
- kYGValueUndefined,
- kYGValueUndefined,
- kYGValueUndefined,
- kYGValueUndefined,
- kYGValueUndefined,
- kYGValueUndefined,
- kYGValueUndefined,
- kYGValueUndefined}};
-
-const std::array<YGValue, 2> kYGDefaultDimensionValuesAutoUnit = {
- {kYGValueAuto, kYGValueAuto}};
-
-const std::array<YGValue, 2> kYGDefaultDimensionValuesUnit = {
- {kYGValueUndefined, kYGValueUndefined}};
-
-YGStyle::YGStyle()
- : direction(YGDirectionInherit),
- flexDirection(YGFlexDirectionColumn),
- justifyContent(YGJustifyFlexStart),
- alignContent(YGAlignFlexStart),
- alignItems(YGAlignStretch),
- alignSelf(YGAlignAuto),
- positionType(YGPositionTypeRelative),
- flexWrap(YGWrapNoWrap),
- overflow(YGOverflowVisible),
- display(YGDisplayFlex),
- flex(YGFloatOptional()),
- flexGrow(YGFloatOptional()),
- flexShrink(YGFloatOptional()),
- flexBasis(kYGValueAuto),
- margin(kYGDefaultEdgeValuesUnit),
- position(kYGDefaultEdgeValuesUnit),
- padding(kYGDefaultEdgeValuesUnit),
- border(kYGDefaultEdgeValuesUnit),
- dimensions(kYGDefaultDimensionValuesAutoUnit),
- minDimensions(kYGDefaultDimensionValuesUnit),
- maxDimensions(kYGDefaultDimensionValuesUnit),
- aspectRatio(YGFloatOptional()) {}
-
// Yoga specific properties, not compatible with flexbox specification
-bool YGStyle::operator==(const YGStyle& style) {
- bool areNonFloatValuesEqual = direction == style.direction &&
- flexDirection == style.flexDirection &&
- justifyContent == style.justifyContent &&
- alignContent == style.alignContent && alignItems == style.alignItems &&
- alignSelf == style.alignSelf && positionType == style.positionType &&
- flexWrap == style.flexWrap && overflow == style.overflow &&
- display == style.display && YGValueEqual(flexBasis, style.flexBasis) &&
- YGValueArrayEqual(margin, style.margin) &&
- YGValueArrayEqual(position, style.position) &&
- YGValueArrayEqual(padding, style.padding) &&
- YGValueArrayEqual(border, style.border) &&
- YGValueArrayEqual(dimensions, style.dimensions) &&
- YGValueArrayEqual(minDimensions, style.minDimensions) &&
- YGValueArrayEqual(maxDimensions, style.maxDimensions);
+bool operator==(const YGStyle& lhs, const YGStyle& rhs) {
+ bool areNonFloatValuesEqual = lhs.direction == rhs.direction &&
+ lhs.flexDirection == rhs.flexDirection &&
+ lhs.justifyContent == rhs.justifyContent &&
+ lhs.alignContent == rhs.alignContent &&
+ lhs.alignItems == rhs.alignItems && lhs.alignSelf == rhs.alignSelf &&
+ lhs.positionType == rhs.positionType && lhs.flexWrap == rhs.flexWrap &&
+ lhs.overflow == rhs.overflow && lhs.display == rhs.display &&
+ YGValueEqual(lhs.flexBasis, rhs.flexBasis) && lhs.margin == rhs.margin &&
+ lhs.position == rhs.position && lhs.padding == rhs.padding &&
+ lhs.border == rhs.border && lhs.dimensions == rhs.dimensions &&
+ lhs.minDimensions == rhs.minDimensions &&
+ lhs.maxDimensions == rhs.maxDimensions;
- areNonFloatValuesEqual =
- areNonFloatValuesEqual && flex.isUndefined() == style.flex.isUndefined();
- if (areNonFloatValuesEqual && !flex.isUndefined() &&
- !style.flex.isUndefined()) {
- areNonFloatValuesEqual =
- areNonFloatValuesEqual && flex.getValue() == style.flex.getValue();
+ areNonFloatValuesEqual = areNonFloatValuesEqual &&
+ lhs.flex.isUndefined() == rhs.flex.isUndefined();
+ if (areNonFloatValuesEqual && !lhs.flex.isUndefined() &&
+ !rhs.flex.isUndefined()) {
+ areNonFloatValuesEqual = areNonFloatValuesEqual && lhs.flex == rhs.flex;
}
areNonFloatValuesEqual = areNonFloatValuesEqual &&
- flexGrow.isUndefined() == style.flexGrow.isUndefined();
- if (areNonFloatValuesEqual && !flexGrow.isUndefined()) {
- areNonFloatValuesEqual = areNonFloatValuesEqual &&
- flexGrow.getValue() == style.flexGrow.getValue();
+ lhs.flexGrow.isUndefined() == rhs.flexGrow.isUndefined();
+ if (areNonFloatValuesEqual && !lhs.flexGrow.isUndefined()) {
+ areNonFloatValuesEqual =
+ areNonFloatValuesEqual && lhs.flexGrow == rhs.flexGrow;
}
areNonFloatValuesEqual = areNonFloatValuesEqual &&
- flexShrink.isUndefined() == style.flexShrink.isUndefined();
- if (areNonFloatValuesEqual && !style.flexShrink.isUndefined()) {
- areNonFloatValuesEqual = areNonFloatValuesEqual &&
- flexShrink.getValue() == style.flexShrink.getValue();
+ lhs.flexShrink.isUndefined() == rhs.flexShrink.isUndefined();
+ if (areNonFloatValuesEqual && !rhs.flexShrink.isUndefined()) {
+ areNonFloatValuesEqual =
+ areNonFloatValuesEqual && lhs.flexShrink == rhs.flexShrink;
}
- if (!(aspectRatio.isUndefined() && style.aspectRatio.isUndefined())) {
- areNonFloatValuesEqual = areNonFloatValuesEqual &&
- aspectRatio.getValue() == style.aspectRatio.getValue();
+ if (!(lhs.aspectRatio.isUndefined() && rhs.aspectRatio.isUndefined())) {
+ areNonFloatValuesEqual =
+ areNonFloatValuesEqual && lhs.aspectRatio == rhs.aspectRatio;
}
return areNonFloatValuesEqual;

ReactCommon/yoga/yoga/YGStyle.h

@@ -1,45 +1,75 @@
-/*
- * Copyright (c) 2014-present, Facebook, Inc.
+/**
+ * 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.
- *
*/
#pragma once
+#include <algorithm>
+#include <array>
+#include <initializer_list>
+#include "CompactValue.h"
+#include "YGEnums.h"
#include "YGFloatOptional.h"
#include "Yoga-internal.h"
#include "Yoga.h"
+#if !defined(ENUM_BITFIELDS_NOT_SUPPORTED)
+#define BITFIELD_ENUM_SIZED(num) : num
+#else
+#define BITFIELD_ENUM_SIZED(num)
+#endif
+
struct YGStyle {
- YGDirection direction;
- YGFlexDirection flexDirection;
- YGJustify justifyContent;
- YGAlign alignContent;
- YGAlign alignItems;
- YGAlign alignSelf;
- YGPositionType positionType;
- YGWrap flexWrap;
- YGOverflow overflow;
- YGDisplay display;
- YGFloatOptional flex;
- YGFloatOptional flexGrow;
- YGFloatOptional flexShrink;
- YGValue flexBasis;
- std::array<YGValue, YGEdgeCount> margin;
- std::array<YGValue, YGEdgeCount> position;
- std::array<YGValue, YGEdgeCount> padding;
- std::array<YGValue, YGEdgeCount> border;
- std::array<YGValue, 2> dimensions;
- std::array<YGValue, 2> minDimensions;
- std::array<YGValue, 2> maxDimensions;
- // Yoga specific properties, not compatible with flexbox specification
- YGFloatOptional aspectRatio;
+private:
+ using CompactValue = facebook::yoga::detail::CompactValue;
- YGStyle();
- bool operator==(const YGStyle& style);
+public:
+ using Dimensions = facebook::yoga::detail::Values<2>;
+ using Edges =
+ facebook::yoga::detail::Values<facebook::yoga::enums::count<YGEdge>()>;
- bool operator!=(YGStyle style) {
- return !(*this == style);
- }
+ /* Some platforms don't support enum bitfields,
+ so please use BITFIELD_ENUM_SIZED(BITS_COUNT) */
+ YGDirection direction BITFIELD_ENUM_SIZED(2);
+ YGFlexDirection flexDirection BITFIELD_ENUM_SIZED(2);
+ YGJustify justifyContent BITFIELD_ENUM_SIZED(3);
+ YGAlign alignContent BITFIELD_ENUM_SIZED(3);
+ YGAlign alignItems BITFIELD_ENUM_SIZED(3);
+ YGAlign alignSelf BITFIELD_ENUM_SIZED(3);
+ YGPositionType positionType BITFIELD_ENUM_SIZED(1);
+ YGWrap flexWrap BITFIELD_ENUM_SIZED(2);
+ YGOverflow overflow BITFIELD_ENUM_SIZED(2);
+ YGDisplay display BITFIELD_ENUM_SIZED(1);
+ YGFloatOptional flex = {};
+ YGFloatOptional flexGrow = {};
+ YGFloatOptional flexShrink = {};
+ CompactValue flexBasis = CompactValue::ofAuto();
+ Edges margin = {};
+ Edges position = {};
+ Edges padding = {};
+ Edges border = {};
+ Dimensions dimensions{CompactValue::ofAuto()};
+ Dimensions minDimensions = {};
+ Dimensions maxDimensions = {};
+ // Yoga specific properties, not compatible with flexbox specification
+ YGFloatOptional aspectRatio = {};
+
+ YGStyle()
+ : direction(YGDirectionInherit),
+ flexDirection(YGFlexDirectionColumn),
+ justifyContent(YGJustifyFlexStart),
+ alignContent(YGAlignFlexStart),
+ alignItems(YGAlignStretch),
+ alignSelf(YGAlignAuto),
+ positionType(YGPositionTypeRelative),
+ flexWrap(YGWrapNoWrap),
+ overflow(YGOverflowVisible),
+ display(YGDisplayFlex) {}
~YGStyle() = default;
};
+
+bool operator==(const YGStyle& lhs, const YGStyle& rhs);
+inline bool operator!=(const YGStyle& lhs, const YGStyle& rhs) {
+ return !(lhs == rhs);
+}

ReactCommon/yoga/yoga/YGValue.cpp

@@ -0,0 +1,11 @@
+/**
+ * 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.
+ */
+#include "YGValue.h"
+
+const YGValue YGValueZero = {0, YGUnitPoint};
+const YGValue YGValueUndefined = {YGUndefined, YGUnitUndefined};
+const YGValue YGValueAuto = {YGUndefined, YGUnitAuto};

ReactCommon/yoga/yoga/YGValue.h

@@ -0,0 +1,83 @@
+/**
+ * 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.
+ */
+#pragma once
+
+#include <math.h>
+#include "YGEnums.h"
+#include "YGMacros.h"
+
+YG_EXTERN_C_BEGIN
+
+// Not defined in MSVC++
+#ifndef NAN
+static const uint32_t __nan = 0x7fc00000;
+#define NAN (*(const float*) __nan)
+#endif
+
+#define YGUndefined NAN
+
+typedef struct YGValue {
+ float value;
+ YGUnit unit;
+} YGValue;
+
+extern const YGValue YGValueAuto;
+extern const YGValue YGValueUndefined;
+extern const YGValue YGValueZero;
+
+YG_EXTERN_C_END
+
+#ifdef __cplusplus
+
+inline bool operator==(const YGValue& lhs, const YGValue& rhs) {
+ if (lhs.unit != rhs.unit) {
+ return false;
+ }
+
+ switch (lhs.unit) {
+ case YGUnitUndefined:
+ case YGUnitAuto:
+ return true;
+ case YGUnitPoint:
+ case YGUnitPercent:
+ return lhs.value == rhs.value;
+ }
+
+ return false;
+}
+
+inline bool operator!=(const YGValue& lhs, const YGValue& rhs) {
+ return !(lhs == rhs);
+}
+
+inline YGValue operator-(const YGValue& value) {
+ return {-value.value, value.unit};
+}
+
+namespace facebook {
+namespace yoga {
+namespace literals {
+
+inline YGValue operator"" _pt(long double value) {
+ return YGValue{static_cast<float>(value), YGUnitPoint};
+}
+inline YGValue operator"" _pt(unsigned long long value) {
+ return operator"" _pt(static_cast<long double>(value));
+}
+
+inline YGValue operator"" _percent(long double value) {
+ return YGValue{static_cast<float>(value), YGUnitPercent};
+}
+inline YGValue operator"" _percent(unsigned long long value) {
+ return operator"" _percent(static_cast<long double>(value));
+}
+
+} // namespace literals
+} // namespace yoga
+} // namespace facebook
+
+#endif

ReactCommon/yoga/yoga/Yoga.cpp

@@ -1,11 +1,9 @@
-/*
- * Copyright (c) 2014-present, Facebook, Inc.
+/**
+ * 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.
- *
*/
-
#include "Yoga.h"
#include <float.h>
#include <string.h>
@@ -14,20 +12,20 @@
#include "YGNode.h"
#include "YGNodePrint.h"
#include "Yoga-internal.h"
+#include "instrumentation.h"
#ifdef _MSC_VER
#include <float.h>
/* define fmaxf if < VC12 */
#if _MSC_VER < 1800
__forceinline const float fmaxf(const float a, const float b) {
- if (!YGFloatIsUndefined(a) && !YGFloatIsUndefined(b)) {
return (a > b) ? a : b;
- }
- return YGFloatIsUndefined(a) ? b : a;
}
#endif
#endif
+using namespace facebook::yoga;
+
#ifdef ANDROID
static int YGAndroidLog(
const YGConfigRef config,
@@ -44,23 +42,6 @@
va_list args);
#endif
-const YGValue YGValueZero = {0, YGUnitPoint};
-const YGValue YGValueUndefined = {YGUndefined, YGUnitUndefined};
-const YGValue YGValueAuto = {YGUndefined, YGUnitAuto};
-
-bool operator==(const YGValue& lhs, const YGValue& rhs) {
- if ((lhs.unit == YGUnitUndefined && rhs.unit == YGUnitUndefined) ||
- (lhs.unit == YGUnitAuto && rhs.unit == YGUnitAuto)) {
- return true;
- }
-
- return lhs.unit == rhs.unit && lhs.value == rhs.value;
-}
-
-bool operator!=(const YGValue& lhs, const YGValue& rhs) {
- return !(lhs == rhs);
-}
-
#ifdef ANDROID
#include <android/log.h>
static int YGAndroidLog(
@@ -94,7 +75,7 @@
return result;
}
#else
-#define YG_UNUSED(x) (void)(x);
+#define YG_UNUSED(x) (void) (x);
static int YGDefaultLog(
const YGConfigRef config,
@@ -124,31 +105,31 @@
return facebook::yoga::isUndefined(value);
}
-const YGValue* YGComputedEdgeValue(
- const std::array<YGValue, YGEdgeCount>& edges,
- const YGEdge edge,
- const YGValue* const defaultValue) {
- if (edges[edge].unit != YGUnitUndefined) {
- return &edges[edge];
+detail::CompactValue YGComputedEdgeValue(
+ const YGStyle::Edges& edges,
+ YGEdge edge,
+ detail::CompactValue defaultValue) {
+ if (!edges[edge].isUndefined()) {
+ return edges[edge];
}
if ((edge == YGEdgeTop || edge == YGEdgeBottom) &&
- edges[YGEdgeVertical].unit != YGUnitUndefined) {
- return &edges[YGEdgeVertical];
+ !edges[YGEdgeVertical].isUndefined()) {
+ return edges[YGEdgeVertical];
}
if ((edge == YGEdgeLeft || edge == YGEdgeRight || edge == YGEdgeStart ||
edge == YGEdgeEnd) &&
- edges[YGEdgeHorizontal].unit != YGUnitUndefined) {
- return &edges[YGEdgeHorizontal];
+ !edges[YGEdgeHorizontal].isUndefined()) {
+ return edges[YGEdgeHorizontal];
}
- if (edges[YGEdgeAll].unit != YGUnitUndefined) {
- return &edges[YGEdgeAll];
+ if (!edges[YGEdgeAll].isUndefined()) {
+ return edges[YGEdgeAll];
}
if (edge == YGEdgeStart || edge == YGEdgeEnd) {
- return &YGValueUndefined;
+ return detail::CompactValue::ofUndefined();
}
return defaultValue;
@@ -198,6 +179,10 @@
return node->getHasNewLayout();
}
+void YGConfigSetPrintTreeFlag(YGConfigRef config, bool enabled) {
+ config->printTree = enabled;
+}
+
void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout) {
node->setHasNewLayout(hasNewLayout);
}
@@ -316,7 +301,9 @@
}
}
-void YGNodeFreeRecursive(const YGNodeRef root) {
+void YGNodeFreeRecursiveWithCleanupFunc(
+ const YGNodeRef root,
+ YGNodeCleanupFunc cleanup) {
while (YGNodeGetChildCount(root) > 0) {
const YGNodeRef child = YGNodeGetChild(root, 0);
if (child->getOwner() != root) {
@@ -326,9 +313,16 @@
YGNodeRemoveChild(root, child);
YGNodeFreeRecursive(child);
}
+ if (cleanup != nullptr) {
+ cleanup(root);
+ }
YGNodeFree(root);
}
+void YGNodeFreeRecursive(const YGNodeRef root) {
+ return YGNodeFreeRecursiveWithCleanupFunc(root, nullptr);
+}
+
void YGNodeReset(const YGNodeRef node) {
YGAssertWithNode(
node,
@@ -377,6 +371,17 @@
memcpy(dest, src, sizeof(YGConfig));
}
+void YGNodeSetIsReferenceBaseline(YGNodeRef node, bool isReferenceBaseline) {
+ if (node->isReferenceBaseline() != isReferenceBaseline) {
+ node->setIsReferenceBaseline(isReferenceBaseline);
+ node->markDirtyAndPropogate();
+ }
+}
+
+bool YGNodeIsReferenceBaseline(YGNodeRef node) {
+ return node->isReferenceBaseline();
+}
+
void YGNodeInsertChild(
const YGNodeRef node,
const YGNodeRef child,
@@ -398,20 +403,6 @@
node->markDirtyAndPropogate();
}
-void YGNodeInsertSharedChild(
- const YGNodeRef node,
- const YGNodeRef child,
- const uint32_t index) {
- YGAssertWithNode(
- node,
- node->getMeasure() == nullptr,
- "Cannot add child: Nodes with measure functions cannot have children.");
-
- node->insertChild(child, index);
- child->setOwner(nullptr);
- node->markDirtyAndPropogate();
-}
-
void YGNodeRemoveChild(const YGNodeRef owner, const YGNodeRef excludedChild) {
// This algorithm is a forked variant from cloneChildrenIfNeeded in YGNode
// that excludes a child.
@@ -579,28 +570,51 @@
float YGNodeStyleGetFlexGrow(const YGNodeRef node) {
return node->getStyle().flexGrow.isUndefined()
? kDefaultFlexGrow
- : node->getStyle().flexGrow.getValue();
+ : node->getStyle().flexGrow.unwrap();
}
float YGNodeStyleGetFlexShrink(const YGNodeRef node) {
return node->getStyle().flexShrink.isUndefined()
? (node->getConfig()->useWebDefaults ? kWebDefaultFlexShrink
: kDefaultFlexShrink)
- : node->getStyle().flexShrink.getValue();
+ : node->getStyle().flexShrink.unwrap();
}
namespace {
-template <typename T, T YGStyle::*P>
-struct StyleProp {
- static T get(YGNodeRef node) {
- return node->getStyle().*P;
- }
- static void set(YGNodeRef node, T newValue) {
- if (node->getStyle().*P != newValue) {
- YGStyle style = node->getStyle();
- style.*P = newValue;
- node->setStyle(style);
+struct Value {
+ template <YGUnit U>
+ static detail::CompactValue create(float value) {
+ return detail::CompactValue::ofMaybe<U>(value);
+ }
+};
+
+template <>
+inline detail::CompactValue Value::create<YGUnitUndefined>(float) {
+ return detail::CompactValue::ofUndefined();
+}
+
+template <>
+inline detail::CompactValue Value::create<YGUnitAuto>(float) {
+ return detail::CompactValue::ofAuto();
+}
+
+template <YGStyle::Dimensions YGStyle::*P>
+struct DimensionProp {
+ template <YGDimension idx>
+ static YGValue get(YGNodeRef node) {
+ YGValue value = (node->getStyle().*P)[idx];
+ if (value.unit == YGUnitUndefined || value.unit == YGUnitAuto) {
+ value.value = YGUndefined;
+ }
+ return value;
+ }
+
+ template <YGDimension idx, YGUnit U>
+ static void set(YGNodeRef node, float newValue) {
+ auto value = Value::create<U>(newValue);
+ if ((node->getStyle().*P)[idx] != value) {
+ (node->getStyle().*P)[idx] = value;
node->markDirtyAndPropogate();
}
}
@@ -608,92 +622,32 @@
} // namespace
-#define YG_NODE_STYLE_PROPERTY_SETTER_UNIT_IMPL( \
- type, name, paramName, instanceName) \
- void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) { \
- YGValue value = { \
- YGFloatSanitize(paramName), \
- YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \
- }; \
- if ((node->getStyle().instanceName.value != value.value && \
- value.unit != YGUnitUndefined) || \
- node->getStyle().instanceName.unit != value.unit) { \
- YGStyle style = node->getStyle(); \
- style.instanceName = value; \
- node->setStyle(style); \
- node->markDirtyAndPropogate(); \
- } \
- } \
- \
- void YGNodeStyleSet##name##Percent( \
- const YGNodeRef node, const type paramName) { \
- YGValue value = { \
- YGFloatSanitize(paramName), \
- YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPercent, \
- }; \
- if ((node->getStyle().instanceName.value != value.value && \
- value.unit != YGUnitUndefined) || \
- node->getStyle().instanceName.unit != value.unit) { \
- YGStyle style = node->getStyle(); \
- \
- style.instanceName = value; \
- node->setStyle(style); \
- node->markDirtyAndPropogate(); \
- } \
- }
-
#define YG_NODE_STYLE_PROPERTY_SETTER_UNIT_AUTO_IMPL( \
type, name, paramName, instanceName) \
void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) { \
- YGValue value = { \
- YGFloatSanitize(paramName), \
- YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \
- }; \
- if ((node->getStyle().instanceName.value != value.value && \
- value.unit != YGUnitUndefined) || \
- node->getStyle().instanceName.unit != value.unit) { \
- YGStyle style = node->getStyle(); \
- style.instanceName = value; \
- node->setStyle(style); \
+ auto value = detail::CompactValue::ofMaybe<YGUnitPoint>(paramName); \
+ if (node->getStyle().instanceName != value) { \
+ node->getStyle().instanceName = value; \
node->markDirtyAndPropogate(); \
} \
} \
\
void YGNodeStyleSet##name##Percent( \
const YGNodeRef node, const type paramName) { \
- if (node->getStyle().instanceName.value != YGFloatSanitize(paramName) || \
- node->getStyle().instanceName.unit != YGUnitPercent) { \
- YGStyle style = node->getStyle(); \
- style.instanceName.value = YGFloatSanitize(paramName); \
- style.instanceName.unit = \
- YGFloatIsUndefined(paramName) ? YGUnitAuto : YGUnitPercent; \
- node->setStyle(style); \
+ auto value = detail::CompactValue::ofMaybe<YGUnitPercent>(paramName); \
+ if (node->getStyle().instanceName != value) { \
+ node->getStyle().instanceName = value; \
node->markDirtyAndPropogate(); \
} \
} \
\
void YGNodeStyleSet##name##Auto(const YGNodeRef node) { \
- if (node->getStyle().instanceName.unit != YGUnitAuto) { \
- YGStyle style = node->getStyle(); \
- style.instanceName.value = 0; \
- style.instanceName.unit = YGUnitAuto; \
- node->setStyle(style); \
+ if (node->getStyle().instanceName != detail::CompactValue::ofAuto()) { \
+ node->getStyle().instanceName = detail::CompactValue::ofAuto(); \
node->markDirtyAndPropogate(); \
} \
}
-#define YG_NODE_STYLE_PROPERTY_UNIT_IMPL(type, name, paramName, instanceName) \
- YG_NODE_STYLE_PROPERTY_SETTER_UNIT_IMPL( \
- float, name, paramName, instanceName) \
- \
- type YGNodeStyleGet##name(const YGNodeRef node) { \
- YGValue value = node->getStyle().instanceName; \
- if (value.unit == YGUnitUndefined || value.unit == YGUnitAuto) { \
- value.value = YGUndefined; \
- } \
- return value; \
- }
-
#define YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL( \
type, name, paramName, instanceName) \
YG_NODE_STYLE_PROPERTY_SETTER_UNIT_AUTO_IMPL( \
@@ -709,11 +663,9 @@
#define YG_NODE_STYLE_EDGE_PROPERTY_UNIT_AUTO_IMPL(type, name, instanceName) \
void YGNodeStyleSet##name##Auto(const YGNodeRef node, const YGEdge edge) { \
- if (node->getStyle().instanceName[edge].unit != YGUnitAuto) { \
- YGStyle style = node->getStyle(); \
- style.instanceName[edge].value = 0; \
- style.instanceName[edge].unit = YGUnitAuto; \
- node->setStyle(style); \
+ if (node->getStyle().instanceName[edge] != \
+ detail::CompactValue::ofAuto()) { \
+ node->getStyle().instanceName[edge] = detail::CompactValue::ofAuto(); \
node->markDirtyAndPropogate(); \
} \
}
@@ -722,43 +674,28 @@
type, name, paramName, instanceName) \
void YGNodeStyleSet##name( \
const YGNodeRef node, const YGEdge edge, const float paramName) { \
- YGValue value = { \
- YGFloatSanitize(paramName), \
- YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \
- }; \
- if ((node->getStyle().instanceName[edge].value != value.value && \
- value.unit != YGUnitUndefined) || \
- node->getStyle().instanceName[edge].unit != value.unit) { \
- YGStyle style = node->getStyle(); \
- style.instanceName[edge] = value; \
- node->setStyle(style); \
+ auto value = detail::CompactValue::ofMaybe<YGUnitPoint>(paramName); \
+ if (node->getStyle().instanceName[edge] != value) { \
+ node->getStyle().instanceName[edge] = value; \
node->markDirtyAndPropogate(); \
} \
} \
\
void YGNodeStyleSet##name##Percent( \
const YGNodeRef node, const YGEdge edge, const float paramName) { \
- YGValue value = { \
- YGFloatSanitize(paramName), \
- YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPercent, \
- }; \
- if ((node->getStyle().instanceName[edge].value != value.value && \
- value.unit != YGUnitUndefined) || \
- node->getStyle().instanceName[edge].unit != value.unit) { \
- YGStyle style = node->getStyle(); \
- style.instanceName[edge] = value; \
- node->setStyle(style); \
+ auto value = detail::CompactValue::ofMaybe<YGUnitPercent>(paramName); \
+ if (node->getStyle().instanceName[edge] != value) { \
+ node->getStyle().instanceName[edge] = value; \
node->markDirtyAndPropogate(); \
} \
} \
\
- WIN_STRUCT(type) \
- YGNodeStyleGet##name(const YGNodeRef node, const YGEdge edge) { \
+ type YGNodeStyleGet##name(const YGNodeRef node, const YGEdge edge) { \
YGValue value = node->getStyle().instanceName[edge]; \
if (value.unit == YGUnitUndefined || value.unit == YGUnitAuto) { \
value.value = YGUndefined; \
} \
- return WIN_STRUCT_REF(value); \
+ return value; \
}
#define YG_NODE_LAYOUT_PROPERTY_IMPL(type, name, instanceName) \
@@ -792,96 +729,95 @@
return node->getLayout().instanceName[edge]; \
}
-void YGNodeStyleSetDirection(
- const YGNodeRef node,
- const YGDirection direction) {
- StyleProp<YGDirection, &YGStyle::direction>::set(node, direction);
+#define YG_NODE_STYLE_SET(node, property, value) \
+ if (node->getStyle().property != value) { \
+ node->getStyle().property = value; \
+ node->markDirtyAndPropogate(); \
+ }
+
+void YGNodeStyleSetDirection(const YGNodeRef node, const YGDirection value) {
+ YG_NODE_STYLE_SET(node, direction, value);
}
YGDirection YGNodeStyleGetDirection(const YGNodeRef node) {
- return StyleProp<YGDirection, &YGStyle::direction>::get(node);
+ return node->getStyle().direction;
}
void YGNodeStyleSetFlexDirection(
const YGNodeRef node,
const YGFlexDirection flexDirection) {
- StyleProp<YGFlexDirection, &YGStyle::flexDirection>::set(node, flexDirection);
+ YG_NODE_STYLE_SET(node, flexDirection, flexDirection);
}
YGFlexDirection YGNodeStyleGetFlexDirection(const YGNodeRef node) {
- return StyleProp<YGFlexDirection, &YGStyle::flexDirection>::get(node);
+ return node->getStyle().flexDirection;
}
void YGNodeStyleSetJustifyContent(
const YGNodeRef node,
const YGJustify justifyContent) {
- StyleProp<YGJustify, &YGStyle::justifyContent>::set(node, justifyContent);
+ YG_NODE_STYLE_SET(node, justifyContent, justifyContent);
}
YGJustify YGNodeStyleGetJustifyContent(const YGNodeRef node) {
- return StyleProp<YGJustify, &YGStyle::justifyContent>::get(node);
+ return node->getStyle().justifyContent;
}
void YGNodeStyleSetAlignContent(
const YGNodeRef node,
const YGAlign alignContent) {
- StyleProp<YGAlign, &YGStyle::alignContent>::set(node, alignContent);
+ YG_NODE_STYLE_SET(node, alignContent, alignContent);
}
YGAlign YGNodeStyleGetAlignContent(const YGNodeRef node) {
- return StyleProp<YGAlign, &YGStyle::alignContent>::get(node);
+ return node->getStyle().alignContent;
}
void YGNodeStyleSetAlignItems(const YGNodeRef node, const YGAlign alignItems) {
- StyleProp<YGAlign, &YGStyle::alignItems>::set(node, alignItems);
+ YG_NODE_STYLE_SET(node, alignItems, alignItems);
}
YGAlign YGNodeStyleGetAlignItems(const YGNodeRef node) {
- return StyleProp<YGAlign, &YGStyle::alignItems>::get(node);
+ return node->getStyle().alignItems;
}
void YGNodeStyleSetAlignSelf(const YGNodeRef node, const YGAlign alignSelf) {
- StyleProp<YGAlign, &YGStyle::alignSelf>::set(node, alignSelf);
+ YG_NODE_STYLE_SET(node, alignSelf, alignSelf);
}
YGAlign YGNodeStyleGetAlignSelf(const YGNodeRef node) {
- return StyleProp<YGAlign, &YGStyle::alignSelf>::get(node);
+ return node->getStyle().alignSelf;
}
void YGNodeStyleSetPositionType(
const YGNodeRef node,
const YGPositionType positionType) {
- StyleProp<YGPositionType, &YGStyle::positionType>::set(node, positionType);
+ YG_NODE_STYLE_SET(node, positionType, positionType);
}
YGPositionType YGNodeStyleGetPositionType(const YGNodeRef node) {
- return StyleProp<YGPositionType, &YGStyle::positionType>::get(node);
+ return node->getStyle().positionType;
}
void YGNodeStyleSetFlexWrap(const YGNodeRef node, const YGWrap flexWrap) {
- StyleProp<YGWrap, &YGStyle::flexWrap>::set(node, flexWrap);
+ YG_NODE_STYLE_SET(node, flexWrap, flexWrap);
}
YGWrap YGNodeStyleGetFlexWrap(const YGNodeRef node) {
- return StyleProp<YGWrap, &YGStyle::flexWrap>::get(node);
+ return node->getStyle().flexWrap;
}
void YGNodeStyleSetOverflow(const YGNodeRef node, const YGOverflow overflow) {
- StyleProp<YGOverflow, &YGStyle::overflow>::set(node, overflow);
+ YG_NODE_STYLE_SET(node, overflow, overflow);
}
YGOverflow YGNodeStyleGetOverflow(const YGNodeRef node) {
- return StyleProp<YGOverflow, &YGStyle::overflow>::get(node);
+ return node->getStyle().overflow;
}
void YGNodeStyleSetDisplay(const YGNodeRef node, const YGDisplay display) {
- StyleProp<YGDisplay, &YGStyle::display>::set(node, display);
+ YG_NODE_STYLE_SET(node, display, display);
}
YGDisplay YGNodeStyleGetDisplay(const YGNodeRef node) {
- return StyleProp<YGDisplay, &YGStyle::display>::get(node);
+ return node->getStyle().display;
}
// TODO(T26792433): Change the API to accept YGFloatOptional.
void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) {
if (node->getStyle().flex != flex) {
- YGStyle style = node->getStyle();
- if (YGFloatIsUndefined(flex)) {
- style.flex = YGFloatOptional();
- } else {
- style.flex = YGFloatOptional(flex);
- }
- node->setStyle(style);
+ node->getStyle().flex =
+ YGFloatIsUndefined(flex) ? YGFloatOptional() : YGFloatOptional(flex);
node->markDirtyAndPropogate();
}
}
@@ -889,19 +825,15 @@
// TODO(T26792433): Change the API to accept YGFloatOptional.
float YGNodeStyleGetFlex(const YGNodeRef node) {
return node->getStyle().flex.isUndefined() ? YGUndefined
- : node->getStyle().flex.getValue();
+ : node->getStyle().flex.unwrap();
}
// TODO(T26792433): Change the API to accept YGFloatOptional.
void YGNodeStyleSetFlexGrow(const YGNodeRef node, const float flexGrow) {
if (node->getStyle().flexGrow != flexGrow) {
- YGStyle style = node->getStyle();
- if (YGFloatIsUndefined(flexGrow)) {
- style.flexGrow = YGFloatOptional();
- } else {
- style.flexGrow = YGFloatOptional(flexGrow);
- }
- node->setStyle(style);
+ node->getStyle().flexGrow = YGFloatIsUndefined(flexGrow)
+ ? YGFloatOptional()
+ : YGFloatOptional(flexGrow);
node->markDirtyAndPropogate();
}
}
@@ -909,13 +841,9 @@
// TODO(T26792433): Change the API to accept YGFloatOptional.
void YGNodeStyleSetFlexShrink(const YGNodeRef node, const float flexShrink) {
if (node->getStyle().flexShrink != flexShrink) {
- YGStyle style = node->getStyle();
- if (YGFloatIsUndefined(flexShrink)) {
- style.flexShrink = YGFloatOptional();
- } else {
- style.flexShrink = YGFloatOptional(flexShrink);
- }
- node->setStyle(style);
+ node->getStyle().flexShrink = YGFloatIsUndefined(flexShrink)
+ ? YGFloatOptional()
+ : YGFloatOptional(flexShrink);
node->markDirtyAndPropogate();
}
}
@@ -930,16 +858,9 @@
}
void YGNodeStyleSetFlexBasis(const YGNodeRef node, const float flexBasis) {
- YGValue value = {
- YGFloatSanitize(flexBasis),
- YGFloatIsUndefined(flexBasis) ? YGUnitUndefined : YGUnitPoint,
- };
- if ((node->getStyle().flexBasis.value != value.value &&
- value.unit != YGUnitUndefined) ||
- node->getStyle().flexBasis.unit != value.unit) {
- YGStyle style = node->getStyle();
- style.flexBasis = value;
- node->setStyle(style);
+ auto value = detail::CompactValue::ofMaybe<YGUnitPoint>(flexBasis);
+ if (node->getStyle().flexBasis != value) {
+ node->getStyle().flexBasis = value;
node->markDirtyAndPropogate();
}
}
@@ -947,23 +868,16 @@
void YGNodeStyleSetFlexBasisPercent(
const YGNodeRef node,
const float flexBasisPercent) {
- if (node->getStyle().flexBasis.value != flexBasisPercent ||
- node->getStyle().flexBasis.unit != YGUnitPercent) {
- YGStyle style = node->getStyle();
- style.flexBasis.value = YGFloatSanitize(flexBasisPercent);
- style.flexBasis.unit =
- YGFloatIsUndefined(flexBasisPercent) ? YGUnitAuto : YGUnitPercent;
- node->setStyle(style);
+ auto value = detail::CompactValue::ofMaybe<YGUnitPercent>(flexBasisPercent);
+ if (node->getStyle().flexBasis != value) {
+ node->getStyle().flexBasis = value;
node->markDirtyAndPropogate();
}
}
void YGNodeStyleSetFlexBasisAuto(const YGNodeRef node) {
- if (node->getStyle().flexBasis.unit != YGUnitAuto) {
- YGStyle style = node->getStyle();
- style.flexBasis.value = 0;
- style.flexBasis.unit = YGUnitAuto;
- node->setStyle(style);
+ if (node->getStyle().flexBasis != detail::CompactValue::ofAuto()) {
+ node->getStyle().flexBasis = detail::CompactValue::ofAuto();
node->markDirtyAndPropogate();
}
}
@@ -978,29 +892,23 @@
const YGNodeRef node,
const YGEdge edge,
const float border) {
- YGValue value = {
- YGFloatSanitize(border),
- YGFloatIsUndefined(border) ? YGUnitUndefined : YGUnitPoint,
- };
- if ((node->getStyle().border[edge].value != value.value &&
- value.unit != YGUnitUndefined) ||
- node->getStyle().border[edge].unit != value.unit) {
- YGStyle style = node->getStyle();
- style.border[edge] = value;
- node->setStyle(style);
+ auto value = detail::CompactValue::ofMaybe<YGUnitPoint>(border);
+ if (node->getStyle().border[edge] != value) {
+ node->getStyle().border[edge] = value;
node->markDirtyAndPropogate();
}
}
float YGNodeStyleGetBorder(const YGNodeRef node, const YGEdge edge) {
- if (node->getStyle().border[edge].unit == YGUnitUndefined ||
- node->getStyle().border[edge].unit == YGUnitAuto) {
+ if (node->getStyle().border[edge].isUndefined() ||
+ node->getStyle().border[edge].isAuto()) {
// TODO(T26792433): Rather than returning YGUndefined, change the api to
// return YGFloatOptional.
return YGUndefined;
}
- return node->getStyle().border[edge].value;
+ auto border = (YGValue) node->getStyle().border[edge];
+ return border.value;
}
// Yoga specific properties, not compatible with flexbox specification
@@ -1008,15 +916,13 @@
// TODO(T26792433): Change the API to accept YGFloatOptional.
float YGNodeStyleGetAspectRatio(const YGNodeRef node) {
const YGFloatOptional op = node->getStyle().aspectRatio;
- return op.isUndefined() ? YGUndefined : op.getValue();
+ return op.isUndefined() ? YGUndefined : op.unwrap();
}
// TODO(T26792433): Change the API to accept YGFloatOptional.
void YGNodeStyleSetAspectRatio(const YGNodeRef node, const float aspectRatio) {
if (node->getStyle().aspectRatio != aspectRatio) {
- YGStyle style = node->getStyle();
- style.aspectRatio = YGFloatOptional(aspectRatio);
- node->setStyle(style);
+ node->getStyle().aspectRatio = YGFloatOptional(aspectRatio);
node->markDirtyAndPropogate();
}
}
@@ -1031,26 +937,59 @@
Height,
height,
dimensions[YGDimensionHeight]);
-YG_NODE_STYLE_PROPERTY_UNIT_IMPL(
- YGValue,
- MinWidth,
- minWidth,
- minDimensions[YGDimensionWidth]);
-YG_NODE_STYLE_PROPERTY_UNIT_IMPL(
- YGValue,
- MinHeight,
- minHeight,
- minDimensions[YGDimensionHeight]);
-YG_NODE_STYLE_PROPERTY_UNIT_IMPL(
- YGValue,
- MaxWidth,
- maxWidth,
- maxDimensions[YGDimensionWidth]);
-YG_NODE_STYLE_PROPERTY_UNIT_IMPL(
- YGValue,
- MaxHeight,
- maxHeight,
- maxDimensions[YGDimensionHeight]);
+
+void YGNodeStyleSetMinWidth(const YGNodeRef node, const float minWidth) {
+ DimensionProp<&YGStyle::minDimensions>::set<YGDimensionWidth, YGUnitPoint>(
+ node, minWidth);
+}
+void YGNodeStyleSetMinWidthPercent(const YGNodeRef node, const float minWidth) {
+ DimensionProp<&YGStyle::minDimensions>::set<YGDimensionWidth, YGUnitPercent>(
+ node, minWidth);
+}
+YGValue YGNodeStyleGetMinWidth(const YGNodeRef node) {
+ return DimensionProp<&YGStyle::minDimensions>::get<YGDimensionWidth>(node);
+};
+
+void YGNodeStyleSetMinHeight(const YGNodeRef node, const float minHeight) {
+ DimensionProp<&YGStyle::minDimensions>::set<YGDimensionHeight, YGUnitPoint>(
+ node, minHeight);
+}
+void YGNodeStyleSetMinHeightPercent(
+ const YGNodeRef node,
+ const float minHeight) {
+ DimensionProp<&YGStyle::minDimensions>::set<YGDimensionHeight, YGUnitPercent>(
+ node, minHeight);
+}
+YGValue YGNodeStyleGetMinHeight(const YGNodeRef node) {
+ return DimensionProp<&YGStyle::minDimensions>::get<YGDimensionHeight>(node);
+};
+
+void YGNodeStyleSetMaxWidth(const YGNodeRef node, const float maxWidth) {
+ DimensionProp<&YGStyle::maxDimensions>::set<YGDimensionWidth, YGUnitPoint>(
+ node, maxWidth);
+}
+void YGNodeStyleSetMaxWidthPercent(const YGNodeRef node, const float maxWidth) {
+ DimensionProp<&YGStyle::maxDimensions>::set<YGDimensionWidth, YGUnitPercent>(
+ node, maxWidth);
+}
+YGValue YGNodeStyleGetMaxWidth(const YGNodeRef node) {
+ return DimensionProp<&YGStyle::maxDimensions>::get<YGDimensionWidth>(node);
+};
+
+void YGNodeStyleSetMaxHeight(const YGNodeRef node, const float maxHeight) {
+ DimensionProp<&YGStyle::maxDimensions>::set<YGDimensionHeight, YGUnitPoint>(
+ node, maxHeight);
+}
+void YGNodeStyleSetMaxHeightPercent(
+ const YGNodeRef node,
+ const float maxHeight) {
+ DimensionProp<&YGStyle::maxDimensions>::set<YGDimensionHeight, YGUnitPercent>(
+ node, maxHeight);
+}
+YGValue YGNodeStyleGetMaxHeight(const YGNodeRef node) {
+ return DimensionProp<&YGStyle::maxDimensions>::get<YGDimensionHeight>(node);
+};
+
YG_NODE_LAYOUT_PROPERTY_IMPL(float, Left, position[YGEdgeLeft]);
YG_NODE_LAYOUT_PROPERTY_IMPL(float, Top, position[YGEdgeTop]);
YG_NODE_LAYOUT_PROPERTY_IMPL(float, Right, position[YGEdgeRight]);
@@ -1081,13 +1020,14 @@
const float ownerHeight,
const bool performLayout,
const char* reason,
- const YGConfigRef config);
+ const YGConfigRef config,
+ YGMarkerLayoutData& layoutMarkerData);
static void YGNodePrintInternal(
const YGNodeRef node,
const YGPrintOptions options) {
std::string str;
- facebook::yoga::YGNodeToString(&str, node, options, 0);
+ facebook::yoga::YGNodeToString(str, node, options, 0);
YGLog(node, YGLogLevelDebug, str.c_str());
}
@@ -1114,9 +1054,9 @@
const YGNodeRef node,
const YGFlexDirection axis,
const float widthSize) {
- return YGUnwrapFloatOptional(
- node->getLeadingPaddingAndBorder(axis, widthSize) +
- node->getTrailingPaddingAndBorder(axis, widthSize));
+ return (node->getLeadingPaddingAndBorder(axis, widthSize) +
+ node->getTrailingPaddingAndBorder(axis, widthSize))
+ .unwrap();
}
static inline YGAlign YGNodeAlignItem(
@@ -1134,7 +1074,9 @@
static float YGBaseline(const YGNodeRef node) {
if (node->getBaseline() != nullptr) {
- const float baseline = node->getBaseline()(
+ const float baseline = marker::MarkerSection<YGMarkerBaselineFn>::wrap(
+ node,
+ node->getBaseline(),
node,
node->getLayout().measuredDimensions[YGDimensionWidth],
node->getLayout().measuredDimensions[YGDimensionHeight]);
@@ -1155,7 +1097,8 @@
if (child->getStyle().positionType == YGPositionTypeAbsolute) {
continue;
}
- if (YGNodeAlignItem(node, child) == YGAlignBaseline) {
+ if (YGNodeAlignItem(node, child) == YGAlignBaseline ||
+ child->isReferenceBaseline()) {
baselineChild = child;
break;
}
@@ -1197,9 +1140,9 @@
const YGFlexDirection axis,
const float widthSize) {
return node->getLayout().measuredDimensions[dim[axis]] +
- YGUnwrapFloatOptional(
- node->getLeadingMargin(axis, widthSize) +
- node->getTrailingMargin(axis, widthSize));
+ (node->getLeadingMargin(axis, widthSize) +
+ node->getTrailingMargin(axis, widthSize))
+ .unwrap();
}
static inline bool YGNodeIsStyleDimDefined(
@@ -1228,9 +1171,9 @@
static YGFloatOptional YGNodeBoundAxisWithinMinAndMax(
const YGNodeRef node,
- const YGFlexDirection& axis,
- const float& value,
- const float& axisSize) {
+ const YGFlexDirection axis,
+ const YGFloatOptional value,
+ const float axisSize) {
YGFloatOptional min;
YGFloatOptional max;
@@ -1246,15 +1189,15 @@
node->getStyle().maxDimensions[YGDimensionWidth], axisSize);
}
- if (!max.isUndefined() && max.getValue() >= 0 && value > max.getValue()) {
+ if (max >= YGFloatOptional{0} && value > max) {
return max;
}
- if (!min.isUndefined() && min.getValue() >= 0 && value < min.getValue()) {
+ if (min >= YGFloatOptional{0} && value < min) {
return min;
}
- return YGFloatOptional(value);
+ return value;
}
// Like YGNodeBoundAxisWithinMinAndMax but also ensures that the value doesn't
@@ -1266,8 +1209,9 @@
const float axisSize,
const float widthSize) {
return YGFloatMax(
- YGUnwrapFloatOptional(
- YGNodeBoundAxisWithinMinAndMax(node, axis, value, axisSize)),
+ YGNodeBoundAxisWithinMinAndMax(
+ node, axis, YGFloatOptional{value}, axisSize)
+ .unwrap(),
YGNodePaddingAndBorderForAxis(node, axis, widthSize));
}
@@ -1295,14 +1239,14 @@
switch (*mode) {
case YGMeasureModeExactly:
case YGMeasureModeAtMost:
- *size = (maxSize.isUndefined() || *size < maxSize.getValue())
+ *size = (maxSize.isUndefined() || *size < maxSize.unwrap())
? *size
- : maxSize.getValue();
+ : maxSize.unwrap();
break;
case YGMeasureModeUndefined:
if (!maxSize.isUndefined()) {
*mode = YGMeasureModeAtMost;
- *size = maxSize.getValue();
+ *size = maxSize.unwrap();
}
break;
}
@@ -1318,7 +1262,8 @@
const float ownerHeight,
const YGMeasureMode heightMode,
const YGDirection direction,
- const YGConfigRef config) {
+ const YGConfigRef config,
+ YGMarkerLayoutData& layoutMarkerData) {
const YGFlexDirection mainAxis =
YGResolveFlexDirection(node->getStyle().flexDirection, direction);
const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
@@ -1343,14 +1288,14 @@
child->getConfig(), YGExperimentalFeatureWebFlexBasis) &&
child->getLayout().computedFlexBasisGeneration !=
gCurrentGenerationCount)) {
- const YGFloatOptional& paddingAndBorder = YGFloatOptional(
+ const YGFloatOptional paddingAndBorder = YGFloatOptional(
YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth));
child->setLayoutComputedFlexBasis(
YGFloatOptionalMax(resolvedFlexBasis, paddingAndBorder));
}
} else if (isMainAxisRow && isRowStyleDimDefined) {
// The width is definite, so use that as the flex basis.
- const YGFloatOptional& paddingAndBorder = YGFloatOptional(
+ const YGFloatOptional paddingAndBorder = YGFloatOptional(
YGNodePaddingAndBorderForAxis(child, YGFlexDirectionRow, ownerWidth));
child->setLayoutComputedFlexBasis(YGFloatOptionalMax(
@@ -1359,7 +1304,7 @@
paddingAndBorder));
} else if (!isMainAxisRow && isColumnStyleDimDefined) {
// The height is definite, so use that as the flex basis.
- const YGFloatOptional& paddingAndBorder =
+ const YGFloatOptional paddingAndBorder =
YGFloatOptional(YGNodePaddingAndBorderForAxis(
child, YGFlexDirectionColumn, ownerWidth));
child->setLayoutComputedFlexBasis(YGFloatOptionalMax(
@@ -1367,35 +1312,37 @@
child->getResolvedDimension(YGDimensionHeight), ownerHeight),
paddingAndBorder));
} else {
- // Compute the flex basis and hypothetical main size (i.e. the clamped
- // flex basis).
+ // Compute the flex basis and hypothetical main size (i.e. the clamped flex
+ // basis).
childWidth = YGUndefined;
childHeight = YGUndefined;
childWidthMeasureMode = YGMeasureModeUndefined;
childHeightMeasureMode = YGMeasureModeUndefined;
- auto marginRow = YGUnwrapFloatOptional(
- child->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
- auto marginColumn = YGUnwrapFloatOptional(
- child->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
+ auto marginRow =
+ child->getMarginForAxis(YGFlexDirectionRow, ownerWidth).unwrap();
+ auto marginColumn =
+ child->getMarginForAxis(YGFlexDirectionColumn, ownerWidth).unwrap();
if (isRowStyleDimDefined) {
childWidth =
- YGUnwrapFloatOptional(YGResolveValue(
- child->getResolvedDimension(YGDimensionWidth), ownerWidth)) +
+ YGResolveValue(
+ child->getResolvedDimension(YGDimensionWidth), ownerWidth)
+ .unwrap() +
marginRow;
childWidthMeasureMode = YGMeasureModeExactly;
}
if (isColumnStyleDimDefined) {
childHeight =
- YGUnwrapFloatOptional(YGResolveValue(
- child->getResolvedDimension(YGDimensionHeight), ownerHeight)) +
+ YGResolveValue(
+ child->getResolvedDimension(YGDimensionHeight), ownerHeight)
+ .unwrap() +
marginColumn;
childHeightMeasureMode = YGMeasureModeExactly;
}
- // The W3C spec doesn't say anything about the 'overflow' property,
- // but all major browsers appear to implement the following logic.
+ // The W3C spec doesn't say anything about the 'overflow' property, but all
+ // major browsers appear to implement the following logic.
if ((!isMainAxisRow && node->getStyle().overflow == YGOverflowScroll) ||
node->getStyle().overflow != YGOverflowScroll) {
if (YGFloatIsUndefined(childWidth) && !YGFloatIsUndefined(width)) {
@@ -1415,20 +1362,19 @@
if (!child->getStyle().aspectRatio.isUndefined()) {
if (!isMainAxisRow && childWidthMeasureMode == YGMeasureModeExactly) {
childHeight = marginColumn +
- (childWidth - marginRow) / child->getStyle().aspectRatio.getValue();
+ (childWidth - marginRow) / child->getStyle().aspectRatio.unwrap();
childHeightMeasureMode = YGMeasureModeExactly;
} else if (
isMainAxisRow && childHeightMeasureMode == YGMeasureModeExactly) {
childWidth = marginRow +
(childHeight - marginColumn) *
- child->getStyle().aspectRatio.getValue();
+ child->getStyle().aspectRatio.unwrap();
childWidthMeasureMode = YGMeasureModeExactly;
}
}
- // If child has no defined size in the cross axis and is set to stretch,
- // set the cross
- // axis to be measured exactly with the available inner width
+ // If child has no defined size in the cross axis and is set to stretch, set
+ // the cross axis to be measured exactly with the available inner width
const bool hasExactWidth =
!YGFloatIsUndefined(width) && widthMode == YGMeasureModeExactly;
@@ -1441,7 +1387,7 @@
childWidthMeasureMode = YGMeasureModeExactly;
if (!child->getStyle().aspectRatio.isUndefined()) {
childHeight =
- (childWidth - marginRow) / child->getStyle().aspectRatio.getValue();
+ (childWidth - marginRow) / child->getStyle().aspectRatio.unwrap();
childHeightMeasureMode = YGMeasureModeExactly;
}
}
@@ -1458,7 +1404,7 @@
if (!child->getStyle().aspectRatio.isUndefined()) {
childWidth = (childHeight - marginColumn) *
- child->getStyle().aspectRatio.getValue();
+ child->getStyle().aspectRatio.unwrap();
childWidthMeasureMode = YGMeasureModeExactly;
}
}
@@ -1490,7 +1436,8 @@
ownerHeight,
false,
"measure",
- config);
+ config,
+ layoutMarkerData);
child->setLayoutComputedFlexBasis(YGFloatOptional(YGFloatMax(
child->getLayout().measuredDimensions[dim[mainAxis]],
@@ -1506,7 +1453,8 @@
const YGMeasureMode widthMode,
const float height,
const YGDirection direction,
- const YGConfigRef config) {
+ const YGConfigRef config,
+ YGMarkerLayoutData& layoutMarkerData) {
const YGFlexDirection mainAxis =
YGResolveFlexDirection(node->getStyle().flexDirection, direction);
const YGFlexDirection crossAxis = YGFlexDirectionCross(mainAxis, direction);
@@ -1517,49 +1465,47 @@
YGMeasureMode childWidthMeasureMode = YGMeasureModeUndefined;
YGMeasureMode childHeightMeasureMode = YGMeasureModeUndefined;
- auto marginRow =
- YGUnwrapFloatOptional(child->getMarginForAxis(YGFlexDirectionRow, width));
- auto marginColumn = YGUnwrapFloatOptional(
- child->getMarginForAxis(YGFlexDirectionColumn, width));
+ auto marginRow = child->getMarginForAxis(YGFlexDirectionRow, width).unwrap();
+ auto marginColumn =
+ child->getMarginForAxis(YGFlexDirectionColumn, width).unwrap();
if (YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, width)) {
- childWidth = YGUnwrapFloatOptional(YGResolveValue(
- child->getResolvedDimension(YGDimensionWidth), width)) +
+ childWidth =
+ YGResolveValue(child->getResolvedDimension(YGDimensionWidth), width)
+ .unwrap() +
marginRow;
} else {
- // If the child doesn't have a specified width, compute the width based
- // on the left/right
- // offsets if they're defined.
+ // If the child doesn't have a specified width, compute the width based on
+ // the left/right offsets if they're defined.
if (child->isLeadingPositionDefined(YGFlexDirectionRow) &&
child->isTrailingPosDefined(YGFlexDirectionRow)) {
childWidth = node->getLayout().measuredDimensions[YGDimensionWidth] -
(node->getLeadingBorder(YGFlexDirectionRow) +
node->getTrailingBorder(YGFlexDirectionRow)) -
- YGUnwrapFloatOptional(
- child->getLeadingPosition(YGFlexDirectionRow, width) +
- child->getTrailingPosition(YGFlexDirectionRow, width));
+ (child->getLeadingPosition(YGFlexDirectionRow, width) +
+ child->getTrailingPosition(YGFlexDirectionRow, width))
+ .unwrap();
childWidth =
YGNodeBoundAxis(child, YGFlexDirectionRow, childWidth, width, width);
}
}
if (YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn, height)) {
- childHeight = YGUnwrapFloatOptional(YGResolveValue(
- child->getResolvedDimension(YGDimensionHeight), height)) +
+ childHeight =
+ YGResolveValue(child->getResolvedDimension(YGDimensionHeight), height)
+ .unwrap() +
marginColumn;
} else {
- // If the child doesn't have a specified height, compute the height
- // based on the top/bottom
- // offsets if they're defined.
+ // If the child doesn't have a specified height, compute the height based on
+ // the top/bottom offsets if they're defined.
if (child->isLeadingPositionDefined(YGFlexDirectionColumn) &&
child->isTrailingPosDefined(YGFlexDirectionColumn)) {
- childHeight =
- node->getLayout().measuredDimensions[YGDimensionHeight] -
+ childHeight = node->getLayout().measuredDimensions[YGDimensionHeight] -
(node->getLeadingBorder(YGFlexDirectionColumn) +
node->getTrailingBorder(YGFlexDirectionColumn)) -
- YGUnwrapFloatOptional(
- child->getLeadingPosition(YGFlexDirectionColumn, height) +
- child->getTrailingPosition(YGFlexDirectionColumn, height));
+ (child->getLeadingPosition(YGFlexDirectionColumn, height) +
+ child->getTrailingPosition(YGFlexDirectionColumn, height))
+ .unwrap();
childHeight = YGNodeBoundAxis(
child, YGFlexDirectionColumn, childHeight, height, width);
}
@@ -1573,10 +1519,10 @@
if (YGFloatIsUndefined(childWidth)) {
childWidth = marginRow +
(childHeight - marginColumn) *
- child->getStyle().aspectRatio.getValue();
+ child->getStyle().aspectRatio.unwrap();
} else if (YGFloatIsUndefined(childHeight)) {
childHeight = marginColumn +
- (childWidth - marginRow) / child->getStyle().aspectRatio.getValue();
+ (childWidth - marginRow) / child->getStyle().aspectRatio.unwrap();
}
}
}
@@ -1612,13 +1558,12 @@
childHeight,
false,
"abs-measure",
- config);
+ config,
+ layoutMarkerData);
childWidth = child->getLayout().measuredDimensions[YGDimensionWidth] +
- YGUnwrapFloatOptional(
- child->getMarginForAxis(YGFlexDirectionRow, width));
+ child->getMarginForAxis(YGFlexDirectionRow, width).unwrap();
childHeight = child->getLayout().measuredDimensions[YGDimensionHeight] +
- YGUnwrapFloatOptional(
- child->getMarginForAxis(YGFlexDirectionColumn, width));
+ child->getMarginForAxis(YGFlexDirectionColumn, width).unwrap();
}
YGLayoutNodeInternal(
@@ -1632,7 +1577,8 @@
childHeight,
true,
"abs-layout",
- config);
+ config,
+ layoutMarkerData);
if (child->isTrailingPosDefined(mainAxis) &&
!child->isLeadingPositionDefined(mainAxis)) {
@@ -1640,9 +1586,9 @@
node->getLayout().measuredDimensions[dim[mainAxis]] -
child->getLayout().measuredDimensions[dim[mainAxis]] -
node->getTrailingBorder(mainAxis) -
- YGUnwrapFloatOptional(child->getTrailingMargin(mainAxis, width)) -
- YGUnwrapFloatOptional(child->getTrailingPosition(
- mainAxis, isMainAxisRow ? width : height)),
+ child->getTrailingMargin(mainAxis, width).unwrap() -
+ child->getTrailingPosition(mainAxis, isMainAxisRow ? width : height)
+ .unwrap(),
leading[mainAxis]);
} else if (
!child->isLeadingPositionDefined(mainAxis) &&
@@ -1667,9 +1613,10 @@
node->getLayout().measuredDimensions[dim[crossAxis]] -
child->getLayout().measuredDimensions[dim[crossAxis]] -
node->getTrailingBorder(crossAxis) -
- YGUnwrapFloatOptional(child->getTrailingMargin(crossAxis, width)) -
- YGUnwrapFloatOptional(child->getTrailingPosition(
- crossAxis, isMainAxisRow ? height : width)),
+ child->getTrailingMargin(crossAxis, width).unwrap() -
+ child
+ ->getTrailingPosition(crossAxis, isMainAxisRow ? height : width)
+ .unwrap(),
leading[crossAxis]);
} else if (
@@ -1708,10 +1655,10 @@
YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, availableWidth);
const float paddingAndBorderAxisColumn = YGNodePaddingAndBorderForAxis(
node, YGFlexDirectionColumn, availableWidth);
- const float marginAxisRow = YGUnwrapFloatOptional(
- node->getMarginForAxis(YGFlexDirectionRow, availableWidth));
- const float marginAxisColumn = YGUnwrapFloatOptional(
- node->getMarginForAxis(YGFlexDirectionColumn, availableWidth));
+ const float marginAxisRow =
+ node->getMarginForAxis(YGFlexDirectionRow, availableWidth).unwrap();
+ const float marginAxisColumn =
+ node->getMarginForAxis(YGFlexDirectionColumn, availableWidth).unwrap();
// We want to make sure we don't call measure with negative size
const float innerWidth = YGFloatIsUndefined(availableWidth)
@@ -1743,8 +1690,14 @@
YGDimensionHeight);
} else {
// Measure the text under the current constraints.
- const YGSize measuredSize = node->getMeasure()(
- node, innerWidth, widthMeasureMode, innerHeight, heightMeasureMode);
+ const YGSize measuredSize = marker::MarkerSection<YGMarkerMeasure>::wrap(
+ node,
+ node->getMeasure(),
+ node,
+ innerWidth,
+ widthMeasureMode,
+ innerHeight,
+ heightMeasureMode);
node->setLayoutMeasuredDimension(
YGNodeBoundAxis(
@@ -1786,10 +1739,10 @@
YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, ownerWidth);
const float paddingAndBorderAxisColumn =
YGNodePaddingAndBorderForAxis(node, YGFlexDirectionColumn, ownerWidth);
- const float marginAxisRow = YGUnwrapFloatOptional(
- node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
- const float marginAxisColumn = YGUnwrapFloatOptional(
- node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
+ const float marginAxisRow =
+ node->getMarginForAxis(YGFlexDirectionRow, ownerWidth).unwrap();
+ const float marginAxisColumn =
+ node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth).unwrap();
node->setLayoutMeasuredDimension(
YGNodeBoundAxis(
@@ -1830,10 +1783,10 @@
heightMeasureMode == YGMeasureModeAtMost && availableHeight <= 0.0f) ||
(widthMeasureMode == YGMeasureModeExactly &&
heightMeasureMode == YGMeasureModeExactly)) {
- auto marginAxisColumn = YGUnwrapFloatOptional(
- node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
- auto marginAxisRow = YGUnwrapFloatOptional(
- node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
+ auto marginAxisColumn =
+ node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth).unwrap();
+ auto marginAxisRow =
+ node->getMarginForAxis(YGFlexDirectionRow, ownerWidth).unwrap();
node->setLayoutMeasuredDimension(
YGNodeBoundAxis(
@@ -1867,7 +1820,9 @@
}
static void YGZeroOutLayoutRecursivly(const YGNodeRef node) {
- memset(&(node->getLayout()), 0, sizeof(YGLayout));
+ node->getLayout() = {};
+ node->setLayoutDimension(0, 0);
+ node->setLayoutDimension(0, 1);
node->setHasNewLayout(true);
node->cloneChildrenIfNeeded();
const uint32_t childCount = YGNodeGetChildCount(node);
@@ -1887,8 +1842,7 @@
YGDimension dimension =
YGFlexDirectionIsRow(axis) ? YGDimensionWidth : YGDimensionHeight;
- const float margin =
- YGUnwrapFloatOptional(node->getMarginForAxis(direction, ownerDim));
+ const float margin = node->getMarginForAxis(direction, ownerDim).unwrap();
const float paddingAndBorder =
YGNodePaddingAndBorderForAxis(node, direction, ownerDim);
@@ -1902,14 +1856,14 @@
YGResolveValue(node->getStyle().minDimensions[dimension], ownerDim);
const float minInnerDim = minDimensionOptional.isUndefined()
? 0.0f
- : minDimensionOptional.getValue() - paddingAndBorder;
+ : minDimensionOptional.unwrap() - paddingAndBorder;
const YGFloatOptional maxDimensionOptional =
YGResolveValue(node->getStyle().maxDimensions[dimension], ownerDim);
const float maxInnerDim = maxDimensionOptional.isUndefined()
? FLT_MAX
- : maxDimensionOptional.getValue() - paddingAndBorder;
+ : maxDimensionOptional.unwrap() - paddingAndBorder;
availableInnerDim =
YGFloatMax(YGFloatMin(availableInnerDim, maxInnerDim), minInnerDim);
}
@@ -1917,7 +1871,7 @@
return availableInnerDim;
}
-static void YGNodeComputeFlexBasisForChildren(
+static float YGNodeComputeFlexBasisForChildren(
const YGNodeRef node,
const float availableInnerWidth,
const float availableInnerHeight,
@@ -1927,7 +1881,8 @@
YGFlexDirection mainAxis,
const YGConfigRef config,
bool performLayout,
- float& totalOuterFlexBasis) {
+ YGMarkerLayoutData& layoutMarkerData) {
+ float totalOuterFlexBasis = 0.0f;
YGNodeRef singleFlexChild = nullptr;
YGVector children = node->getChildren();
YGMeasureMode measureModeMainDim =
@@ -1990,19 +1945,23 @@
availableInnerHeight,
heightMeasureMode,
direction,
- config);
+ config,
+ layoutMarkerData);
}
- totalOuterFlexBasis += YGUnwrapFloatOptional(
- child->getLayout().computedFlexBasis +
- child->getMarginForAxis(mainAxis, availableInnerWidth));
+ totalOuterFlexBasis +=
+ (child->getLayout().computedFlexBasis +
+ child->getMarginForAxis(mainAxis, availableInnerWidth))
+ .unwrap();
}
+
+ return totalOuterFlexBasis;
}
// This function assumes that all the children of node have their
// computedFlexBasis properly computed(To do this use
-// YGNodeComputeFlexBasisForChildren function).
-// This function calculates YGCollectFlexItemsRowMeasurement
+// YGNodeComputeFlexBasisForChildren function). This function calculates
+// YGCollectFlexItemsRowMeasurement
static YGCollectFlexItemsRowValues YGCalculateCollectFlexItemsRowValues(
const YGNodeRef& node,
const YGDirection ownerDirection,
@@ -2028,19 +1987,19 @@
continue;
}
child->setLineIndex(lineCount);
- const float childMarginMainAxis = YGUnwrapFloatOptional(
- child->getMarginForAxis(mainAxis, availableInnerWidth));
+ const float childMarginMainAxis =
+ child->getMarginForAxis(mainAxis, availableInnerWidth).unwrap();
const float flexBasisWithMinAndMaxConstraints =
- YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
+ YGNodeBoundAxisWithinMinAndMax(
child,
mainAxis,
- YGUnwrapFloatOptional(child->getLayout().computedFlexBasis),
- mainAxisownerSize));
-
- // If this is a multi-line flow and this item pushes us over the
- // available size, we've
- // hit the end of the current line. Break out of the loop and lay out
- // the current line.
+ child->getLayout().computedFlexBasis,
+ mainAxisownerSize)
+ .unwrap();
+
+ // If this is a multi-line flow and this item pushes us over the available
+ // size, we've hit the end of the current line. Break out of the loop and
+ // lay out the current line.
if (sizeConsumedOnCurrentLineIncludingMinConstraint +
flexBasisWithMinAndMaxConstraints + childMarginMainAxis >
availableInnerMainDim &&
@@ -2061,7 +2020,7 @@
// child dimension.
flexAlgoRowMeasurement.totalFlexShrinkScaledFactors +=
-child->resolveFlexShrink() *
- YGUnwrapFloatOptional(child->getLayout().computedFlexBasis);
+ child->getLayout().computedFlexBasis.unwrap();
}
flexAlgoRowMeasurement.relativeChildren.push_back(child);
@@ -2099,7 +2058,8 @@
const bool flexBasisOverflows,
const YGMeasureMode measureModeCrossDim,
const bool performLayout,
- const YGConfigRef config) {
+ const YGConfigRef config,
+ YGMarkerLayoutData& layoutMarkerData) {
float childFlexBasis = 0;
float flexShrinkScaledFactor = 0;
float flexGrowFactor = 0;
@@ -2108,12 +2068,12 @@
const bool isNodeFlexWrap = node->getStyle().flexWrap != YGWrapNoWrap;
for (auto currentRelativeChild : collectedFlexItemsValues.relativeChildren) {
- childFlexBasis = YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
+ childFlexBasis = YGNodeBoundAxisWithinMinAndMax(
currentRelativeChild,
mainAxis,
- YGUnwrapFloatOptional(
- currentRelativeChild->getLayout().computedFlexBasis),
- mainAxisownerSize));
+ currentRelativeChild->getLayout().computedFlexBasis,
+ mainAxisownerSize)
+ .unwrap();
float updatedMainSize = childFlexBasis;
if (!YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) &&
@@ -2163,10 +2123,12 @@
deltaFreeSpace += updatedMainSize - childFlexBasis;
- const float marginMain = YGUnwrapFloatOptional(
- currentRelativeChild->getMarginForAxis(mainAxis, availableInnerWidth));
- const float marginCross = YGUnwrapFloatOptional(
- currentRelativeChild->getMarginForAxis(crossAxis, availableInnerWidth));
+ const float marginMain =
+ currentRelativeChild->getMarginForAxis(mainAxis, availableInnerWidth)
+ .unwrap();
+ const float marginCross =
+ currentRelativeChild->getMarginForAxis(crossAxis, availableInnerWidth)
+ .unwrap();
float childCrossSize;
float childMainSize = updatedMainSize + marginMain;
@@ -2175,9 +2137,9 @@
if (!currentRelativeChild->getStyle().aspectRatio.isUndefined()) {
childCrossSize = isMainAxisRow ? (childMainSize - marginMain) /
- currentRelativeChild->getStyle().aspectRatio.getValue()
+ currentRelativeChild->getStyle().aspectRatio.unwrap()
: (childMainSize - marginMain) *
- currentRelativeChild->getStyle().aspectRatio.getValue();
+ currentRelativeChild->getStyle().aspectRatio.unwrap();
childCrossMeasureMode = YGMeasureModeExactly;
childCrossSize += marginCross;
@@ -2202,9 +2164,10 @@
: YGMeasureModeAtMost;
} else {
childCrossSize =
- YGUnwrapFloatOptional(YGResolveValue(
+ YGResolveValue(
currentRelativeChild->getResolvedDimension(dim[crossAxis]),
- availableInnerCrossDim)) +
+ availableInnerCrossDim)
+ .unwrap() +
marginCross;
const bool isLoosePercentageMeasurement =
currentRelativeChild->getResolvedDimension(dim[crossAxis]).unit ==
@@ -2260,7 +2223,8 @@
availableInnerHeight,
performLayout && !requiresStretchLayout,
"flex",
- config);
+ config,
+ layoutMarkerData);
node->setLayoutHadOverflow(
node->getLayout().hadOverflow |
currentRelativeChild->getLayout().hadOverflow);
@@ -2284,12 +2248,13 @@
float deltaFreeSpace = 0;
for (auto currentRelativeChild : collectedFlexItemsValues.relativeChildren) {
- float childFlexBasis = YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
+ float childFlexBasis =
+ YGNodeBoundAxisWithinMinAndMax(
currentRelativeChild,
mainAxis,
- YGUnwrapFloatOptional(
- currentRelativeChild->getLayout().computedFlexBasis),
- mainAxisownerSize));
+ currentRelativeChild->getLayout().computedFlexBasis,
+ mainAxisownerSize)
+ .unwrap();
if (collectedFlexItemsValues.remainingFreeSpace < 0) {
flexShrinkScaledFactor =
@@ -2311,12 +2276,10 @@
if (!YGFloatIsUndefined(baseMainSize) &&
!YGFloatIsUndefined(boundMainSize) &&
baseMainSize != boundMainSize) {
- // By excluding this item's size and flex factor from remaining,
- // this item's
- // min/max constraints should also trigger in the second pass
- // resulting in the
- // item's size calculation being identical in the first and second
- // passes.
+ // By excluding this item's size and flex factor from remaining, this
+ // item's min/max constraints should also trigger in the second pass
+ // resulting in the item's size calculation being identical in the
+ // first and second passes.
deltaFreeSpace += boundMainSize - childFlexBasis;
collectedFlexItemsValues.totalFlexShrinkScaledFactors -=
flexShrinkScaledFactor;
@@ -2342,12 +2305,10 @@
if (!YGFloatIsUndefined(baseMainSize) &&
!YGFloatIsUndefined(boundMainSize) &&
baseMainSize != boundMainSize) {
- // By excluding this item's size and flex factor from remaining,
- // this item's
- // min/max constraints should also trigger in the second pass
- // resulting in the
- // item's size calculation being identical in the first and second
- // passes.
+ // By excluding this item's size and flex factor from remaining, this
+ // item's min/max constraints should also trigger in the second pass
+ // resulting in the item's size calculation being identical in the
+ // first and second passes.
deltaFreeSpace += boundMainSize - childFlexBasis;
collectedFlexItemsValues.totalFlexGrowFactors -= flexGrowFactor;
}
@@ -2359,25 +2320,22 @@
// Do two passes over the flex items to figure out how to distribute the
// remaining space.
-// The first pass finds the items whose min/max constraints trigger,
-// freezes them at those
-// sizes, and excludes those sizes from the remaining space. The second
-// pass sets the size
-// of each flexible item. It distributes the remaining space amongst the
-// items whose min/max
-// constraints didn't trigger in pass 1. For the other items, it sets
-// their sizes by forcing
-// their min/max constraints to trigger again.
//
-// This two pass approach for resolving min/max constraints deviates from
-// the spec. The
-// spec (https://www.w3.org/TR/YG-flexbox-1/#resolve-flexible-lengths)
-// describes a process
-// that needs to be repeated a variable number of times. The algorithm
-// implemented here
-// won't handle all cases but it was simpler to implement and it mitigates
-// performance
-// concerns because we know exactly how many passes it'll do.
+// The first pass finds the items whose min/max constraints trigger, freezes
+// them at those sizes, and excludes those sizes from the remaining space.
+//
+// The second pass sets the size of each flexible item. It distributes the
+// remaining space amongst the items whose min/max constraints didn't trigger in
+// the first pass. For the other items, it sets their sizes by forcing their
+// min/max constraints to trigger again.
+//
+// This two pass approach for resolving min/max constraints deviates from the
+// spec. The spec
+// (https://www.w3.org/TR/CSS-flexbox-1/#resolve-flexible-lengths) describes a
+// process that needs to be repeated a variable number of times. The algorithm
+// implemented here won't handle all cases but it was simpler to implement and
+// it mitigates performance concerns because we know exactly how many passes
+// it'll do.
//
// At the end of this function the child nodes would have the proper size
// assigned to them.
@@ -2395,7 +2353,8 @@
const bool flexBasisOverflows,
const YGMeasureMode measureModeCrossDim,
const bool performLayout,
- const YGConfigRef config) {
+ const YGConfigRef config,
+ YGMarkerLayoutData& layoutMarkerData) {
const float originalFreeSpace = collectedFlexItemsValues.remainingFreeSpace;
// First pass: detect the flex items whose min/max constraints trigger
YGDistributeFreeSpaceFirstPass(
@@ -2419,7 +2378,8 @@
flexBasisOverflows,
measureModeCrossDim,
performLayout,
- config);
+ config,
+ layoutMarkerData);
collectedFlexItemsValues.remainingFreeSpace =
originalFreeSpace - distributedFreeSpace;
@@ -2428,32 +2388,44 @@
static void YGJustifyMainAxis(
const YGNodeRef node,
YGCollectFlexItemsRowValues& collectedFlexItemsValues,
- const uint32_t& startOfLineIndex,
- const YGFlexDirection& mainAxis,
- const YGFlexDirection& crossAxis,
- const YGMeasureMode& measureModeMainDim,
- const YGMeasureMode& measureModeCrossDim,
- const float& mainAxisownerSize,
- const float& ownerWidth,
- const float& availableInnerMainDim,
- const float& availableInnerCrossDim,
- const float& availableInnerWidth,
- const bool& performLayout) {
- const YGStyle style = node->getStyle();
-
- // If we are using "at most" rules in the main axis. Calculate the remaining
- // space when constraint by the min size defined for the main axis.
+ const uint32_t startOfLineIndex,
+ const YGFlexDirection mainAxis,
+ const YGFlexDirection crossAxis,
+ const YGMeasureMode measureModeMainDim,
+ const YGMeasureMode measureModeCrossDim,
+ const float mainAxisownerSize,
+ const float ownerWidth,
+ const float availableInnerMainDim,
+ const float availableInnerCrossDim,
+ const float availableInnerWidth,
+ const bool performLayout) {
+ const YGStyle& style = node->getStyle();
+ const float leadingPaddingAndBorderMain =
+ node->getLeadingPaddingAndBorder(mainAxis, ownerWidth).unwrap();
+ const float trailingPaddingAndBorderMain =
+ node->getTrailingPaddingAndBorder(mainAxis, ownerWidth).unwrap();
+ // If we are using "at most" rules in the main axis, make sure that
+ // remainingFreeSpace is 0 when min main dimension is not given
if (measureModeMainDim == YGMeasureModeAtMost &&
collectedFlexItemsValues.remainingFreeSpace > 0) {
- if (style.minDimensions[dim[mainAxis]].unit != YGUnitUndefined &&
+ if (!style.minDimensions[dim[mainAxis]].isUndefined() &&
!YGResolveValue(style.minDimensions[dim[mainAxis]], mainAxisownerSize)
.isUndefined()) {
- collectedFlexItemsValues.remainingFreeSpace = YGFloatMax(
- 0,
- YGUnwrapFloatOptional(YGResolveValue(
- style.minDimensions[dim[mainAxis]], mainAxisownerSize)) -
- (availableInnerMainDim -
- collectedFlexItemsValues.remainingFreeSpace));
+ // This condition makes sure that if the size of main dimension(after
+ // considering child nodes main dim, leading and trailing padding etc)
+ // falls below min dimension, then the remainingFreeSpace is reassigned
+ // considering the min dimension
+
+ // `minAvailableMainDim` denotes minimum available space in which child
+ // can be laid out, it will exclude space consumed by padding and border.
+ const float minAvailableMainDim =
+ YGResolveValue(style.minDimensions[dim[mainAxis]], mainAxisownerSize)
+ .unwrap() -
+ leadingPaddingAndBorderMain - trailingPaddingAndBorderMain;
+ const float occupiedSpaceByChildNodes =
+ availableInnerMainDim - collectedFlexItemsValues.remainingFreeSpace;
+ collectedFlexItemsValues.remainingFreeSpace =
+ YGFloatMax(0, minAvailableMainDim - occupiedSpaceByChildNodes);
} else {
collectedFlexItemsValues.remainingFreeSpace = 0;
}
@@ -2474,9 +2446,9 @@
}
}
- // In order to position the elements in the main axis, we have two
- // controls. The space between the beginning and the first element
- // and the space between each two elements.
+ // In order to position the elements in the main axis, we have two controls.
+ // The space between the beginning and the first element and the space between
+ // each two elements.
float leadingMainDim = 0;
float betweenMainDim = 0;
const YGJustify justifyContent = node->getStyle().justifyContent;
@@ -2515,17 +2487,18 @@
}
}
- const float leadingPaddingAndBorderMain = YGUnwrapFloatOptional(
- node->getLeadingPaddingAndBorder(mainAxis, ownerWidth));
collectedFlexItemsValues.mainDim =
leadingPaddingAndBorderMain + leadingMainDim;
collectedFlexItemsValues.crossDim = 0;
+ float maxAscentForCurrentLine = 0;
+ float maxDescentForCurrentLine = 0;
+ bool isNodeBaselineLayout = YGIsBaselineLayout(node);
for (uint32_t i = startOfLineIndex;
i < collectedFlexItemsValues.endOfLineIndex;
i++) {
const YGNodeRef child = node->getChild(i);
- const YGStyle childStyle = child->getStyle();
+ const YGStyle& childStyle = child->getStyle();
const YGLayout childLayout = child->getLayout();
if (childStyle.display == YGDisplayNone) {
continue;
@@ -2534,20 +2507,19 @@
child->isLeadingPositionDefined(mainAxis)) {
if (performLayout) {
// In case the child is position absolute and has left/top being
- // defined, we override the position to whatever the user said
- // (and margin/border).
+ // defined, we override the position to whatever the user said (and
+ // margin/border).
child->setLayoutPosition(
- YGUnwrapFloatOptional(
- child->getLeadingPosition(mainAxis, availableInnerMainDim)) +
+ child->getLeadingPosition(mainAxis, availableInnerMainDim)
+ .unwrap() +
node->getLeadingBorder(mainAxis) +
- YGUnwrapFloatOptional(
- child->getLeadingMargin(mainAxis, availableInnerWidth)),
+ child->getLeadingMargin(mainAxis, availableInnerWidth).unwrap(),
pos[mainAxis]);
}
} else {
// Now that we placed the element, we need to update the variables.
- // We need to do that only for relative elements. Absolute elements
- // do not take part in that phase.
+ // We need to do that only for relative elements. Absolute elements do not
+ // take part in that phase.
if (childStyle.positionType == YGPositionTypeRelative) {
if (child->marginLeadingValue(mainAxis).unit == YGUnitAuto) {
collectedFlexItemsValues.mainDim +=
@@ -2570,14 +2542,12 @@
bool canSkipFlex =
!performLayout && measureModeCrossDim == YGMeasureModeExactly;
if (canSkipFlex) {
- // If we skipped the flex step, then we can't rely on the
- // measuredDims because
- // they weren't computed. This means we can't call
+ // If we skipped the flex step, then we can't rely on the measuredDims
+ // because they weren't computed. This means we can't call
// YGNodeDimWithMargin.
collectedFlexItemsValues.mainDim += betweenMainDim +
- YGUnwrapFloatOptional(child->getMarginForAxis(
- mainAxis, availableInnerWidth)) +
- YGUnwrapFloatOptional(childLayout.computedFlexBasis);
+ child->getMarginForAxis(mainAxis, availableInnerWidth).unwrap() +
+ childLayout.computedFlexBasis.unwrap();
collectedFlexItemsValues.crossDim = availableInnerCrossDim;
} else {
// The main dimension is the sum of all the elements dimension plus
@@ -2585,12 +2555,35 @@
collectedFlexItemsValues.mainDim += betweenMainDim +
YGNodeDimWithMargin(child, mainAxis, availableInnerWidth);
+ if (isNodeBaselineLayout) {
+ // If the child is baseline aligned then the cross dimension is
+ // calculated by adding maxAscent and maxDescent from the baseline.
+ const float ascent = YGBaseline(child) +
+ child
+ ->getLeadingMargin(
+ YGFlexDirectionColumn, availableInnerWidth)
+ .unwrap();
+ const float descent =
+ child->getLayout().measuredDimensions[YGDimensionHeight] +
+ child
+ ->getMarginForAxis(
+ YGFlexDirectionColumn, availableInnerWidth)
+ .unwrap() -
+ ascent;
+
+ maxAscentForCurrentLine =
+ YGFloatMax(maxAscentForCurrentLine, ascent);
+ maxDescentForCurrentLine =
+ YGFloatMax(maxDescentForCurrentLine, descent);
+ } else {
// The cross dimension is the max of the elements dimension since
- // there can only be one element in that cross dimension.
+ // there can only be one element in that cross dimension in the case
+ // when the items are not baseline aligned
collectedFlexItemsValues.crossDim = YGFloatMax(
collectedFlexItemsValues.crossDim,
YGNodeDimWithMargin(child, crossAxis, availableInnerWidth));
}
+ }
} else if (performLayout) {
child->setLayoutPosition(
childLayout.position[pos[mainAxis]] +
@@ -2599,87 +2592,71 @@
}
}
}
- collectedFlexItemsValues.mainDim += YGUnwrapFloatOptional(
- node->getTrailingPaddingAndBorder(mainAxis, ownerWidth));
+ collectedFlexItemsValues.mainDim += trailingPaddingAndBorderMain;
+
+ if (isNodeBaselineLayout) {
+ collectedFlexItemsValues.crossDim =
+ maxAscentForCurrentLine + maxDescentForCurrentLine;
+ }
}
//
// This is the main routine that implements a subset of the flexbox layout
-// algorithm
-// described in the W3C YG documentation: https://www.w3.org/TR/YG3-flexbox/.
+// algorithm described in the W3C CSS documentation:
+// https://www.w3.org/TR/CSS3-flexbox/.
//
// Limitations of this algorithm, compared to the full standard:
// * Display property is always assumed to be 'flex' except for Text nodes,
-// which
-// are assumed to be 'inline-flex'.
+// which are assumed to be 'inline-flex'.
// * The 'zIndex' property (or any form of z ordering) is not supported. Nodes
-// are
-// stacked in document order.
+// are stacked in document order.
// * The 'order' property is not supported. The order of flex items is always
-// defined
-// by document order.
+// defined by document order.
// * The 'visibility' property is always assumed to be 'visible'. Values of
-// 'collapse'
-// and 'hidden' are not supported.
+// 'collapse' and 'hidden' are not supported.
// * There is no support for forced breaks.
// * It does not support vertical inline directions (top-to-bottom or
// bottom-to-top text).
//
// Deviations from standard:
// * Section 4.5 of the spec indicates that all flex items have a default
-// minimum
-// main size. For text blocks, for example, this is the width of the widest
-// word.
-// Calculating the minimum width is expensive, so we forego it and assume a
-// default
-// minimum main size of 0.
+// minimum main size. For text blocks, for example, this is the width of the
+// widest word. Calculating the minimum width is expensive, so we forego it
+// and assume a default minimum main size of 0.
// * Min/Max sizes in the main axis are not honored when resolving flexible
// lengths.
// * The spec indicates that the default value for 'flexDirection' is 'row',
-// but
-// the algorithm below assumes a default of 'column'.
+// but the algorithm below assumes a default of 'column'.
//
// Input parameters:
// - node: current node to be sized and layed out
// - availableWidth & availableHeight: available size to be used for sizing
-// the node
-// or YGUndefined if the size is not available; interpretation depends on
-// layout
-// flags
+// the node or YGUndefined if the size is not available; interpretation
+// depends on layout flags
// - ownerDirection: the inline (text) direction within the owner
-// (left-to-right or
-// right-to-left)
+// (left-to-right or right-to-left)
// - widthMeasureMode: indicates the sizing rules for the width (see below
// for explanation)
// - heightMeasureMode: indicates the sizing rules for the height (see below
// for explanation)
// - performLayout: specifies whether the caller is interested in just the
-// dimensions
-// of the node or it requires the entire node and its subtree to be layed
-// out
-// (with final positions)
+// dimensions of the node or it requires the entire node and its subtree to
+// be layed out (with final positions)
//
// Details:
// This routine is called recursively to lay out subtrees of flexbox
-// elements. It uses the
-// information in node.style, which is treated as a read-only input. It is
-// responsible for
-// setting the layout.direction and layout.measuredDimensions fields for the
-// input node as well
-// as the layout.position and layout.lineIndex fields for its child nodes.
-// The
+// elements. It uses the information in node.style, which is treated as a
+// read-only input. It is responsible for setting the layout.direction and
+// layout.measuredDimensions fields for the input node as well as the
+// layout.position and layout.lineIndex fields for its child nodes. The
// layout.measuredDimensions field includes any border or padding for the
-// node but does
-// not include margins.
+// node but does not include margins.
//
// The spec describes four different layout modes: "fill available", "max
-// content", "min
-// content",
-// and "fit content". Of these, we don't use "min content" because we don't
-// support default
-// minimum main sizes (see above for details). Each of our measure modes maps
-// to a layout mode
-// from the spec (https://www.w3.org/TR/YG3-sizing/#terms):
+// content", "min content", and "fit content". Of these, we don't use "min
+// content" because we don't support default minimum main sizes (see above
+// for details). Each of our measure modes maps to a layout mode from the
+// spec (https://www.w3.org/TR/CSS3-sizing/#terms):
// - YGMeasureModeUndefined: max content
// - YGMeasureModeExactly: fill available
// - YGMeasureModeAtMost: fit content
@@ -2698,7 +2675,8 @@
const float ownerWidth,
const float ownerHeight,
const bool performLayout,
- const YGConfigRef config) {
+ const YGConfigRef config,
+ YGMarkerLayoutData& layoutMarkerData) {
YGAssertWithNode(
node,
YGFloatIsUndefined(availableWidth)
@@ -2714,6 +2692,8 @@
"availableHeight is indefinite so heightMeasureMode must be "
"YGMeasureModeUndefined");
+ (performLayout ? layoutMarkerData.layouts : layoutMarkerData.measures) += 1;
+
// Set the resolved resolution in the node's layout.
const YGDirection direction = node->resolveDirection(ownerDirection);
node->setLayoutDirection(direction);
@@ -2724,20 +2704,16 @@
YGResolveFlexDirection(YGFlexDirectionColumn, direction);
node->setLayoutMargin(
- YGUnwrapFloatOptional(
- node->getLeadingMargin(flexRowDirection, ownerWidth)),
+ node->getLeadingMargin(flexRowDirection, ownerWidth).unwrap(),
YGEdgeStart);
node->setLayoutMargin(
- YGUnwrapFloatOptional(
- node->getTrailingMargin(flexRowDirection, ownerWidth)),
+ node->getTrailingMargin(flexRowDirection, ownerWidth).unwrap(),
YGEdgeEnd);
node->setLayoutMargin(
- YGUnwrapFloatOptional(
- node->getLeadingMargin(flexColumnDirection, ownerWidth)),
+ node->getLeadingMargin(flexColumnDirection, ownerWidth).unwrap(),
YGEdgeTop);
node->setLayoutMargin(
- YGUnwrapFloatOptional(
- node->getTrailingMargin(flexColumnDirection, ownerWidth)),
+ node->getTrailingMargin(flexColumnDirection, ownerWidth).unwrap(),
YGEdgeBottom);
node->setLayoutBorder(node->getLeadingBorder(flexRowDirection), YGEdgeStart);
@@ -2747,20 +2723,16 @@
node->getTrailingBorder(flexColumnDirection), YGEdgeBottom);
node->setLayoutPadding(
- YGUnwrapFloatOptional(
- node->getLeadingPadding(flexRowDirection, ownerWidth)),
+ node->getLeadingPadding(flexRowDirection, ownerWidth).unwrap(),
YGEdgeStart);
node->setLayoutPadding(
- YGUnwrapFloatOptional(
- node->getTrailingPadding(flexRowDirection, ownerWidth)),
+ node->getTrailingPadding(flexRowDirection, ownerWidth).unwrap(),
YGEdgeEnd);
node->setLayoutPadding(
- YGUnwrapFloatOptional(
- node->getLeadingPadding(flexColumnDirection, ownerWidth)),
+ node->getLeadingPadding(flexColumnDirection, ownerWidth).unwrap(),
YGEdgeTop);
node->setLayoutPadding(
- YGUnwrapFloatOptional(
- node->getTrailingPadding(flexColumnDirection, ownerWidth)),
+ node->getTrailingPadding(flexColumnDirection, ownerWidth).unwrap(),
YGEdgeBottom);
if (node->getMeasure() != nullptr) {
@@ -2818,8 +2790,8 @@
const float mainAxisownerSize = isMainAxisRow ? ownerWidth : ownerHeight;
const float crossAxisownerSize = isMainAxisRow ? ownerHeight : ownerWidth;
- const float leadingPaddingAndBorderCross = YGUnwrapFloatOptional(
- node->getLeadingPaddingAndBorder(crossAxis, ownerWidth));
+ const float leadingPaddingAndBorderCross =
+ node->getLeadingPaddingAndBorder(crossAxis, ownerWidth).unwrap();
const float paddingAndBorderAxisMain =
YGNodePaddingAndBorderForAxis(node, mainAxis, ownerWidth);
const float paddingAndBorderAxisCross =
@@ -2835,26 +2807,30 @@
const float paddingAndBorderAxisColumn =
isMainAxisRow ? paddingAndBorderAxisCross : paddingAndBorderAxisMain;
- const float marginAxisRow = YGUnwrapFloatOptional(
- node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
- const float marginAxisColumn = YGUnwrapFloatOptional(
- node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
+ const float marginAxisRow =
+ node->getMarginForAxis(YGFlexDirectionRow, ownerWidth).unwrap();
+ const float marginAxisColumn =
+ node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth).unwrap();
const float minInnerWidth =
- YGUnwrapFloatOptional(YGResolveValue(
- node->getStyle().minDimensions[YGDimensionWidth], ownerWidth)) -
+ YGResolveValue(
+ node->getStyle().minDimensions[YGDimensionWidth], ownerWidth)
+ .unwrap() -
paddingAndBorderAxisRow;
const float maxInnerWidth =
- YGUnwrapFloatOptional(YGResolveValue(
- node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth)) -
+ YGResolveValue(
+ node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth)
+ .unwrap() -
paddingAndBorderAxisRow;
const float minInnerHeight =
- YGUnwrapFloatOptional(YGResolveValue(
- node->getStyle().minDimensions[YGDimensionHeight], ownerHeight)) -
+ YGResolveValue(
+ node->getStyle().minDimensions[YGDimensionHeight], ownerHeight)
+ .unwrap() -
paddingAndBorderAxisColumn;
const float maxInnerHeight =
- YGUnwrapFloatOptional(YGResolveValue(
- node->getStyle().maxDimensions[YGDimensionHeight], ownerHeight)) -
+ YGResolveValue(
+ node->getStyle().maxDimensions[YGDimensionHeight], ownerHeight)
+ .unwrap() -
paddingAndBorderAxisColumn;
const float minInnerMainDim = isMainAxisRow ? minInnerWidth : minInnerHeight;
@@ -2872,11 +2848,9 @@
const float availableInnerCrossDim =
isMainAxisRow ? availableInnerHeight : availableInnerWidth;
- float totalOuterFlexBasis = 0;
-
// STEP 3: DETERMINE FLEX BASIS FOR EACH ITEM
- YGNodeComputeFlexBasisForChildren(
+ float totalOuterFlexBasis = YGNodeComputeFlexBasisForChildren(
node,
availableInnerWidth,
availableInnerHeight,
@@ -2886,7 +2860,7 @@
mainAxis,
config,
performLayout,
- totalOuterFlexBasis);
+ layoutMarkerData);
const bool flexBasisOverflows = measureModeMainDim == YGMeasureModeUndefined
? false
@@ -2928,9 +2902,9 @@
!performLayout && measureModeCrossDim == YGMeasureModeExactly;
// STEP 5: RESOLVING FLEXIBLE LENGTHS ON MAIN AXIS
- // Calculate the remaining available space that needs to be allocated.
- // If the main dimension size isn't known, it is computed based on
- // the line length, so there's no more space left to distribute.
+ // Calculate the remaining available space that needs to be allocated. If
+ // the main dimension size isn't known, it is computed based on the line
+ // length, so there's no more space left to distribute.
bool sizeBasedOnContent = false;
// If we don't measure with exact main dimension we want to ensure we don't
@@ -2992,7 +2966,8 @@
flexBasisOverflows,
measureModeCrossDim,
performLayout,
- config);
+ config,
+ layoutMarkerData);
}
node->setLayoutHadOverflow(
@@ -3002,11 +2977,9 @@
// STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION
// At this point, all the children have their dimensions set in the main
- // axis.
- // Their dimensions are also set in the cross axis with the exception of
- // items
- // that are aligned "stretch". We need to compute these stretch values and
- // set the final positions.
+ // axis. Their dimensions are also set in the cross axis with the exception
+ // of items that are aligned "stretch". We need to compute these stretch
+ // values and set the final positions.
YGJustifyMainAxis(
node,
@@ -3062,17 +3035,17 @@
}
if (child->getStyle().positionType == YGPositionTypeAbsolute) {
// If the child is absolutely positioned and has a
- // top/left/bottom/right set, override
- // all the previously computed positions to set it correctly.
+ // top/left/bottom/right set, override all the previously computed
+ // positions to set it correctly.
const bool isChildLeadingPosDefined =
child->isLeadingPositionDefined(crossAxis);
if (isChildLeadingPosDefined) {
child->setLayoutPosition(
- YGUnwrapFloatOptional(child->getLeadingPosition(
- crossAxis, availableInnerCrossDim)) +
+ child->getLeadingPosition(crossAxis, availableInnerCrossDim)
+ .unwrap() +
node->getLeadingBorder(crossAxis) +
- YGUnwrapFloatOptional(child->getLeadingMargin(
- crossAxis, availableInnerWidth)),
+ child->getLeadingMargin(crossAxis, availableInnerWidth)
+ .unwrap(),
pos[crossAxis]);
}
// If leading position is not defined or calculations result in Nan,
@@ -3081,8 +3054,8 @@
YGFloatIsUndefined(child->getLayout().position[pos[crossAxis]])) {
child->setLayoutPosition(
node->getLeadingBorder(crossAxis) +
- YGUnwrapFloatOptional(child->getLeadingMargin(
- crossAxis, availableInnerWidth)),
+ child->getLeadingMargin(crossAxis, availableInnerWidth)
+ .unwrap(),
pos[crossAxis]);
}
} else {
@@ -3094,9 +3067,8 @@
const YGAlign alignItem = YGNodeAlignItem(node, child);
// If the child uses align stretch, we need to lay it out one more
- // time, this time
- // forcing the cross-axis size to be the computed cross size for the
- // current line.
+ // time, this time forcing the cross-axis size to be the computed
+ // cross size for the current line.
if (alignItem == YGAlignStretch &&
child->marginLeadingValue(crossAxis).unit != YGUnitAuto &&
child->marginTrailingValue(crossAxis).unit != YGUnitAuto) {
@@ -3108,16 +3080,17 @@
child->getLayout().measuredDimensions[dim[mainAxis]];
float childCrossSize =
!child->getStyle().aspectRatio.isUndefined()
- ? ((YGUnwrapFloatOptional(child->getMarginForAxis(
- crossAxis, availableInnerWidth)) +
+ ? child->getMarginForAxis(crossAxis, availableInnerWidth)
+ .unwrap() +
(isMainAxisRow ? childMainSize /
- child->getStyle().aspectRatio.getValue()
+ child->getStyle().aspectRatio.unwrap()
: childMainSize *
- child->getStyle().aspectRatio.getValue())))
+ child->getStyle().aspectRatio.unwrap())
: collectedFlexItemsValues.crossDim;
- childMainSize += YGUnwrapFloatOptional(
- child->getMarginForAxis(mainAxis, availableInnerWidth));
+ childMainSize +=
+ child->getMarginForAxis(mainAxis, availableInnerWidth)
+ .unwrap();
YGMeasureMode childMainMeasureMode = YGMeasureModeExactly;
YGMeasureMode childCrossMeasureMode = YGMeasureModeExactly;
@@ -3159,7 +3132,8 @@
availableInnerHeight,
true,
"stretch",
- config);
+ config,
+ layoutMarkerData);
}
} else {
const float remainingCrossDim = containerCrossAxis -
@@ -3197,14 +3171,13 @@
}
// STEP 8: MULTI-LINE CONTENT ALIGNMENT
- if (performLayout && (lineCount > 1 || YGIsBaselineLayout(node)) &&
- !YGFloatIsUndefined(availableInnerCrossDim)) {
- const float remainingAlignContentDim =
- availableInnerCrossDim - totalLineCrossDim;
-
+ // currentLead stores the size of the cross dim
+ if (performLayout && (lineCount > 1 || YGIsBaselineLayout(node))) {
float crossDimLead = 0;
float currentLead = leadingPaddingAndBorderCross;
-
+ if (!YGFloatIsUndefined(availableInnerCrossDim)) {
+ const float remainingAlignContentDim =
+ availableInnerCrossDim - totalLineCrossDim;
switch (node->getStyle().alignContent) {
case YGAlignFlexEnd:
currentLead += remainingAlignContentDim;
@@ -3237,7 +3210,7 @@
case YGAlignBaseline:
break;
}
-
+ }
uint32_t endIndex = 0;
for (uint32_t i = 0; i < lineCount; i++) {
const uint32_t startIndex = endIndex;
@@ -3260,17 +3233,21 @@
lineHeight = YGFloatMax(
lineHeight,
child->getLayout().measuredDimensions[dim[crossAxis]] +
- YGUnwrapFloatOptional(child->getMarginForAxis(
- crossAxis, availableInnerWidth)));
+ child->getMarginForAxis(crossAxis, availableInnerWidth)
+ .unwrap());
}
if (YGNodeAlignItem(node, child) == YGAlignBaseline) {
const float ascent = YGBaseline(child) +
- YGUnwrapFloatOptional(child->getLeadingMargin(
- YGFlexDirectionColumn, availableInnerWidth));
+ child
+ ->getLeadingMargin(
+ YGFlexDirectionColumn, availableInnerWidth)
+ .unwrap();
const float descent =
child->getLayout().measuredDimensions[YGDimensionHeight] +
- YGUnwrapFloatOptional(child->getMarginForAxis(
- YGFlexDirectionColumn, availableInnerWidth)) -
+ child
+ ->getMarginForAxis(
+ YGFlexDirectionColumn, availableInnerWidth)
+ .unwrap() -
ascent;
maxAscentForCurrentLine =
YGFloatMax(maxAscentForCurrentLine, ascent);
@@ -3295,16 +3272,16 @@
case YGAlignFlexStart: {
child->setLayoutPosition(
currentLead +
- YGUnwrapFloatOptional(child->getLeadingMargin(
- crossAxis, availableInnerWidth)),
+ child->getLeadingMargin(crossAxis, availableInnerWidth)
+ .unwrap(),
pos[crossAxis]);
break;
}
case YGAlignFlexEnd: {
child->setLayoutPosition(
currentLead + lineHeight -
- YGUnwrapFloatOptional(child->getTrailingMargin(
- crossAxis, availableInnerWidth)) -
+ child->getTrailingMargin(crossAxis, availableInnerWidth)
+ .unwrap() -
child->getLayout().measuredDimensions[dim[crossAxis]],
pos[crossAxis]);
break;
@@ -3321,8 +3298,8 @@
case YGAlignStretch: {
child->setLayoutPosition(
currentLead +
- YGUnwrapFloatOptional(child->getLeadingMargin(
- crossAxis, availableInnerWidth)),
+ child->getLeadingMargin(crossAxis, availableInnerWidth)
+ .unwrap(),
pos[crossAxis]);
// Remeasure child with the line height as it as been only
@@ -3332,15 +3309,15 @@
const float childWidth = isMainAxisRow
? (child->getLayout()
.measuredDimensions[YGDimensionWidth] +
- YGUnwrapFloatOptional(child->getMarginForAxis(
- mainAxis, availableInnerWidth)))
+ child->getMarginForAxis(mainAxis, availableInnerWidth)
+ .unwrap())
: lineHeight;
const float childHeight = !isMainAxisRow
? (child->getLayout()
.measuredDimensions[YGDimensionHeight] +
- YGUnwrapFloatOptional(child->getMarginForAxis(
- crossAxis, availableInnerWidth)))
+ child->getMarginForAxis(crossAxis, availableInnerWidth)
+ .unwrap())
: lineHeight;
if (!(YGFloatsEqual(
@@ -3362,7 +3339,8 @@
availableInnerHeight,
true,
"multiline-stretch",
- config);
+ config,
+ layoutMarkerData);
}
}
break;
@@ -3370,8 +3348,10 @@
case YGAlignBaseline: {
child->setLayoutPosition(
currentLead + maxAscentForCurrentLine - YGBaseline(child) +
- YGUnwrapFloatOptional(child->getLeadingPosition(
- YGFlexDirectionColumn, availableInnerCrossDim)),
+ child
+ ->getLeadingPosition(
+ YGFlexDirectionColumn, availableInnerCrossDim)
+ .unwrap(),
YGEdgeTop);
break;
@@ -3428,8 +3407,12 @@
YGFloatMax(
YGFloatMin(
availableInnerMainDim + paddingAndBorderAxisMain,
- YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
- node, mainAxis, maxLineMainDim, mainAxisownerSize))),
+ YGNodeBoundAxisWithinMinAndMax(
+ node,
+ mainAxis,
+ YGFloatOptional{maxLineMainDim},
+ mainAxisownerSize)
+ .unwrap()),
paddingAndBorderAxisMain),
dim[mainAxis]);
}
@@ -3456,11 +3438,13 @@
YGFloatMax(
YGFloatMin(
availableInnerCrossDim + paddingAndBorderAxisCross,
- YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
+ YGNodeBoundAxisWithinMinAndMax(
node,
crossAxis,
- totalLineCrossDim + paddingAndBorderAxisCross,
- crossAxisownerSize))),
+ YGFloatOptional{totalLineCrossDim +
+ paddingAndBorderAxisCross},
+ crossAxisownerSize)
+ .unwrap()),
paddingAndBorderAxisCross),
dim[crossAxis]);
}
@@ -3493,7 +3477,8 @@
isMainAxisRow ? measureModeMainDim : measureModeCrossDim,
availableInnerHeight,
direction,
- config);
+ config,
+ layoutMarkerData);
}
// STEP 11: SETTING TRAILING POSITIONS FOR CHILDREN
@@ -3522,7 +3507,6 @@
}
uint32_t gDepth = 0;
-bool gPrintTree = false;
bool gPrintChanges = false;
bool gPrintSkips = false;
@@ -3541,14 +3525,12 @@
static const char* YGMeasureModeName(
const YGMeasureMode mode,
const bool performLayout) {
- const char* kMeasureModeNames[YGMeasureModeCount] = {
- "UNDEFINED", "EXACTLY", "AT_MOST"};
- const char* kLayoutModeNames[YGMeasureModeCount] = {"LAY_UNDEFINED",
- "LAY_EXACTLY",
- "LAY_AT_"
- "MOST"};
+ constexpr auto N = enums::count<YGMeasureMode>();
+ const char* kMeasureModeNames[N] = {"UNDEFINED", "EXACTLY", "AT_MOST"};
+ const char* kLayoutModeNames[N] = {
+ "LAY_UNDEFINED", "LAY_EXACTLY", "LAY_AT_MOST"};
- if (mode >= YGMeasureModeCount) {
+ if (mode >= N) {
return "";
}
@@ -3592,7 +3574,27 @@
const bool forceCeil,
const bool forceFloor) {
float scaledValue = value * pointScaleFactor;
+ // We want to calculate `fractial` such that `floor(scaledValue) = scaledValue
+ // - fractial`.
float fractial = fmodf(scaledValue, 1.0f);
+ if (fractial < 0) {
+ // This branch is for handling negative numbers for `value`.
+ //
+ // Regarding `floor` and `ceil`. Note that for a number x, `floor(x) <= x <=
+ // ceil(x)` even for negative numbers. Here are a couple of examples:
+ // - x = 2.2: floor( 2.2) = 2, ceil( 2.2) = 3
+ // - x = -2.2: floor(-2.2) = -3, ceil(-2.2) = -2
+ //
+ // Regarding `fmodf`. For fractional negative numbers, `fmodf` returns a
+ // negative number. For example, `fmodf(-2.2) = -0.2`. However, we want
+ // `fractial` to be the number such that subtracting it from `value` will
+ // give us `floor(value)`. In the case of negative numbers, adding 1 to
+ // `fmodf(value)` gives us this. Let's continue the example from above:
+ // - fractial = fmodf(-2.2) = -0.2
+ // - Add 1 to the fraction: fractial2 = fractial + 1 = -0.2 + 1 = 0.8
+ // - Finding the `floor`: -2.2 - fractial2 = -2.2 - 0.8 = -3
+ ++fractial;
+ }
if (YGFloatsEqual(fractial, 0)) {
// First we check if the value is already rounded
scaledValue = scaledValue - fractial;
@@ -3690,8 +3692,8 @@
}
//
-// This is a wrapper around the YGNodelayoutImpl function. It determines
-// whether the layout request is redundant and can be skipped.
+// This is a wrapper around the YGNodelayoutImpl function. It determines whether
+// the layout request is redundant and can be skipped.
//
// Parameters:
// Input parameters are the same as YGNodelayoutImpl (see above)
@@ -3708,7 +3710,8 @@
const float ownerHeight,
const bool performLayout,
const char* reason,
- const YGConfigRef config) {
+ const YGConfigRef config,
+ YGMarkerLayoutData& layoutMarkerData) {
YGLayout* layout = &node->getLayout();
gDepth++;
@@ -3720,8 +3723,8 @@
if (needToVisitNode) {
// Invalidate the cached results.
layout->nextCachedMeasurementsIndex = 0;
- layout->cachedLayout.widthMeasureMode = (YGMeasureMode)-1;
- layout->cachedLayout.heightMeasureMode = (YGMeasureMode)-1;
+ layout->cachedLayout.widthMeasureMode = (YGMeasureMode) -1;
+ layout->cachedLayout.heightMeasureMode = (YGMeasureMode) -1;
layout->cachedLayout.computedWidth = -1;
layout->cachedLayout.computedHeight = -1;
}
@@ -3730,21 +3733,17 @@
// Determine whether the results are already cached. We maintain a separate
// cache for layouts and measurements. A layout operation modifies the
- // positions
- // and dimensions for nodes in the subtree. The algorithm assumes that each
- // node
- // gets layed out a maximum of one time per tree layout, but multiple
- // measurements
- // may be required to resolve all of the flex dimensions.
- // We handle nodes with measure functions specially here because they are the
- // most
- // expensive to measure, so it's worth avoiding redundant measurements if at
- // all possible.
+ // positions and dimensions for nodes in the subtree. The algorithm assumes
+ // that each node gets layed out a maximum of one time per tree layout, but
+ // multiple measurements may be required to resolve all of the flex
+ // dimensions. We handle nodes with measure functions specially here because
+ // they are the most expensive to measure, so it's worth avoiding redundant
+ // measurements if at all possible.
if (node->getMeasure() != nullptr) {
- const float marginAxisRow = YGUnwrapFloatOptional(
- node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
- const float marginAxisColumn = YGUnwrapFloatOptional(
- node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
+ const float marginAxisRow =
+ node->getMarginForAxis(YGFlexDirectionRow, ownerWidth).unwrap();
+ const float marginAxisColumn =
+ node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth).unwrap();
// First, try to use the layout cache.
if (YGNodeCanUseCachedMeasurement(
@@ -3811,6 +3810,9 @@
layout->measuredDimensions[YGDimensionHeight] =
cachedResults->computedHeight;
+ (performLayout ? layoutMarkerData.cachedLayouts
+ : layoutMarkerData.cachedMeasures) += 1;
+
if (gPrintChanges && gPrintSkips) {
YGLog(
node,
@@ -3866,7 +3868,8 @@
ownerWidth,
ownerHeight,
performLayout,
- config);
+ config,
+ layoutMarkerData);
if (gPrintChanges) {
YGLog(
@@ -3893,6 +3896,11 @@
layout->lastOwnerDirection = ownerDirection;
if (cachedResults == nullptr) {
+ if (layout->nextCachedMeasurementsIndex + 1 >
+ (uint32_t) layoutMarkerData.maxMeasureCache) {
+ layoutMarkerData.maxMeasureCache =
+ layout->nextCachedMeasurementsIndex + 1;
+ }
if (layout->nextCachedMeasurementsIndex == YG_MAX_CACHED_RESULT_COUNT) {
if (gPrintChanges) {
YGLog(node, YGLogLevelVerbose, "Out of cache entries!\n");
@@ -4034,26 +4042,28 @@
const float ownerWidth,
const float ownerHeight,
const YGDirection ownerDirection) {
+ marker::MarkerSection<YGMarkerLayout> marker{node};
+
// Increment the generation count. This will force the recursive routine to
- // visit
- // all dirty nodes at least once. Subsequent visits will be skipped if the
- // input
- // parameters don't change.
+ // visit all dirty nodes at least once. Subsequent visits will be skipped if
+ // the input parameters don't change.
gCurrentGenerationCount++;
node->resolveDimension();
float width = YGUndefined;
YGMeasureMode widthMeasureMode = YGMeasureModeUndefined;
if (YGNodeIsStyleDimDefined(node, YGFlexDirectionRow, ownerWidth)) {
- width = YGUnwrapFloatOptional(
- YGResolveValue(
+ width =
+ (YGResolveValue(
node->getResolvedDimension(dim[YGFlexDirectionRow]), ownerWidth) +
- node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
+ node->getMarginForAxis(YGFlexDirectionRow, ownerWidth))
+ .unwrap();
widthMeasureMode = YGMeasureModeExactly;
} else if (!YGResolveValue(
node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth)
.isUndefined()) {
- width = YGUnwrapFloatOptional(YGResolveValue(
- node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth));
+ width = YGResolveValue(
+ node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth)
+ .unwrap();
widthMeasureMode = YGMeasureModeAtMost;
} else {
width = ownerWidth;
@@ -4064,18 +4074,19 @@
float height = YGUndefined;
YGMeasureMode heightMeasureMode = YGMeasureModeUndefined;
if (YGNodeIsStyleDimDefined(node, YGFlexDirectionColumn, ownerHeight)) {
- height = YGUnwrapFloatOptional(
- YGResolveValue(
+ height = (YGResolveValue(
node->getResolvedDimension(dim[YGFlexDirectionColumn]),
ownerHeight) +
- node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
+ node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth))
+ .unwrap();
heightMeasureMode = YGMeasureModeExactly;
} else if (!YGResolveValue(
node->getStyle().maxDimensions[YGDimensionHeight],
ownerHeight)
.isUndefined()) {
- height = YGUnwrapFloatOptional(YGResolveValue(
- node->getStyle().maxDimensions[YGDimensionHeight], ownerHeight));
+ height = YGResolveValue(
+ node->getStyle().maxDimensions[YGDimensionHeight], ownerHeight)
+ .unwrap();
heightMeasureMode = YGMeasureModeAtMost;
} else {
height = ownerHeight;
@@ -4093,12 +4104,13 @@
ownerHeight,
true,
"initial",
- node->getConfig())) {
+ node->getConfig(),
+ marker.data)) {
node->setPosition(
node->getLayout().direction, ownerWidth, ownerHeight, ownerWidth);
YGRoundToPixelGrid(node, node->getConfig()->pointScaleFactor, 0.0f, 0.0f);
- if (gPrintTree) {
+ if (node->getConfig()->printTree) {
YGNodePrint(
node,
(YGPrintOptions)(
@@ -4123,6 +4135,7 @@
gCurrentGenerationCount++;
// Rerun the layout, and calculate the diff
originalNode->setAndPropogateUseLegacyFlag(false);
+ YGMarkerLayoutData layoutMarkerData;
if (YGLayoutNodeInternal(
originalNode,
width,
@@ -4134,7 +4147,8 @@
ownerHeight,
true,
"initial",
- originalNode->getConfig())) {
+ originalNode->getConfig(),
+ layoutMarkerData)) {
originalNode->setPosition(
originalNode->getLayout().direction,
ownerWidth,
@@ -4147,10 +4161,11 @@
0.0f);
// Set whether the two layouts are different or not.
- node->setLayoutDoesLegacyFlagAffectsLayout(
- !originalNode->isLayoutTreeEqualToNode(*node));
+ auto neededLegacyStretchBehaviour =
+ !originalNode->isLayoutTreeEqualToNode(*node);
+ node->setLayoutDoesLegacyFlagAffectsLayout(neededLegacyStretchBehaviour);
- if (gPrintTree) {
+ if (originalNode->getConfig()->printTree) {
YGNodePrint(
originalNode,
(YGPrintOptions)(

ReactCommon/yoga/yoga/Yoga.h

@@ -1,9 +1,8 @@
-/*
- * Copyright (c) 2014-present, Facebook, Inc.
+/**
+ * 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.
- *
*/
#pragma once
@@ -18,17 +17,9 @@
#include <stdbool.h>
#endif
-/** Large positive number signifies that the property(float) is undefined.
- *Earlier we used to have YGundefined as NAN, but the downside of this is that
- *we can't use -ffast-math compiler flag as it assumes all floating-point
- *calculation involve and result into finite numbers. For more information
- *regarding -ffast-math compiler flag in clang, have a look at
- *https://clang.llvm.org/docs/UsersManual.html#cmdoption-ffast-math
- **/
-#define YGUndefined 10E20F
-
#include "YGEnums.h"
#include "YGMacros.h"
+#include "YGValue.h"
YG_EXTERN_C_BEGIN
@@ -37,21 +28,6 @@
float height;
} YGSize;
-typedef struct YGValue {
- float value;
- YGUnit unit;
-} YGValue;
-
-extern const YGValue YGValueUndefined;
-extern const YGValue YGValueAuto;
-
-#ifdef __cplusplus
-
-extern bool operator==(const YGValue& lhs, const YGValue& rhs);
-extern bool operator!=(const YGValue& lhs, const YGValue& rhs);
-
-#endif
-
typedef struct YGConfig* YGConfigRef;
typedef struct YGNode* YGNodeRef;
@@ -66,6 +42,7 @@
*YGBaselineFunc)(YGNodeRef node, const float width, const float height);
typedef void (*YGDirtiedFunc)(YGNodeRef node);
typedef void (*YGPrintFunc)(YGNodeRef node);
+typedef void (*YGNodeCleanupFunc)(YGNodeRef node);
typedef int (*YGLogger)(
const YGConfigRef config,
const YGNodeRef node,
@@ -80,6 +57,9 @@
WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config);
WIN_EXPORT YGNodeRef YGNodeClone(const YGNodeRef node);
WIN_EXPORT void YGNodeFree(const YGNodeRef node);
+WIN_EXPORT void YGNodeFreeRecursiveWithCleanupFunc(
+ const YGNodeRef node,
+ YGNodeCleanupFunc cleanup);
WIN_EXPORT void YGNodeFreeRecursive(const YGNodeRef node);
WIN_EXPORT void YGNodeReset(const YGNodeRef node);
WIN_EXPORT int32_t YGNodeGetInstanceCount(void);
@@ -89,16 +69,6 @@
const YGNodeRef child,
const uint32_t index);
-// This function inserts the child YGNodeRef as a children of the node received
-// by parameter and set the Owner of the child object to null. This function is
-// expected to be called when using Yoga in persistent mode in order to share a
-// YGNodeRef object as a child of two different Yoga trees. The child YGNodeRef
-// is expected to be referenced from its original owner and from a clone of its
-// original owner.
-WIN_EXPORT void YGNodeInsertSharedChild(
- const YGNodeRef node,
- const YGNodeRef child,
- const uint32_t index);
WIN_EXPORT void YGNodeRemoveChild(const YGNodeRef node, const YGNodeRef child);
WIN_EXPORT void YGNodeRemoveAllChildren(const YGNodeRef node);
WIN_EXPORT YGNodeRef YGNodeGetChild(const YGNodeRef node, const uint32_t index);
@@ -110,6 +80,12 @@
const YGNodeRef children[],
const uint32_t count);
+WIN_EXPORT void YGNodeSetIsReferenceBaseline(
+ YGNodeRef node,
+ bool isReferenceBaseline);
+
+WIN_EXPORT bool YGNodeIsReferenceBaseline(YGNodeRef node);
+
WIN_EXPORT void YGNodeCalculateLayout(
const YGNodeRef node,
const float availableWidth,
@@ -118,16 +94,16 @@
// Mark a node as dirty. Only valid for nodes with a custom measure function
// set.
-// YG knows when to mark all other nodes as dirty but because nodes with
-// measure functions
-// depends on information not known to YG they must perform this dirty
-// marking manually.
+//
+// Yoga knows when to mark all other nodes as dirty but because nodes with
+// measure functions depend on information not known to Yoga they must perform
+// this dirty marking manually.
WIN_EXPORT void YGNodeMarkDirty(const YGNodeRef node);
-// This function marks the current node and all its descendants as dirty. This
-// function is added to test yoga benchmarks. This function is not expected to
-// be used in production as calling `YGCalculateLayout` will cause the
-// recalculation of each and every node.
+// Marks the current node and all its descendants as dirty.
+//
+// Intended to be used for Uoga benchmarks. Don't use in production, as calling
+// `YGCalculateLayout` will cause the recalculation of each and every node.
WIN_EXPORT void YGNodeMarkDirtyAndPropogateToDescendants(const YGNodeRef node);
WIN_EXPORT void YGNodePrint(const YGNodeRef node, const YGPrintOptions options);
@@ -153,21 +129,22 @@
const YGNodeRef dstNode,
const YGNodeRef srcNode);
-void* YGNodeGetContext(YGNodeRef node);
-void YGNodeSetContext(YGNodeRef node, void* context);
+WIN_EXPORT void* YGNodeGetContext(YGNodeRef node);
+WIN_EXPORT void YGNodeSetContext(YGNodeRef node, void* context);
+void YGConfigSetPrintTreeFlag(YGConfigRef config, bool enabled);
YGMeasureFunc YGNodeGetMeasureFunc(YGNodeRef node);
-void YGNodeSetMeasureFunc(YGNodeRef node, YGMeasureFunc measureFunc);
+WIN_EXPORT void YGNodeSetMeasureFunc(YGNodeRef node, YGMeasureFunc measureFunc);
YGBaselineFunc YGNodeGetBaselineFunc(YGNodeRef node);
void YGNodeSetBaselineFunc(YGNodeRef node, YGBaselineFunc baselineFunc);
YGDirtiedFunc YGNodeGetDirtiedFunc(YGNodeRef node);
void YGNodeSetDirtiedFunc(YGNodeRef node, YGDirtiedFunc dirtiedFunc);
YGPrintFunc YGNodeGetPrintFunc(YGNodeRef node);
void YGNodeSetPrintFunc(YGNodeRef node, YGPrintFunc printFunc);
-bool YGNodeGetHasNewLayout(YGNodeRef node);
-void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout);
+WIN_EXPORT bool YGNodeGetHasNewLayout(YGNodeRef node);
+WIN_EXPORT void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout);
YGNodeType YGNodeGetNodeType(YGNodeRef node);
void YGNodeSetNodeType(YGNodeRef node, YGNodeType nodeType);
-bool YGNodeIsDirty(YGNodeRef node);
+WIN_EXPORT bool YGNodeIsDirty(YGNodeRef node);
bool YGNodeLayoutGetDidUseLegacyFlag(const YGNodeRef node);
WIN_EXPORT void YGNodeStyleSetDirection(
@@ -250,8 +227,8 @@
const YGNodeRef node,
const YGEdge edge,
const float position);
-WIN_EXPORT WIN_STRUCT(YGValue)
- YGNodeStyleGetPosition(const YGNodeRef node, const YGEdge edge);
+WIN_EXPORT YGValue
+YGNodeStyleGetPosition(const YGNodeRef node, const YGEdge edge);
WIN_EXPORT void YGNodeStyleSetMargin(
const YGNodeRef node,
@@ -330,11 +307,11 @@
const float maxHeight);
WIN_EXPORT YGValue YGNodeStyleGetMaxHeight(const YGNodeRef node);
-// Yoga specific properties, not compatible with flexbox specification
-// Aspect ratio control the size of the undefined dimension of a node.
-// Aspect ratio is encoded as a floating point value width/height. e.g. A value
-// of 2 leads to a node with a width twice the size of its height while a value
-// of 0.5 gives the opposite effect.
+// Yoga specific properties, not compatible with flexbox specification Aspect
+// ratio control the size of the undefined dimension of a node. Aspect ratio is
+// encoded as a floating point value width/height. e.g. A value of 2 leads to a
+// node with a width twice the size of its height while a value of 0.5 gives the
+// opposite effect.
//
// - On a node with a set width/height aspect ratio control the size of the
// unset dimension
@@ -371,8 +348,11 @@
const YGEdge edge);
WIN_EXPORT void YGConfigSetLogger(const YGConfigRef config, YGLogger logger);
-WIN_EXPORT void
-YGLog(const YGNodeRef node, YGLogLevel level, const char* message, ...);
+WIN_EXPORT void YGLog(
+ const YGNodeRef node,
+ YGLogLevel level,
+ const char* message,
+ ...);
WIN_EXPORT void YGLogWithConfig(
const YGConfigRef config,
YGLogLevel level,
@@ -387,8 +367,8 @@
const YGConfigRef config,
const bool condition,
const char* message);
-// Set this to number of pixels in 1 point to round calculation results
-// If you want to avoid rounding - set PointScaleFactor to 0
+// Set this to number of pixels in 1 point to round calculation results If you
+// want to avoid rounding - set PointScaleFactor to 0
WIN_EXPORT void YGConfigSetPointScaleFactor(
const YGConfigRef config,
const float pixelsInPoint);
@@ -419,8 +399,8 @@
const YGConfigRef config,
const YGExperimentalFeature feature);
-// Using the web defaults is the prefered configuration for new projects.
-// Usage of non web defaults should be considered as legacy.
+// Using the web defaults is the prefered configuration for new projects. Usage
+// of non web defaults should be considered as legacy.
WIN_EXPORT void YGConfigSetUseWebDefaults(
const YGConfigRef config,
const bool enabled);

ReactCommon/yoga/yoga/Yoga-internal.h

@@ -1,15 +1,15 @@
-/*
- * Copyright (c) 2014-present, Facebook, Inc.
+/**
+ * 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.
- *
*/
#pragma once
#include <algorithm>
#include <array>
#include <cmath>
#include <vector>
+#include "CompactValue.h"
#include "Yoga.h"
using YGVector = std::vector<YGNodeRef>;
@@ -28,15 +28,7 @@
namespace yoga {
inline bool isUndefined(float value) {
- // Value of a float in the case of it being not defined is 10.1E20. Earlier
- // it used to be NAN, the benefit of which was that if NAN is involved in any
- // mathematical expression the result was NAN. But since we want to have
- // `-ffast-math` flag being used by compiler which assumes that the floating
- // point values are not NAN and Inf, we represent YGUndefined as 10.1E20. But
- // now if YGUndefined is involved in any mathematical operations this
- // value(10.1E20) would change. So the following check makes sure that if the
- // value is outside a range (-10E8, 10E8) then it is undefined.
- return value >= 10E8 || value <= -10E8;
+ return std::isnan(value);
}
} // namespace yoga
@@ -51,17 +43,6 @@
extern const YGValue YGValueAuto;
extern const YGValue YGValueZero;
-template <std::size_t size>
-bool YGValueArrayEqual(
- const std::array<YGValue, size> val1,
- const std::array<YGValue, size> val2) {
- bool areEqual = true;
- for (uint32_t i = 0; i < size && areEqual; ++i) {
- areEqual = YGValueEqual(val1[i], val2[i]);
- }
- return areEqual;
-}
-
struct YGCachedMeasurement {
float availableWidth;
float availableHeight;
@@ -74,8 +55,8 @@
YGCachedMeasurement()
: availableWidth(0),
availableHeight(0),
- widthMeasureMode((YGMeasureMode)-1),
- heightMeasureMode((YGMeasureMode)-1),
+ widthMeasureMode((YGMeasureMode) -1),
+ heightMeasureMode((YGMeasureMode) -1),
computedWidth(-1),
computedHeight(-1) {}
@@ -108,13 +89,67 @@
// layouts should not require more than 16 entries to fit within the cache.
#define YG_MAX_CACHED_RESULT_COUNT 16
+namespace facebook {
+namespace yoga {
+namespace detail {
+
+template <size_t Size>
+class Values {
+private:
+ std::array<CompactValue, Size> values_;
+
+public:
+ Values() = default;
+ explicit Values(const YGValue& defaultValue) noexcept {
+ values_.fill(defaultValue);
+ }
+
+ const CompactValue& operator[](size_t i) const noexcept {
+ return values_[i];
+ }
+ CompactValue& operator[](size_t i) noexcept {
+ return values_[i];
+ }
+
+ template <size_t I>
+ YGValue get() const noexcept {
+ return std::get<I>(values_);
+ }
+
+ template <size_t I>
+ void set(YGValue& value) noexcept {
+ std::get<I>(values_) = value;
+ }
+
+ template <size_t I>
+ void set(YGValue&& value) noexcept {
+ set<I>(value);
+ }
+
+ bool operator==(const Values& other) const noexcept {
+ for (size_t i = 0; i < Size; ++i) {
+ if (values_[i] != other.values_[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ Values& operator=(const Values& other) = default;
+};
+
+} // namespace detail
+} // namespace yoga
+} // namespace facebook
+
static const float kDefaultFlexGrow = 0.0f;
static const float kDefaultFlexShrink = 0.0f;
static const float kWebDefaultFlexShrink = 1.0f;
extern bool YGFloatsEqual(const float a, const float b);
extern bool YGValueEqual(const YGValue a, const YGValue b);
-extern const YGValue* YGComputedEdgeValue(
- const std::array<YGValue, YGEdgeCount>& edges,
- const YGEdge edge,
- const YGValue* const defaultValue);
+extern facebook::yoga::detail::CompactValue YGComputedEdgeValue(
+ const facebook::yoga::detail::Values<
+ facebook::yoga::enums::count<YGEdge>()>& edges,
+ YGEdge edge,
+ facebook::yoga::detail::CompactValue defaultValue);

ReactCommon/yoga/yoga.podspec

@@ -1,3 +1,8 @@
+# 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 = JSON.parse(File.read(File.expand_path('../../package.json', __dir__)))
version = package['version']
@@ -42,7 +47,7 @@
source_files = File.join('ReactCommon/yoga', source_files) if ENV['INSTALL_YOGA_WITHOUT_PATH_OPTION']
spec.source_files = source_files
- header_files = 'yoga/{Yoga,YGEnums,YGMacros}.h'
+ header_files = 'yoga/{Yoga,YGEnums,YGMacros,YGValue}.h'
header_files = File.join('ReactCommon/yoga', header_files) if ENV['INSTALL_YOGA_WITHOUT_PATH_OPTION']
spec.public_header_files = header_files
end

react.gradle

@@ -1,8 +1,13 @@
+// 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.
+
import org.apache.tools.ant.taskdefs.condition.Os
def config = project.hasProperty("react") ? project.react : [];
-def cliPath = config.cliPath ?: "node_modules/react-native/local-cli/cli.js"
+def cliPath = config.cliPath ?: "node_modules/react-native/cli.js"
def bundleAssetName = config.bundleAssetName ?: "index.android.bundle"
def entryFile = config.entryFile ?: "index.android.js"
def bundleCommand = config.bundleCommand ?: "bundle"
@@ -12,7 +17,9 @@
afterEvaluate {
- android.applicationVariants.all { def variant ->
+ def isAndroidLibrary = plugins.hasPlugin("com.android.library")
+ def variants = isAndroidLibrary ? android.libraryVariants : android.applicationVariants
+ variants.all { def variant ->
// Create variant and target names
def targetName = variant.name.capitalize()
def targetPath = variant.dirName
@@ -43,11 +50,11 @@
// Set up inputs and outputs so gradle can cache the result
inputs.files fileTree(dir: reactRoot, excludes: inputExcludes)
- outputs.dir jsBundleDir
- outputs.dir resourcesDir
+ outputs.dir(jsBundleDir)
+ outputs.dir(resourcesDir)
// Set up the call to the react-native cli
- workingDir reactRoot
+ workingDir(reactRoot)
// Set up dev mode
def devEnabled = !(config."devDisabledIn${targetName}"
@@ -85,12 +92,18 @@
} else {
variant.registerResGeneratingTask(currentBundleTask)
}
- variant.mergeResources.dependsOn(currentBundleTask)
+ variant.mergeResourcesProvider.get().dependsOn(currentBundleTask)
// packageApplication for Android plugin 3.x
def packageTask = variant.hasProperty("packageApplication")
- ? variant.packageApplication
+ ? variant.packageApplicationProvider.get()
: tasks.findByName("package${targetName}")
+ if (variant.hasProperty("packageLibrary")) {
+ packageTask = variant.packageLibrary
+ }
+
+ // pre bundle build task for Android plugin 3.2+
+ def buildPreBundleTask = tasks.findByName("build${targetName}PreBundle")
def resourcesDirConfigValue = config."resourcesDir${targetName}"
if (resourcesDirConfigValue) {
@@ -100,15 +113,18 @@
group = "react"
description = "copy bundled resources into custom location for ${targetName}."
- from resourcesDir
- into file(resourcesDirConfigValue)
+ from(resourcesDir)
+ into(file(resourcesDirConfigValue))
dependsOn(currentBundleTask)
- enabled currentBundleTask.enabled
+ enabled(currentBundleTask.enabled)
}
packageTask.dependsOn(currentCopyResTask)
+ if (buildPreBundleTask != null) {
+ buildPreBundleTask.dependsOn(currentCopyResTask)
+ }
}
def currentAssetsCopyTask = tasks.create(
@@ -118,26 +134,29 @@
description = "copy bundled JS into ${targetName}."
if (config."jsBundleDir${targetName}") {
- from jsBundleDir
- into file(config."jsBundleDir${targetName}")
+ from(jsBundleDir)
+ into(file(config."jsBundleDir${targetName}"))
} else {
into ("$buildDir/intermediates")
into ("assets/${targetPath}") {
- from jsBundleDir
+ from(jsBundleDir)
}
// Workaround for Android Gradle Plugin 3.2+ new asset directory
into ("merged_assets/${variant.name}/merge${targetName}Assets/out") {
- from jsBundleDir
+ from(jsBundleDir)
}
}
// mergeAssets must run first, as it clears the intermediates directory
- dependsOn(variant.mergeAssets)
+ dependsOn(variant.mergeAssetsProvider.get())
- enabled currentBundleTask.enabled
+ enabled(currentBundleTask.enabled)
}
packageTask.dependsOn(currentAssetsCopyTask)
+ if (buildPreBundleTask != null) {
+ buildPreBundleTask.dependsOn(currentAssetsCopyTask)
+ }
}
}

React.podspec

@@ -1,4 +1,9 @@
# coding: utf-8
+# 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.
+
require "json"
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
@@ -13,7 +18,7 @@
end
folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1'
-folly_version = '2016.10.31.00'
+folly_version = '2018.10.22.00'
Pod::Spec.new do |s|
s.name = "React"
@@ -61,6 +66,7 @@
"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++"
@@ -71,6 +77,7 @@
ss.dependency "Folly", folly_version
ss.dependency "React/Core"
ss.dependency "React/cxxreact"
+ ss.dependency "React/jsiexecutor"
ss.compiler_flags = folly_compiler_flags
ss.private_header_files = "React/Cxx*/*.h"
ss.source_files = "React/Cxx*/*.{h,m,mm}"
@@ -100,19 +107,33 @@
ss.source_files = "React/**/RCTTV*.{h,m}"
end
- s.subspec "jschelpers" do |ss|
+ s.subspec "jsinspector" do |ss|
+ ss.source_files = "ReactCommon/jsinspector/*.{cpp,h}"
+ ss.private_header_files = "ReactCommon/jsinspector/*.h"
+ ss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\"" }
+ end
+
+ s.subspec "jsiexecutor" do |ss|
+ ss.dependency "React/cxxreact"
+ ss.dependency "React/jsi"
ss.dependency "Folly", folly_version
- ss.dependency "React/PrivateDatabase"
+ ss.dependency "DoubleConversion"
+ ss.dependency "glog"
ss.compiler_flags = folly_compiler_flags
- ss.source_files = "ReactCommon/jschelpers/*.{cpp,h}"
- ss.private_header_files = "ReactCommon/jschelpers/*.h"
- ss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\"" }
- ss.framework = "JavaScriptCore"
+ ss.source_files = "ReactCommon/jsiexecutor/jsireact/*.{cpp,h}"
+ ss.private_header_files = "ReactCommon/jsiexecutor/jsireact/*.h"
+ ss.header_dir = "jsireact"
+ ss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\", \"$(PODS_TARGET_SRCROOT)/ReactCommon/jsiexecutor\"" }
end
- s.subspec "jsinspector" do |ss|
- ss.source_files = "ReactCommon/jsinspector/*.{cpp,h}"
- ss.private_header_files = "ReactCommon/jsinspector/*.h"
+ 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"
+ ss.framework = "JavaScriptCore"
ss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\"" }
end
@@ -123,10 +144,11 @@
end
s.subspec "cxxreact" do |ss|
- ss.dependency "React/jschelpers"
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.*"

README.md

@@ -1,27 +1,24 @@
-# [React Native](https://facebook.github.io/react-native/) &middot; [![Circle CI Status](https://circleci.com/gh/facebook/react-native.svg?style=shield)](https://circleci.com/gh/facebook/react-native) [![Build status](https://ci.appveyor.com/api/projects/status/github/facebook/react-native?branch=master&svg=true)](https://ci.appveyor.com/project/facebok/react-native/branch/master) [![npm version](https://badge.fury.io/js/react-native.svg)](https://badge.fury.io/js/react-native) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md#pull-requests)
+# [React Native](https://facebook.github.io/react-native/) &middot; [![Circle CI Status](https://circleci.com/gh/facebook/react-native.svg?style=shield)](https://circleci.com/gh/facebook/react-native) [![Build status](https://ci.appveyor.com/api/projects/status/g8d58ipi3auqdtrk/branch/master?svg=true)](https://ci.appveyor.com/project/facebook/react-native/branch/master) [![npm version](https://badge.fury.io/js/react-native.svg)](https://badge.fury.io/js/react-native) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md#pull-requests)
Learn once, write anywhere: Build mobile apps with React.
-- **Build native mobile apps using JavaScript and React:** React Native lets you build mobile apps using only JavaScript. It uses the same design as [React](https://facebook.github.io/react), letting you compose a rich mobile UI from declarative components.
-- **A React Native app is a real mobile app:** With React Native, you don't build a "mobile web app", an "HTML5 app", or a "hybrid app". You build a real mobile app that's indistinguishable from an app built using Objective-C, Java, or Swift. React Native uses the same fundamental UI building blocks as regular iOS and Android apps. You just put those building blocks together using JavaScript and React.
-- **Don't waste time recompiling:** React Native lets you build your app faster. Instead of recompiling, you can reload your app instantly. With hot reloading, you can even run new code while retaining your application state. Give it a try - it's a magical experience.
-- **Use native code when you need to:** React Native combines smoothly with components written in Objective-C, Java, or Swift. It's simple to drop down to native code if you need to optimize a few aspects of your application. It's also easy to build part of your app in React Native, and part of your app using native code directly - that's how the Facebook app works.
-
-The focus of React Native is on developer efficiency across all the platforms you care about - learn once, write anywhere. Facebook uses React Native in multiple production apps and will continue investing in React Native.
-
See the official [React Native website](https://facebook.github.io/react-native/) for an introduction to React Native.
-Supported operating systems are >= Android 4.1 (API 16) and >= iOS 9.0.
-
-- [Getting Started](#getting-started)
-- [Documentation](#documentation)
-- [Upgrading](#upgrading)
-- [Contributing](#contributing)
+- [Requirements](#requirements)
+- [Getting Started](#building-your-first-react-native-app)
+- [Documentation](#full-documentation)
+- [Upgrading](https://facebook.github.io/react-native/docs/upgrading)
+- [Contributing](#join-the-react-native-community)
+- [Code of Conduct](./CODE_OF_CONDUCT.md)
- [License](#license)
---
-## Getting Started
+## Requirements
+
+Supported target operating systems are >= Android 4.1 (API 16) and >= iOS 9.0. You may use Windows, macOS, or Linux as your development operating system, though building and running iOS apps is limited to macOS by default (tools like [Expo](https://expo.io) can be used to get around this).
+
+## Building your first React Native app
Follow the [Getting Started guide](https://facebook.github.io/react-native/docs/getting-started.html). The recommended way to install React Native depends on your project. Here you can find short guides for the most common scenarios:
@@ -29,52 +26,33 @@
- [Creating a New Application](https://facebook.github.io/react-native/docs/getting-started.html)
- [Adding React Native to an Existing Application](https://facebook.github.io/react-native/docs/integration-with-existing-apps.html)
-
-## Documentation
+## How React Native works
-[The website’s documentation](https://facebook.github.io/react-native/docs/getting-started.html) is divided into multiple sections.
-- There are **Guides** that discuss topics like [debugging](https://facebook.github.io/react-native/docs/debugging.html), [integrating with existing apps](https://facebook.github.io/react-native/docs/integration-with-existing-apps.html), and [the gesture responder system](https://facebook.github.io/react-native/docs/gesture-responder-system.html).
-- The **Components** section covers React components such as [`View`](https://facebook.github.io/react-native/docs/view.html) and [`Button`](https://facebook.github.io/react-native/docs/button.html).
-- The **APIs** section covers other libraries like [Animated](https://facebook.github.io/react-native/docs/animated.html) and [StyleSheet](https://facebook.github.io/react-native/docs/stylesheet.html) that aren’t React components themselves.
-- Finally, React Native provides a small number of **Polyfills** that offer web-like APIs.
+React Native lets you build mobile apps using JavaScript. It uses the same design as [React](https://facebook.github.io/react), letting you compose a rich mobile UI from declarative components.
-Another great way to learn more about the components and APIs included with React Native is to read their source. Look under the `Libraries/Components` directory for components like `ScrollView` and `TextInput`, for example. The RNTester example is also here to demonstrate some of the ways to use these components. From the source you can get an accurate understanding of each component’s behavior and API.
+With React Native, you don't build a "mobile web app", an "HTML5 app", or a "hybrid app". You build a real mobile app that's indistinguishable from an app built using Objective-C, Java, Kotlin, or Swift. React Native uses the same fundamental UI building blocks as regular iOS and Android apps. You just put those building blocks together using JavaScript and React.
-The React Native documentation only discusses the components, APIs and topics specific to React Native (React on iOS and Android). For further documentation on the React API that is shared between React Native and React DOM, refer to the [React documentation](https://facebook.github.io/react/).
+React Native lets you build your app faster. Instead of recompiling, you can reload your app instantly. With hot reloading, you can even run new code while retaining your application state.
+React Native combines smoothly with components written in Objective-C, Java, Kotlin, or Swift. It's simple to drop down to native code if you need to optimize a few aspects of your application. It's also easy to build part of your app in React Native, and part of your app using native code directly - that's how the Facebook app works.
-## Upgrading
+The focus of React Native is on developer efficiency across all the platforms you care about - learn once, write anywhere. Facebook uses React Native in multiple production apps and will continue investing in React Native. You can learn more about our open source roadmap in this blog post: [Open Source Roadmap](https://facebook.github.io/react-native/blog/2018/11/01/oss-roadmap).
-React Native is under active development. See the guide on [upgrading React Native](https://facebook.github.io/react-native/docs/upgrading.html) to keep your project up-to-date.
-
+## Full documentation
-## Contributing
+The full documentation for React Native can be found on our [website](https://facebook.github.io/react-native/docs/getting-started.html). The source for the React Native documentation and website is hosted on a separate repo, <https://github.com/facebook/react-native-website>. Releases are discussed in the React Native Community, <https://github.com/react-native-community/react-native-releases>, and larger discussions and proposals are in <https://github.com/react-native-community/discussions-and-proposals>.
-Read below to learn how you can take part in improving React Native.
+The React Native documentation only discusses the components, APIs, and topics specific to React Native (React on iOS and Android). For further documentation on the React API that is shared between React Native and React DOM, refer to the [React documentation](https://facebook.github.io/react/).
-### [Code of Conduct](https://code.facebook.com/codeofconduct)
+## Join the React Native community
+* Website: https://facebook.github.io/react-native
+* Twitter: https://twitter.com/reactnative
+* Help: https://facebook.github.io/react-native/en/help
-Facebook has adopted a Code of Conduct that we expect project participants to adhere to. Please read [the full text](https://code.facebook.com/codeofconduct) so that you can understand what actions will and will not be tolerated.
-
-### Contributing Guide
-
-Read our [contributing guide](https://facebook.github.io/react-native/docs/contributing.html) to learn about our development process, how to propose bug fixes and improvements, and how to build and test your changes to React Native.
-
-### Beginner Friendly Bugs
-
-We have a list of [beginner friendly issues](https://github.com/facebook/react-native/labels/Good%20first%20issue) to help you get your feet wet in the React Native codebase and familiar with our contribution process. This is a great place to get started.
-
+See the [CONTRIBUTING](./CONTRIBUTING.md) file for how to help out.
## License
-React Native is [MIT licensed](./LICENSE).
-
-React Native documentation is [Creative Commons licensed](./LICENSE-docs).
-
+React Native is MIT licensed, as found in the LICENSE file.
-<img src="https://avatars2.githubusercontent.com/u/69631?s=200&v=4" width="50"></img>
+React Native documentation is Creative Commons licensed, as found in the LICENSE-docs file.

rn-get-polyfills.js

@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013-present, Facebook, Inc.
+ * 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.

scripts/ios-configure-glog.sh

@@ -1,4 +1,9 @@
#!/bin/bash
+# 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.
+
set -e
PLATFORM_NAME="${PLATFORM_NAME:-iphoneos}"
@@ -50,3 +55,12 @@
#define PC_FROM_UCONTEXT uc_mcontext->__ss.__eip
#endif
EOF
+
+# Prepare exported header include
+EXPORTED_INCLUDE_DIR="exported/glog"
+mkdir -p exported/glog
+cp -f src/glog/log_severity.h "$EXPORTED_INCLUDE_DIR/"
+cp -f src/glog/logging.h "$EXPORTED_INCLUDE_DIR/"
+cp -f src/glog/raw_logging.h "$EXPORTED_INCLUDE_DIR/"
+cp -f src/glog/stl_logging.h "$EXPORTED_INCLUDE_DIR/"
+cp -f src/glog/vlog_is_on.h "$EXPORTED_INCLUDE_DIR/"

scripts/ios-install-third-party.sh

@@ -1,6 +1,14 @@
#!/bin/bash
-
-cachedir="$HOME/.rncache"
+# 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.
+
+if [ -d "$HOME/.rncache" ]; then
+ cachedir="$HOME/.rncache" # react-native 0.57.8 and older
+else
+ cachedir="$HOME/Library/Caches/com.facebook.ReactNativeBuild"
+fi
mkdir -p "$cachedir"
function file_fail () {
@@ -64,4 +72,4 @@
fetch_and_unpack glog-0.3.5.tar.gz https://github.com/google/glog/archive/v0.3.5.tar.gz 61067502c5f9769d111ea1ee3f74e6ddf0a5f9cc "\"$SCRIPTDIR/ios-configure-glog.sh\""
fetch_and_unpack double-conversion-1.1.6.tar.gz https://github.com/google/double-conversion/archive/v1.1.6.tar.gz 1c7d88afde3aaeb97bb652776c627b49e132e8e0
fetch_and_unpack boost_1_63_0.tar.gz https://github.com/react-native-community/boost-for-react-native/releases/download/v1.63.0-0/boost_1_63_0.tar.gz c3f57e1d22a995e608983effbb752b54b6eab741
-fetch_and_unpack folly-2016.10.31.00.tar.gz https://github.com/facebook/folly/archive/v2016.10.31.00.tar.gz fb8cdf8962d8c9d0c20a150b6ec3b75d1fa50696
+fetch_and_unpack folly-2018.10.22.00.tar.gz https://github.com/facebook/folly/archive/v2018.10.22.00.tar.gz f70a75bfeb394363d2049a846bba118ffb3b368a

scripts/launchPackager.bat

@@ -1,4 +1,4 @@
-:: Copyright (c) 2015-present, Facebook, Inc.
+:: 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.
@@ -6,6 +6,6 @@
@echo off
title Metro Bundler
call .packager.bat
-node "%~dp0..\local-cli\cli.js" start
+node "%~dp0..\cli.js" --reactNativePath ../ --projectRoot ../../../ start
pause
exit

scripts/launchPackager.command

@@ -1,16 +1,17 @@
#!/bin/bash
-
-# Copyright (c) 2015-present, Facebook, Inc.
+# 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.
# Set terminal title
-echo -en "\033]0;Metro Bundler\a"
+echo -en "\\033]0;Metro Bundler\\a"
clear
THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd)
+
+# shellcheck source=/dev/null
. "$THIS_DIR/packager.sh"
echo "Process terminated. Press <enter> to close the window"
-read
+read -r

scripts/packager.sh

@@ -1,11 +1,23 @@
#!/bin/bash
-
-# Copyright (c) 2015-present, Facebook, Inc.
+# 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.
+# scripts directory
THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd)
+REACT_NATIVE_ROOT="$THIS_DIR/.."
+# Application root directory - General use case: react-native is a dependency
+PROJECT_ROOT="$THIS_DIR/../../.."
+
+# shellcheck source=/dev/null
source "${THIS_DIR}/.packager.env"
-cd "$THIS_DIR/.."
-node "./local-cli/cli.js" start "$@"
+
+# When running react-native tests, react-native doesn't live in node_modules but in the PROJECT_ROOT
+if [ ! -d "$PROJECT_ROOT/node_modules/react-native" ];
+then
+ PROJECT_ROOT="$THIS_DIR/.."
+fi
+# Start packager from PROJECT_ROOT
+cd "$PROJECT_ROOT" || exit
+node "$REACT_NATIVE_ROOT/cli.js" start "$@"

scripts/react-native-xcode.sh

@@ -1,9 +1,9 @@
#!/bin/bash
-# Copyright (c) 2015-present, Facebook, Inc.
+# 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.
-
+#
# Bundle React Native app's code and image assets.
# This script is supposed to be invoked as part of Xcode build process
# and relies on environment variables (including PWD) set by Xcode
@@ -53,9 +53,11 @@
# Path to react-native folder inside node_modules
REACT_NATIVE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
+# The project should be located next to where react-native is installed
+# in node_modules.
+PROJECT_ROOT=${PROJECT_ROOT:-"$REACT_NATIVE_DIR/../.."}
-# Xcode project file for React Native apps is located in ios/ subfolder
-cd "${REACT_NATIVE_DIR}"/../..
+cd $PROJECT_ROOT
# Define NVM_DIR and source the nvm.sh setup script
[ -z "$NVM_DIR" ] && export NVM_DIR="$HOME/.nvm"
@@ -80,16 +82,26 @@
eval "$("$(brew --prefix nodenv)/bin/nodenv" init -)"
fi
+# Set up the ndenv of anyenv if preset
+if [[ ! -x node && -d ${HOME}/.anyenv/bin ]]; then
+ export PATH=${HOME}/.anyenv/bin:${PATH}
+ if [[ "$(anyenv envs | grep -c ndenv )" -eq 1 ]]; then
+ eval "$(anyenv init -)"
+ fi
+fi
+
[ -z "$NODE_BINARY" ] && export NODE_BINARY="node"
-[ -z "$CLI_PATH" ] && export CLI_PATH="$REACT_NATIVE_DIR/local-cli/cli.js"
+[ -z "$NODE_ARGS" ] && export NODE_ARGS=""
+
+[ -z "$CLI_PATH" ] && export CLI_PATH="$REACT_NATIVE_DIR/cli.js"
[ -z "$BUNDLE_COMMAND" ] && BUNDLE_COMMAND="bundle"
if [[ -z "$BUNDLE_CONFIG" ]]; then
CONFIG_ARG=""
else
- CONFIG_ARG="--config $(pwd)/$BUNDLE_CONFIG"
+ CONFIG_ARG="--config $BUNDLE_CONFIG"
fi
nodejs_not_found()
@@ -106,7 +118,7 @@
BUNDLE_FILE="$DEST/main.jsbundle"
-"$NODE_BINARY" "$CLI_PATH" $BUNDLE_COMMAND \
+"$NODE_BINARY" $NODE_ARGS "$CLI_PATH" $BUNDLE_COMMAND \
$CONFIG_ARG \
--entry-file "$ENTRY_FILE" \
--platform ios \

setupBabel.js

@@ -1,27 +0,0 @@
-/**
- * Copyright (c) 2013-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const babelRegisterOnly = require('metro-babel-register');
-
-const BABEL_ENABLED_PATHS = ['local-cli'];
-
-/**
- * Centralized place to register all the directories that need a Babel
- * transformation before being fed to Node.js. Notably, this is necessary to
- * support Flow type annotations.
- */
-function setupBabel() {
- babelRegisterOnly(
- babelRegisterOnly.buildRegExps(__dirname, BABEL_ENABLED_PATHS),
- );
-}
-
-module.exports = setupBabel;

template/android/app/_BUCK

@@ -0,0 +1,55 @@
+# To learn about Buck see [Docs](https://buckbuild.com/).
+# To run your application with Buck:
+# - install Buck
+# - `npm start` - to start the packager
+# - `cd android`
+# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
+# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
+# - `buck install -r android/app` - compile, install and run application
+#
+
+load(":build_defs.bzl", "create_aar_targets", "create_jar_targets")
+
+lib_deps = []
+
+create_aar_targets(glob(["libs/*.aar"]))
+
+create_jar_targets(glob(["libs/*.jar"]))
+
+android_library(
+ name = "all-libs",
+ exported_deps = lib_deps,
+)
+
+android_library(
+ name = "app-code",
+ srcs = glob([
+ "src/main/java/**/*.java",
+ ]),
+ deps = [
+ ":all-libs",
+ ":build_config",
+ ":res",
+ ],
+)
+
+android_build_config(
+ name = "build_config",
+ package = "com.helloworld",
+)
+
+android_resource(
+ name = "res",
+ package = "com.helloworld",
+ res = "src/main/res",
+)
+
+android_binary(
+ name = "app",
+ keystore = "//android/keystores:debug",
+ manifest = "src/main/AndroidManifest.xml",
+ package_type = "debug",
+ deps = [
+ ":app-code",
+ ],
+)

template/android/app/build_defs.bzl

@@ -0,0 +1,19 @@
+"""Helper definitions to glob .aar and .jar targets"""
+
+def create_aar_targets(aarfiles):
+ for aarfile in aarfiles:
+ name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")]
+ lib_deps.append(":" + name)
+ android_prebuilt_aar(
+ name = name,
+ aar = aarfile,
+ )
+
+def create_jar_targets(jarfiles):
+ for jarfile in jarfiles:
+ name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")]
+ lib_deps.append(":" + name)
+ prebuilt_jar(
+ name = name,
+ binary_jar = jarfile,
+ )

template/android/app/build.gradle

@@ -0,0 +1,151 @@
+apply plugin: "com.android.application"
+
+import com.android.build.OutputFile
+
+/**
+ * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
+ * and bundleReleaseJsAndAssets).
+ * These basically call `react-native bundle` with the correct arguments during the Android build
+ * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
+ * bundle directly from the development server. Below you can see all the possible configurations
+ * and their defaults. If you decide to add a configuration block, make sure to add it before the
+ * `apply from: "../../node_modules/react-native/react.gradle"` line.
+ *
+ * project.ext.react = [
+ * // the name of the generated asset file containing your JS bundle
+ * bundleAssetName: "index.android.bundle",
+ *
+ * // the entry file for bundle generation
+ * entryFile: "index.android.js",
+ *
+ * // whether to bundle JS and assets in debug mode
+ * bundleInDebug: false,
+ *
+ * // whether to bundle JS and assets in release mode
+ * bundleInRelease: true,
+ *
+ * // whether to bundle JS and assets in another build variant (if configured).
+ * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
+ * // The configuration property can be in the following formats
+ * // 'bundleIn${productFlavor}${buildType}'
+ * // 'bundleIn${buildType}'
+ * // bundleInFreeDebug: true,
+ * // bundleInPaidRelease: true,
+ * // bundleInBeta: true,
+ *
+ * // whether to disable dev mode in custom build variants (by default only disabled in release)
+ * // for example: to disable dev mode in the staging build type (if configured)
+ * devDisabledInStaging: true,
+ * // The configuration property can be in the following formats
+ * // 'devDisabledIn${productFlavor}${buildType}'
+ * // 'devDisabledIn${buildType}'
+ *
+ * // the root of your project, i.e. where "package.json" lives
+ * root: "../../",
+ *
+ * // where to put the JS bundle asset in debug mode
+ * jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
+ *
+ * // where to put the JS bundle asset in release mode
+ * jsBundleDirRelease: "$buildDir/intermediates/assets/release",
+ *
+ * // where to put drawable resources / React Native assets, e.g. the ones you use via
+ * // require('./image.png')), in debug mode
+ * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
+ *
+ * // where to put drawable resources / React Native assets, e.g. the ones you use via
+ * // require('./image.png')), in release mode
+ * resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
+ *
+ * // by default the gradle tasks are skipped if none of the JS files or assets change; this means
+ * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
+ * // date; if you have any other folders that you want to ignore for performance reasons (gradle
+ * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
+ * // for example, you might want to remove it from here.
+ * inputExcludes: ["android/**", "ios/**"],
+ *
+ * // override which node gets called and with what additional arguments
+ * nodeExecutableAndArgs: ["node"],
+ *
+ * // supply additional arguments to the packager
+ * extraPackagerArgs: []
+ * ]
+ */
+
+project.ext.react = [
+ entryFile: "index.js"
+]
+
+apply from: "../../node_modules/react-native/react.gradle"
+
+/**
+ * Set this to true to create two separate APKs instead of one:
+ * - An APK that only works on ARM devices
+ * - An APK that only works on x86 devices
+ * The advantage is the size of the APK is reduced by about 4MB.
+ * Upload all the APKs to the Play Store and people will download
+ * the correct one based on the CPU architecture of their device.
+ */
+def enableSeparateBuildPerCPUArchitecture = false
+
+/**
+ * Run Proguard to shrink the Java bytecode in release builds.
+ */
+def enableProguardInReleaseBuilds = false
+
+android {
+ compileSdkVersion rootProject.ext.compileSdkVersion
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ defaultConfig {
+ applicationId "com.helloworld"
+ minSdkVersion rootProject.ext.minSdkVersion
+ targetSdkVersion rootProject.ext.targetSdkVersion
+ versionCode 1
+ versionName "1.0"
+ }
+ splits {
+ abi {
+ reset()
+ enable enableSeparateBuildPerCPUArchitecture
+ universalApk false // If true, also generate a universal APK
+ include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
+ }
+ }
+ buildTypes {
+ release {
+ minifyEnabled enableProguardInReleaseBuilds
+ proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
+ }
+ }
+ // applicationVariants are e.g. debug, release
+ applicationVariants.all { variant ->
+ variant.outputs.each { output ->
+ // For each separate APK per architecture, set a unique version code as described here:
+ // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
+ def versionCodes = ["armeabi-v7a":1, "x86":2, "arm64-v8a": 3, "x86_64": 4]
+ def abi = output.getFilter(OutputFile.ABI)
+ if (abi != null) { // null for the universal-debug, universal-release variants
+ output.versionCodeOverride =
+ versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
+ }
+ }
+ }
+}
+
+dependencies {
+ implementation fileTree(dir: "libs", include: ["*.jar"])
+ implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
+ implementation "com.facebook.react:react-native:+" // From node_modules
+}
+
+// Run this once to be able to run the application with BUCK
+// puts all compile dependencies into folder libs for BUCK to use
+task copyDownloadableDepsToLibs(type: Copy) {
+ from configurations.compile
+ into 'libs'
+}

template/android/app/proguard-rules.pro

@@ -0,0 +1,17 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}

template/android/app/src/debug/AndroidManifest.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools">
+
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
+
+ <application android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" />
+</manifest>

template/android/app/src/main/AndroidManifest.xml

@@ -0,0 +1,26 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.helloworld">
+
+ <uses-permission android:name="android.permission.INTERNET" />
+
+ <application
+ android:name=".MainApplication"
+ android:label="@string/app_name"
+ android:icon="@mipmap/ic_launcher"
+ android:roundIcon="@mipmap/ic_launcher_round"
+ android:allowBackup="false"
+ android:theme="@style/AppTheme">
+ <activity
+ android:name=".MainActivity"
+ android:label="@string/app_name"
+ android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
+ android:windowSoftInputMode="adjustResize">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
+ </application>
+
+</manifest>

template/android/app/src/main/java/com/helloworld/MainActivity.java

@@ -0,0 +1,15 @@
+package com.helloworld;
+
+import com.facebook.react.ReactActivity;
+
+public class MainActivity extends ReactActivity {
+
+ /**
+ * Returns the name of the main component registered from JavaScript.
+ * This is used to schedule rendering of the component.
+ */
+ @Override
+ protected String getMainComponentName() {
+ return "HelloWorld";
+ }
+}

template/android/app/src/main/java/com/helloworld/MainApplication.java

@@ -0,0 +1,45 @@
+package com.helloworld;
+
+import android.app.Application;
+
+import com.facebook.react.ReactApplication;
+import com.facebook.react.ReactNativeHost;
+import com.facebook.react.ReactPackage;
+import com.facebook.react.shell.MainReactPackage;
+import com.facebook.soloader.SoLoader;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class MainApplication extends Application implements ReactApplication {
+
+ private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
+ @Override
+ public boolean getUseDeveloperSupport() {
+ return BuildConfig.DEBUG;
+ }
+
+ @Override
+ protected List<ReactPackage> getPackages() {
+ return Arrays.<ReactPackage>asList(
+ new MainReactPackage()
+ );
+ }
+
+ @Override
+ protected String getJSMainModuleName() {
+ return "index";
+ }
+ };
+
+ @Override
+ public ReactNativeHost getReactNativeHost() {
+ return mReactNativeHost;
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ SoLoader.init(this, /* native exopackage */ false);
+ }
+}

template/android/app/src/main/res/mipmap-hdpi/ic_launcher.png

Binary file template/android/app/src/main/res/mipmap-hdpi/ic_launcher.png has changed

template/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png

Binary file template/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png has changed

template/android/app/src/main/res/mipmap-mdpi/ic_launcher.png

Binary file template/android/app/src/main/res/mipmap-mdpi/ic_launcher.png has changed

template/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png

Binary file template/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png has changed

template/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png

Binary file template/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png has changed

template/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png

Binary file template/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png has changed

template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png

Binary file template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png has changed

template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png

Binary file template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png has changed

template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png

Binary file template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png has changed

template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png

Binary file template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png has changed

template/android/app/src/main/res/values/strings.xml

@@ -0,0 +1,3 @@
+<resources>
+ <string name="app_name">Hello App Display Name</string>
+</resources>

template/android/app/src/main/res/values/styles.xml

@@ -0,0 +1,8 @@
+<resources>
+
+ <!-- Base application theme. -->
+ <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
+ <!-- Customize your theme here. -->
+ </style>
+
+</resources>

template/android/build.gradle

@@ -0,0 +1,33 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ ext {
+ buildToolsVersion = "28.0.3"
+ minSdkVersion = 16
+ compileSdkVersion = 28
+ targetSdkVersion = 28
+ supportLibVersion = "28.0.0"
+ }
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.3.1'
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ mavenLocal()
+ google()
+ jcenter()
+ maven {
+ // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
+ url "$rootDir/../node_modules/react-native/android"
+ }
+ }
+}

template/android/gradle/wrapper/gradle-wrapper.jar

Binary file template/android/gradle/wrapper/gradle-wrapper.jar has changed

template/android/gradle/wrapper/gradle-wrapper.properties

@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip

template/android/gradle.properties

@@ -0,0 +1,18 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+# Default value: -Xmx10248m -XX:MaxPermSize=256m
+# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true

template/android/gradlew

@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"

template/android/gradlew.bat

@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega

template/android/keystores/_BUCK

@@ -0,0 +1,8 @@
+keystore(
+ name = "debug",
+ properties = "debug.keystore.properties",
+ store = "debug.keystore",
+ visibility = [
+ "PUBLIC",
+ ],
+)

template/android/keystores/debug.keystore.properties

@@ -0,0 +1,4 @@
+key.store=debug.keystore
+key.alias=androiddebugkey
+key.store.password=android
+key.alias.password=android

template/android/settings.gradle

@@ -0,0 +1,3 @@
+rootProject.name = 'HelloWorld'
+
+include ':app'

template/App.js

@@ -0,0 +1,49 @@
+/**
+ * Sample React Native App
+ * https://github.com/facebook/react-native
+ *
+ * @format
+ * @flow
+ */
+
+import React, {Component} from 'react';
+import {Platform, StyleSheet, Text, View} from 'react-native';
+
+const instructions = Platform.select({
+ ios: 'Press Cmd+R to reload,\n' + 'Cmd+D or shake for dev menu',
+ android:
+ 'Double tap R on your keyboard to reload,\n' +
+ 'Shake or press menu button for dev menu',
+});
+
+type Props = {};
+export default class App extends Component<Props> {
+ render() {
+ return (
+ <View style={styles.container}>
+ <Text style={styles.welcome}>Welcome to React Native!</Text>
+ <Text style={styles.instructions}>To get started, edit App.js</Text>
+ <Text style={styles.instructions}>{instructions}</Text>
+ </View>
+ );
+ }
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ backgroundColor: '#F5FCFF',
+ },
+ welcome: {
+ fontSize: 20,
+ textAlign: 'center',
+ margin: 10,
+ },
+ instructions: {
+ textAlign: 'center',
+ color: '#333333',
+ marginBottom: 5,
+ },
+});

template/app.json

@@ -0,0 +1,4 @@
+{
+ "name": "HelloWorld",
+ "displayName": "HelloWorld"
+}
\ No newline at end of file

template/babel.config.js

@@ -0,0 +1,3 @@
+module.exports = {
+ presets: ['module:metro-react-native-babel-preset'],
+};

template/_buckconfig

@@ -0,0 +1,6 @@
+
+[android]
+ target = Google Inc.:Google APIs:23
+
+[maven_repositories]
+ central = https://repo1.maven.org/maven2

template/_flowconfig

@@ -0,0 +1,69 @@
+[ignore]
+; We fork some components by platform
+.*/*[.]android.js
+
+; Ignore "BUCK" generated dirs
+<PROJECT_ROOT>/\.buckd/
+
+; Ignore unexpected extra "@providesModule"
+.*/node_modules/.*/node_modules/fbjs/.*
+
+; Ignore duplicate module providers
+; For RN Apps installed via npm, "Libraries" folder is inside
+; "node_modules/react-native" but in the source repo it is in the root
+.*/Libraries/react-native/React.js
+
+; Ignore polyfills
+.*/Libraries/polyfills/.*
+
+; Ignore metro
+.*/node_modules/metro/.*
+
+[include]
+
+[libs]
+node_modules/react-native/Libraries/react-native/react-native-interface.js
+node_modules/react-native/flow/
+
+[options]
+emoji=true
+
+esproposal.optional_chaining=enable
+esproposal.nullish_coalescing=enable
+
+module.system=haste
+module.system.haste.use_name_reducers=true
+# get basename
+module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1'
+# strip .js or .js.flow suffix
+module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1'
+# strip .ios suffix
+module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1'
+module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1'
+module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1'
+module.system.haste.paths.blacklist=.*/__tests__/.*
+module.system.haste.paths.blacklist=.*/__mocks__/.*
+module.system.haste.paths.blacklist=<PROJECT_ROOT>/node_modules/react-native/Libraries/Animated/src/polyfills/.*
+module.system.haste.paths.whitelist=<PROJECT_ROOT>/node_modules/react-native/Libraries/.*
+
+munge_underscores=true
+
+module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
+
+module.file_ext=.js
+module.file_ext=.jsx
+module.file_ext=.json
+module.file_ext=.native.js
+
+suppress_type=$FlowIssue
+suppress_type=$FlowFixMe
+suppress_type=$FlowFixMeProps
+suppress_type=$FlowFixMeState
+
+suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
+suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
+suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
+suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
+
+[version]
+^0.92.0

template/_gitattributes

@@ -0,0 +1 @@
+*.pbxproj -text

template/_gitignore

@@ -0,0 +1,56 @@
+# OSX
+#
+.DS_Store
+
+# Xcode
+#
+build/
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+xcuserdata
+*.xccheckout
+*.moved-aside
+DerivedData
+*.hmap
+*.ipa
+*.xcuserstate
+project.xcworkspace
+
+# Android/IntelliJ
+#
+build/
+.idea
+.gradle
+local.properties
+*.iml
+
+# node.js
+#
+node_modules/
+npm-debug.log
+yarn-error.log
+
+# BUCK
+buck-out/
+\.buckd/
+*.keystore
+
+# fastlane
+#
+# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
+# screenshots whenever they are needed.
+# For more information about the recommended setup visit:
+# https://docs.fastlane.tools/best-practices/source-control/
+
+*/fastlane/report.xml
+*/fastlane/Preview.html
+*/fastlane/screenshots
+
+# Bundle artifact
+*.jsbundle

template/index.js

@@ -0,0 +1,9 @@
+/**
+ * @format
+ */
+
+import {AppRegistry} from 'react-native';
+import App from './App';
+import {name as appName} from './app.json';
+
+AppRegistry.registerComponent(appName, () => App);

template/ios/HelloWorld/AppDelegate.h

@@ -0,0 +1,15 @@
+/**
+ * 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.
+ */
+
+#import <React/RCTBridgeDelegate.h>
+#import <UIKit/UIKit.h>
+
+@interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate>
+
+@property (nonatomic, strong) UIWindow *window;
+
+@end

template/ios/HelloWorld/AppDelegate.m

@@ -0,0 +1,42 @@
+/**
+ * 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.
+ */
+
+#import "AppDelegate.h"
+
+#import <React/RCTBridge.h>
+#import <React/RCTBundleURLProvider.h>
+#import <React/RCTRootView.h>
+
+@implementation AppDelegate
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
+{
+ RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
+ RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
+ moduleName:@"HelloWorld"
+ initialProperties:nil];
+
+ rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
+
+ self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
+ UIViewController *rootViewController = [UIViewController new];
+ rootViewController.view = rootView;
+ self.window.rootViewController = rootViewController;
+ [self.window makeKeyAndVisible];
+ return YES;
+}
+
+- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
+{
+#if DEBUG
+ return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
+#else
+ return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
+#endif
+}
+
+@end

template/ios/HelloWorld/Base.lproj/LaunchScreen.xib

@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7702" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
+ <dependencies>
+ <deployment identifier="iOS"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7701"/>
+ <capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
+ </dependencies>
+ <objects>
+ <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+ <view contentMode="scaleToFill" id="iN0-l3-epB">
+ <rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Powered by React Native" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
+ <rect key="frame" x="20" y="439" width="441" height="21"/>
+ <fontDescription key="fontDescription" type="system" pointSize="17"/>
+ <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="HelloWorld" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
+ <rect key="frame" x="20" y="140" width="441" height="43"/>
+ <fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
+ <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
+ <nil key="highlightedColor"/>
+ </label>
+ </subviews>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+ <constraints>
+ <constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
+ <constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
+ <constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
+ <constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
+ <constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
+ <constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
+ </constraints>
+ <nil key="simulatedStatusBarMetrics"/>
+ <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+ <point key="canvasLocation" x="548" y="455"/>
+ </view>
+ </objects>
+</document>

template/ios/HelloWorld/Images.xcassets/AppIcon.appiconset/Contents.json

@@ -0,0 +1,38 @@
+{
+ "images" : [
+ {
+ "idiom" : "iphone",
+ "size" : "29x29",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "29x29",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "40x40",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "40x40",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "60x60",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "60x60",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file

template/ios/HelloWorld/Images.xcassets/Contents.json

@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}

template/ios/HelloWorld/Info.plist

@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleDisplayName</key>
+ <string>Hello App Display Name</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>NSLocationWhenInUseUsageDescription</key>
+ <string></string>
+ <key>UILaunchStoryboardName</key>
+ <string>LaunchScreen</string>
+ <key>UIRequiredDeviceCapabilities</key>
+ <array>
+ <string>armv7</string>
+ </array>
+ <key>UISupportedInterfaceOrientations</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+ <key>UIViewControllerBasedStatusBarAppearance</key>
+ <false/>
+ <key>NSLocationWhenInUseUsageDescription</key>
+ <string></string>
+ <key>NSAppTransportSecurity</key>
+ <!--See http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/ -->
+ <dict>
+ <key>NSAllowsArbitraryLoads</key>
+ <true/>
+ <key>NSExceptionDomains</key>
+ <dict>
+ <key>localhost</key>
+ <dict>
+ <key>NSExceptionAllowsInsecureHTTPLoads</key>
+ <true/>
+ </dict>
+ </dict>
+ </dict>
+</dict>
+</plist>

template/ios/HelloWorld/main.m

@@ -0,0 +1,16 @@
+/**
+ * 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.
+ */
+
+#import <UIKit/UIKit.h>
+
+#import "AppDelegate.h"
+
+int main(int argc, char * argv[]) {
+ @autoreleasepool {
+ return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+ }
+}

template/ios/HelloWorldTests/HelloWorldTests.m

@@ -0,0 +1,68 @@
+/**
+ * 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.
+ */
+
+#import <UIKit/UIKit.h>
+#import <XCTest/XCTest.h>
+
+#import <React/RCTLog.h>
+#import <React/RCTRootView.h>
+
+#define TIMEOUT_SECONDS 600
+#define TEXT_TO_LOOK_FOR @"Welcome to React Native!"
+
+@interface HelloWorldTests : XCTestCase
+
+@end
+
+@implementation HelloWorldTests
+
+- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
+{
+ if (test(view)) {
+ return YES;
+ }
+ for (UIView *subview in [view subviews]) {
+ if ([self findSubviewInView:subview matching:test]) {
+ return YES;
+ }
+ }
+ return NO;
+}
+
+- (void)testRendersWelcomeScreen
+{
+ UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController];
+ NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
+ BOOL foundElement = NO;
+
+ __block NSString *redboxError = nil;
+ RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
+ if (level >= RCTLogLevelError) {
+ redboxError = message;
+ }
+ });
+
+ while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
+ [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
+ [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
+
+ foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
+ if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
+ return YES;
+ }
+ return NO;
+ }];
+ }
+
+ RCTSetLogFunction(RCTDefaultLogFunction);
+
+ XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
+ XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
+}
+
+
+@end

template/ios/HelloWorldTests/Info.plist

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+</dict>
+</plist>

template/ios/HelloWorld-tvOS/Info.plist

@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>UILaunchStoryboardName</key>
+ <string>LaunchScreen</string>
+ <key>UIRequiredDeviceCapabilities</key>
+ <array>
+ <string>armv7</string>
+ </array>
+ <key>UISupportedInterfaceOrientations</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+ <key>UIViewControllerBasedStatusBarAppearance</key>
+ <false/>
+ <key>NSLocationWhenInUseUsageDescription</key>
+ <string></string>
+ <key>NSAppTransportSecurity</key>
+ <!--See http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/ -->
+ <dict>
+ <key>NSExceptionDomains</key>
+ <dict>
+ <key>localhost</key>
+ <dict>
+ <key>NSExceptionAllowsInsecureHTTPLoads</key>
+ <true/>
+ </dict>
+ </dict>
+ </dict>
+</dict>
+</plist>

template/ios/HelloWorld-tvOSTests/Info.plist

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+</dict>
+</plist>

template/ios/HelloWorld.xcodeproj/project.pbxproj

@@ -0,0 +1,1502 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; };
+ 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; };
+ 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */; };
+ 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; };
+ 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; };
+ 00E356F31AD99517003FC87E /* HelloWorldTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* HelloWorldTests.m */; };
+ 11D1A2F320CAFA9E000508D9 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */; };
+ 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; };
+ 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; };
+ 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */; };
+ 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
+ 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
+ 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
+ 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
+ 140ED2AC1D01E1AD002B40FF /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
+ 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
+ 2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
+ 2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
+ 2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
+ 2D02E4C21E0B4AEC006451C7 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation.a */; };
+ 2D02E4C31E0B4AEC006451C7 /* libRCTImage-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */; };
+ 2D02E4C41E0B4AEC006451C7 /* libRCTLinking-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */; };
+ 2D02E4C51E0B4AEC006451C7 /* libRCTNetwork-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */; };
+ 2D02E4C61E0B4AEC006451C7 /* libRCTSettings-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */; };
+ 2D02E4C71E0B4AEC006451C7 /* libRCTText-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */; };
+ 2D02E4C81E0B4AEC006451C7 /* libRCTWebSocket-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */; };
+ 2D16E6881FA4F8E400B85C8A /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D16E6891FA4F8E400B85C8A /* libReact.a */; };
+ 2DCD954D1E0B4F2C00145EB5 /* HelloWorldTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* HelloWorldTests.m */; };
+ 2DF0FFEE2056DD460020B375 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3EA31DF850E9000B6D8A /* libReact.a */; };
+ 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
+ ADBDB9381DFEBF1600ED6528 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */; };
+ ED297163215061F000B7C4FE /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ED297162215061F000B7C4FE /* JavaScriptCore.framework */; };
+ ED2971652150620600B7C4FE /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ED2971642150620600B7C4FE /* JavaScriptCore.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 134814201AA4EA6300B7C361;
+ remoteInfo = RCTActionSheet;
+ };
+ 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 134814201AA4EA6300B7C361;
+ remoteInfo = RCTGeolocation;
+ };
+ 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 58B5115D1A9E6B3D00147676;
+ remoteInfo = RCTImage;
+ };
+ 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 58B511DB1A9E6C8500147676;
+ remoteInfo = RCTNetwork;
+ };
+ 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 832C81801AAF6DEF007FA2F7;
+ remoteInfo = RCTVibration;
+ };
+ 00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 13B07F861A680F5B00A75B9A;
+ remoteInfo = HelloWorld;
+ };
+ 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 134814201AA4EA6300B7C361;
+ remoteInfo = RCTSettings;
+ };
+ 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 3C86DF461ADF2C930047B81A;
+ remoteInfo = RCTWebSocket;
+ };
+ 146834031AC3E56700842450 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192;
+ remoteInfo = React;
+ };
+ 2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 2D02E47A1E0B4A5D006451C7;
+ remoteInfo = "HelloWorld-tvOS";
+ };
+ 2D16E6711FA4F8DC00B85C8A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = ADD01A681E09402E00F6D226;
+ remoteInfo = "RCTBlob-tvOS";
+ };
+ 2D16E6831FA4F8DC00B85C8A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 3DBE0D001F3B181A0099AA32;
+ remoteInfo = fishhook;
+ };
+ 2D16E6851FA4F8DC00B85C8A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 3DBE0D0D1F3B181C0099AA32;
+ remoteInfo = "fishhook-tvOS";
+ };
+ 2DF0FFDE2056DD460020B375 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = EBF21BDC1FC498900052F4D5;
+ remoteInfo = jsinspector;
+ };
+ 2DF0FFE02056DD460020B375 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = EBF21BFA1FC4989A0052F4D5;
+ remoteInfo = "jsinspector-tvOS";
+ };
+ 2DF0FFE22056DD460020B375 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 139D7ECE1E25DB7D00323FB7;
+ remoteInfo = "third-party";
+ };
+ 2DF0FFE42056DD460020B375 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 3D383D3C1EBD27B6005632C8;
+ remoteInfo = "third-party-tvOS";
+ };
+ 2DF0FFE62056DD460020B375 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 139D7E881E25C6D100323FB7;
+ remoteInfo = "double-conversion";
+ };
+ 2DF0FFE82056DD460020B375 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 3D383D621EBD27B9005632C8;
+ remoteInfo = "double-conversion-tvOS";
+ };
+ 2DF0FFEA2056DD460020B375 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 9936F3131F5F2E4B0010BF04;
+ remoteInfo = privatedata;
+ };
+ 2DF0FFEC2056DD460020B375 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 9936F32F1F5F2E5B0010BF04;
+ remoteInfo = "privatedata-tvOS";
+ };
+ 3DAD3E831DF850E9000B6D8A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 2D2A283A1D9B042B00D4039D;
+ remoteInfo = "RCTImage-tvOS";
+ };
+ 3DAD3E871DF850E9000B6D8A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 2D2A28471D9B043800D4039D;
+ remoteInfo = "RCTLinking-tvOS";
+ };
+ 3DAD3E8B1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 2D2A28541D9B044C00D4039D;
+ remoteInfo = "RCTNetwork-tvOS";
+ };
+ 3DAD3E8F1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 2D2A28611D9B046600D4039D;
+ remoteInfo = "RCTSettings-tvOS";
+ };
+ 3DAD3E931DF850E9000B6D8A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 2D2A287B1D9B048500D4039D;
+ remoteInfo = "RCTText-tvOS";
+ };
+ 3DAD3E981DF850E9000B6D8A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 2D2A28881D9B049200D4039D;
+ remoteInfo = "RCTWebSocket-tvOS";
+ };
+ 3DAD3EA21DF850E9000B6D8A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 2D2A28131D9B038B00D4039D;
+ remoteInfo = "React-tvOS";
+ };
+ 3DAD3EA41DF850E9000B6D8A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 3D3C059A1DE3340900C268FA;
+ remoteInfo = yoga;
+ };
+ 3DAD3EA61DF850E9000B6D8A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 3D3C06751DE3340C00C268FA;
+ remoteInfo = "yoga-tvOS";
+ };
+ 3DAD3EA81DF850E9000B6D8A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 3D3CD9251DE5FBEC00167DC4;
+ remoteInfo = cxxreact;
+ };
+ 3DAD3EAA1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 3D3CD9321DE5FBEE00167DC4;
+ remoteInfo = "cxxreact-tvOS";
+ };
+ 3DAD3EAC1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 3D3CD90B1DE5FBD600167DC4;
+ remoteInfo = jschelpers;
+ };
+ 3DAD3EAE1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 3D3CD9181DE5FBD800167DC4;
+ remoteInfo = "jschelpers-tvOS";
+ };
+ 5E9157321DD0AC6500FF2AA8 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 134814201AA4EA6300B7C361;
+ remoteInfo = RCTAnimation;
+ };
+ 5E9157341DD0AC6500FF2AA8 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 2D2A28201D9B03D100D4039D;
+ remoteInfo = "RCTAnimation-tvOS";
+ };
+ 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 134814201AA4EA6300B7C361;
+ remoteInfo = RCTLinking;
+ };
+ 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 58B5119B1A9E6C1200147676;
+ remoteInfo = RCTText;
+ };
+ ADBDB9261DFEBF0700ED6528 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 358F4ED71D1E81A9004DF814;
+ remoteInfo = RCTBlob;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = "<group>"; };
+ 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = "../node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj"; sourceTree = "<group>"; };
+ 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = "../node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj"; sourceTree = "<group>"; };
+ 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = "../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj"; sourceTree = "<group>"; };
+ 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = "../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj"; sourceTree = "<group>"; };
+ 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = "../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj"; sourceTree = "<group>"; };
+ 00E356EE1AD99517003FC87E /* HelloWorldTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HelloWorldTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 00E356F21AD99517003FC87E /* HelloWorldTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HelloWorldTests.m; sourceTree = "<group>"; };
+ 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = "../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj"; sourceTree = "<group>"; };
+ 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = "../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj"; sourceTree = "<group>"; };
+ 13B07F961A680F5B00A75B9A /* HelloWorld.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloWorld.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = HelloWorld/AppDelegate.h; sourceTree = "<group>"; };
+ 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = HelloWorld/AppDelegate.m; sourceTree = "<group>"; };
+ 13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
+ 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = HelloWorld/Images.xcassets; sourceTree = "<group>"; };
+ 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = HelloWorld/Info.plist; sourceTree = "<group>"; };
+ 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = HelloWorld/main.m; sourceTree = "<group>"; };
+ 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = "<group>"; };
+ 2D02E47B1E0B4A5D006451C7 /* HelloWorld-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "HelloWorld-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 2D02E4901E0B4A5D006451C7 /* HelloWorld-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "HelloWorld-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 2D16E6891FA4F8E400B85C8A /* libReact.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libReact.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = "<group>"; };
+ 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = "<group>"; };
+ 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = "<group>"; };
+ ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTBlob.xcodeproj; path = "../node_modules/react-native/Libraries/Blob/RCTBlob.xcodeproj"; sourceTree = "<group>"; };
+ ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
+ ED2971642150620600B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS12.0.sdk/System/Library/Frameworks/JavaScriptCore.framework; sourceTree = DEVELOPER_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 00E356EB1AD99517003FC87E /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 140ED2AC1D01E1AD002B40FF /* libReact.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ ED297163215061F000B7C4FE /* JavaScriptCore.framework in Frameworks */,
+ ADBDB9381DFEBF1600ED6528 /* libRCTBlob.a in Frameworks */,
+ 11D1A2F320CAFA9E000508D9 /* libRCTAnimation.a in Frameworks */,
+ 146834051AC3E58100842450 /* libReact.a in Frameworks */,
+ 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */,
+ 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */,
+ 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */,
+ 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */,
+ 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */,
+ 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */,
+ 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */,
+ 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */,
+ 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2D02E4781E0B4A5D006451C7 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ ED2971652150620600B7C4FE /* JavaScriptCore.framework in Frameworks */,
+ 2D16E6881FA4F8E400B85C8A /* libReact.a in Frameworks */,
+ 2D02E4C21E0B4AEC006451C7 /* libRCTAnimation.a in Frameworks */,
+ 2D02E4C31E0B4AEC006451C7 /* libRCTImage-tvOS.a in Frameworks */,
+ 2D02E4C41E0B4AEC006451C7 /* libRCTLinking-tvOS.a in Frameworks */,
+ 2D02E4C51E0B4AEC006451C7 /* libRCTNetwork-tvOS.a in Frameworks */,
+ 2D02E4C61E0B4AEC006451C7 /* libRCTSettings-tvOS.a in Frameworks */,
+ 2D02E4C71E0B4AEC006451C7 /* libRCTText-tvOS.a in Frameworks */,
+ 2D02E4C81E0B4AEC006451C7 /* libRCTWebSocket-tvOS.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2D02E48D1E0B4A5D006451C7 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2DF0FFEE2056DD460020B375 /* libReact.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 00C302A81ABCB8CE00DB3ED1 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 00C302B61ABCB90400DB3ED1 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 00C302BC1ABCB91800DB3ED1 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */,
+ 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 00C302D41ABCB9D200DB3ED1 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */,
+ 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 00C302E01ABCB9EE00DB3ED1 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 00E356EF1AD99517003FC87E /* HelloWorldTests */ = {
+ isa = PBXGroup;
+ children = (
+ 00E356F21AD99517003FC87E /* HelloWorldTests.m */,
+ 00E356F01AD99517003FC87E /* Supporting Files */,
+ );
+ path = HelloWorldTests;
+ sourceTree = "<group>";
+ };
+ 00E356F01AD99517003FC87E /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ 00E356F11AD99517003FC87E /* Info.plist */,
+ );
+ name = "Supporting Files";
+ sourceTree = "<group>";
+ };
+ 139105B71AF99BAD00B5F7CC /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */,
+ 3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 139FDEE71B06529A00C62182 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */,
+ 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */,
+ 2D16E6841FA4F8DC00B85C8A /* libfishhook.a */,
+ 2D16E6861FA4F8DC00B85C8A /* libfishhook-tvOS.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 13B07FAE1A68108700A75B9A /* HelloWorld */ = {
+ isa = PBXGroup;
+ children = (
+ 008F07F21AC5B25A0029DE68 /* main.jsbundle */,
+ 13B07FAF1A68108700A75B9A /* AppDelegate.h */,
+ 13B07FB01A68108700A75B9A /* AppDelegate.m */,
+ 13B07FB51A68108700A75B9A /* Images.xcassets */,
+ 13B07FB61A68108700A75B9A /* Info.plist */,
+ 13B07FB11A68108700A75B9A /* LaunchScreen.xib */,
+ 13B07FB71A68108700A75B9A /* main.m */,
+ );
+ name = HelloWorld;
+ sourceTree = "<group>";
+ };
+ 146834001AC3E56700842450 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 146834041AC3E56700842450 /* libReact.a */,
+ 3DAD3EA31DF850E9000B6D8A /* libReact.a */,
+ 3DAD3EA51DF850E9000B6D8A /* libyoga.a */,
+ 3DAD3EA71DF850E9000B6D8A /* libyoga.a */,
+ 3DAD3EA91DF850E9000B6D8A /* libcxxreact.a */,
+ 3DAD3EAB1DF850E9000B6D8A /* libcxxreact.a */,
+ 3DAD3EAD1DF850E9000B6D8A /* libjschelpers.a */,
+ 3DAD3EAF1DF850E9000B6D8A /* libjschelpers.a */,
+ 2DF0FFDF2056DD460020B375 /* libjsinspector.a */,
+ 2DF0FFE12056DD460020B375 /* libjsinspector-tvOS.a */,
+ 2DF0FFE32056DD460020B375 /* libthird-party.a */,
+ 2DF0FFE52056DD460020B375 /* libthird-party.a */,
+ 2DF0FFE72056DD460020B375 /* libdouble-conversion.a */,
+ 2DF0FFE92056DD460020B375 /* libdouble-conversion.a */,
+ 2DF0FFEB2056DD460020B375 /* libprivatedata.a */,
+ 2DF0FFED2056DD460020B375 /* libprivatedata-tvOS.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 2D16E6871FA4F8E400B85C8A /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
+ ED2971642150620600B7C4FE /* JavaScriptCore.framework */,
+ 2D16E6891FA4F8E400B85C8A /* libReact.a */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ 5E91572E1DD0AC6500FF2AA8 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */,
+ 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 78C398B11ACF4ADC00677621 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 78C398B91ACF4ADC00677621 /* libRCTLinking.a */,
+ 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 832341AE1AAA6A7D00B99B32 /* Libraries */ = {
+ isa = PBXGroup;
+ children = (
+ 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */,
+ 146833FF1AC3E56700842450 /* React.xcodeproj */,
+ 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */,
+ ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */,
+ 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */,
+ 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */,
+ 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */,
+ 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */,
+ 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */,
+ 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */,
+ 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */,
+ 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */,
+ );
+ name = Libraries;
+ sourceTree = "<group>";
+ };
+ 832341B11AAA6A8300B99B32 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 832341B51AAA6A8300B99B32 /* libRCTText.a */,
+ 3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 83CBB9F61A601CBA00E9B192 = {
+ isa = PBXGroup;
+ children = (
+ 13B07FAE1A68108700A75B9A /* HelloWorld */,
+ 832341AE1AAA6A7D00B99B32 /* Libraries */,
+ 00E356EF1AD99517003FC87E /* HelloWorldTests */,
+ 83CBBA001A601CBA00E9B192 /* Products */,
+ 2D16E6871FA4F8E400B85C8A /* Frameworks */,
+ );
+ indentWidth = 2;
+ sourceTree = "<group>";
+ tabWidth = 2;
+ usesTabs = 0;
+ };
+ 83CBBA001A601CBA00E9B192 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 13B07F961A680F5B00A75B9A /* HelloWorld.app */,
+ 00E356EE1AD99517003FC87E /* HelloWorldTests.xctest */,
+ 2D02E47B1E0B4A5D006451C7 /* HelloWorld-tvOS.app */,
+ 2D02E4901E0B4A5D006451C7 /* HelloWorld-tvOSTests.xctest */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ ADBDB9201DFEBF0600ED6528 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */,
+ 2D16E6721FA4F8DC00B85C8A /* libRCTBlob-tvOS.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 00E356ED1AD99517003FC87E /* HelloWorldTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "HelloWorldTests" */;
+ buildPhases = (
+ 00E356EA1AD99517003FC87E /* Sources */,
+ 00E356EB1AD99517003FC87E /* Frameworks */,
+ 00E356EC1AD99517003FC87E /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 00E356F51AD99517003FC87E /* PBXTargetDependency */,
+ );
+ name = HelloWorldTests;
+ productName = HelloWorldTests;
+ productReference = 00E356EE1AD99517003FC87E /* HelloWorldTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+ 13B07F861A680F5B00A75B9A /* HelloWorld */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "HelloWorld" */;
+ buildPhases = (
+ 13B07F871A680F5B00A75B9A /* Sources */,
+ 13B07F8C1A680F5B00A75B9A /* Frameworks */,
+ 13B07F8E1A680F5B00A75B9A /* Resources */,
+ 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = HelloWorld;
+ productName = "Hello World";
+ productReference = 13B07F961A680F5B00A75B9A /* HelloWorld.app */;
+ productType = "com.apple.product-type.application";
+ };
+ 2D02E47A1E0B4A5D006451C7 /* HelloWorld-tvOS */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "HelloWorld-tvOS" */;
+ buildPhases = (
+ 2D02E4771E0B4A5D006451C7 /* Sources */,
+ 2D02E4781E0B4A5D006451C7 /* Frameworks */,
+ 2D02E4791E0B4A5D006451C7 /* Resources */,
+ 2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "HelloWorld-tvOS";
+ productName = "HelloWorld-tvOS";
+ productReference = 2D02E47B1E0B4A5D006451C7 /* HelloWorld-tvOS.app */;
+ productType = "com.apple.product-type.application";
+ };
+ 2D02E48F1E0B4A5D006451C7 /* HelloWorld-tvOSTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "HelloWorld-tvOSTests" */;
+ buildPhases = (
+ 2D02E48C1E0B4A5D006451C7 /* Sources */,
+ 2D02E48D1E0B4A5D006451C7 /* Frameworks */,
+ 2D02E48E1E0B4A5D006451C7 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */,
+ );
+ name = "HelloWorld-tvOSTests";
+ productName = "HelloWorld-tvOSTests";
+ productReference = 2D02E4901E0B4A5D006451C7 /* HelloWorld-tvOSTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 83CBB9F71A601CBA00E9B192 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0940;
+ ORGANIZATIONNAME = Facebook;
+ TargetAttributes = {
+ 00E356ED1AD99517003FC87E = {
+ CreatedOnToolsVersion = 6.2;
+ TestTargetID = 13B07F861A680F5B00A75B9A;
+ };
+ 2D02E47A1E0B4A5D006451C7 = {
+ CreatedOnToolsVersion = 8.2.1;
+ ProvisioningStyle = Automatic;
+ };
+ 2D02E48F1E0B4A5D006451C7 = {
+ CreatedOnToolsVersion = 8.2.1;
+ ProvisioningStyle = Automatic;
+ TestTargetID = 2D02E47A1E0B4A5D006451C7;
+ };
+ };
+ };
+ buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "HelloWorld" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 83CBB9F61A601CBA00E9B192;
+ productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
+ projectDirPath = "";
+ projectReferences = (
+ {
+ ProductGroup = 00C302A81ABCB8CE00DB3ED1 /* Products */;
+ ProjectRef = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */;
+ },
+ {
+ ProductGroup = 5E91572E1DD0AC6500FF2AA8 /* Products */;
+ ProjectRef = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */;
+ },
+ {
+ ProductGroup = ADBDB9201DFEBF0600ED6528 /* Products */;
+ ProjectRef = ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */;
+ },
+ {
+ ProductGroup = 00C302B61ABCB90400DB3ED1 /* Products */;
+ ProjectRef = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */;
+ },
+ {
+ ProductGroup = 00C302BC1ABCB91800DB3ED1 /* Products */;
+ ProjectRef = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
+ },
+ {
+ ProductGroup = 78C398B11ACF4ADC00677621 /* Products */;
+ ProjectRef = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;
+ },
+ {
+ ProductGroup = 00C302D41ABCB9D200DB3ED1 /* Products */;
+ ProjectRef = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */;
+ },
+ {
+ ProductGroup = 139105B71AF99BAD00B5F7CC /* Products */;
+ ProjectRef = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */;
+ },
+ {
+ ProductGroup = 832341B11AAA6A8300B99B32 /* Products */;
+ ProjectRef = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
+ },
+ {
+ ProductGroup = 00C302E01ABCB9EE00DB3ED1 /* Products */;
+ ProjectRef = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */;
+ },
+ {
+ ProductGroup = 139FDEE71B06529A00C62182 /* Products */;
+ ProjectRef = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
+ },
+ {
+ ProductGroup = 146834001AC3E56700842450 /* Products */;
+ ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */;
+ },
+ );
+ projectRoot = "";
+ targets = (
+ 13B07F861A680F5B00A75B9A /* HelloWorld */,
+ 00E356ED1AD99517003FC87E /* HelloWorldTests */,
+ 2D02E47A1E0B4A5D006451C7 /* HelloWorld-tvOS */,
+ 2D02E48F1E0B4A5D006451C7 /* HelloWorld-tvOSTests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXReferenceProxy section */
+ 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libRCTActionSheet.a;
+ remoteRef = 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libRCTGeolocation.a;
+ remoteRef = 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libRCTImage.a;
+ remoteRef = 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libRCTNetwork.a;
+ remoteRef = 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libRCTVibration.a;
+ remoteRef = 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libRCTSettings.a;
+ remoteRef = 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libRCTWebSocket.a;
+ remoteRef = 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 146834041AC3E56700842450 /* libReact.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libReact.a;
+ remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 2D16E6721FA4F8DC00B85C8A /* libRCTBlob-tvOS.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = "libRCTBlob-tvOS.a";
+ remoteRef = 2D16E6711FA4F8DC00B85C8A /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 2D16E6841FA4F8DC00B85C8A /* libfishhook.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libfishhook.a;
+ remoteRef = 2D16E6831FA4F8DC00B85C8A /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 2D16E6861FA4F8DC00B85C8A /* libfishhook-tvOS.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = "libfishhook-tvOS.a";
+ remoteRef = 2D16E6851FA4F8DC00B85C8A /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 2DF0FFDF2056DD460020B375 /* libjsinspector.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libjsinspector.a;
+ remoteRef = 2DF0FFDE2056DD460020B375 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 2DF0FFE12056DD460020B375 /* libjsinspector-tvOS.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = "libjsinspector-tvOS.a";
+ remoteRef = 2DF0FFE02056DD460020B375 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 2DF0FFE32056DD460020B375 /* libthird-party.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = "libthird-party.a";
+ remoteRef = 2DF0FFE22056DD460020B375 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 2DF0FFE52056DD460020B375 /* libthird-party.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = "libthird-party.a";
+ remoteRef = 2DF0FFE42056DD460020B375 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 2DF0FFE72056DD460020B375 /* libdouble-conversion.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = "libdouble-conversion.a";
+ remoteRef = 2DF0FFE62056DD460020B375 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 2DF0FFE92056DD460020B375 /* libdouble-conversion.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = "libdouble-conversion.a";
+ remoteRef = 2DF0FFE82056DD460020B375 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 2DF0FFEB2056DD460020B375 /* libprivatedata.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libprivatedata.a;
+ remoteRef = 2DF0FFEA2056DD460020B375 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 2DF0FFED2056DD460020B375 /* libprivatedata-tvOS.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = "libprivatedata-tvOS.a";
+ remoteRef = 2DF0FFEC2056DD460020B375 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = "libRCTImage-tvOS.a";
+ remoteRef = 3DAD3E831DF850E9000B6D8A /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = "libRCTLinking-tvOS.a";
+ remoteRef = 3DAD3E871DF850E9000B6D8A /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = "libRCTNetwork-tvOS.a";
+ remoteRef = 3DAD3E8B1DF850E9000B6D8A /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = "libRCTSettings-tvOS.a";
+ remoteRef = 3DAD3E8F1DF850E9000B6D8A /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = "libRCTText-tvOS.a";
+ remoteRef = 3DAD3E931DF850E9000B6D8A /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = "libRCTWebSocket-tvOS.a";
+ remoteRef = 3DAD3E981DF850E9000B6D8A /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 3DAD3EA31DF850E9000B6D8A /* libReact.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libReact.a;
+ remoteRef = 3DAD3EA21DF850E9000B6D8A /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 3DAD3EA51DF850E9000B6D8A /* libyoga.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libyoga.a;
+ remoteRef = 3DAD3EA41DF850E9000B6D8A /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 3DAD3EA71DF850E9000B6D8A /* libyoga.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libyoga.a;
+ remoteRef = 3DAD3EA61DF850E9000B6D8A /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 3DAD3EA91DF850E9000B6D8A /* libcxxreact.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libcxxreact.a;
+ remoteRef = 3DAD3EA81DF850E9000B6D8A /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 3DAD3EAB1DF850E9000B6D8A /* libcxxreact.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libcxxreact.a;
+ remoteRef = 3DAD3EAA1DF850E9000B6D8A /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 3DAD3EAD1DF850E9000B6D8A /* libjschelpers.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libjschelpers.a;
+ remoteRef = 3DAD3EAC1DF850E9000B6D8A /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 3DAD3EAF1DF850E9000B6D8A /* libjschelpers.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libjschelpers.a;
+ remoteRef = 3DAD3EAE1DF850E9000B6D8A /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libRCTAnimation.a;
+ remoteRef = 5E9157321DD0AC6500FF2AA8 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libRCTAnimation.a;
+ remoteRef = 5E9157341DD0AC6500FF2AA8 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 78C398B91ACF4ADC00677621 /* libRCTLinking.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libRCTLinking.a;
+ remoteRef = 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 832341B51AAA6A8300B99B32 /* libRCTText.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libRCTText.a;
+ remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libRCTBlob.a;
+ remoteRef = ADBDB9261DFEBF0700ED6528 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+/* End PBXReferenceProxy section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 00E356EC1AD99517003FC87E /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 13B07F8E1A680F5B00A75B9A /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
+ 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2D02E4791E0B4A5D006451C7 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2D02E48E1E0B4A5D006451C7 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Bundle React Native code and images";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh";
+ };
+ 2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Bundle React Native Code And Images";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 00E356EA1AD99517003FC87E /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 00E356F31AD99517003FC87E /* HelloWorldTests.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 13B07F871A680F5B00A75B9A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
+ 13B07FC11A68108700A75B9A /* main.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2D02E4771E0B4A5D006451C7 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */,
+ 2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2D02E48C1E0B4A5D006451C7 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2DCD954D1E0B4F2C00145EB5 /* HelloWorldTests.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 00E356F51AD99517003FC87E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 13B07F861A680F5B00A75B9A /* HelloWorld */;
+ targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */;
+ };
+ 2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 2D02E47A1E0B4A5D006451C7 /* HelloWorld-tvOS */;
+ targetProxy = 2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 13B07FB21A68108700A75B9A /* Base */,
+ );
+ name = LaunchScreen.xib;
+ path = HelloWorld;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 00E356F61AD99517003FC87E /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ INFOPLIST_FILE = HelloWorldTests/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ OTHER_LDFLAGS = (
+ "-ObjC",
+ "-lc++",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HelloWorld.app/HelloWorld";
+ };
+ name = Debug;
+ };
+ 00E356F71AD99517003FC87E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ COPY_PHASE_STRIP = NO;
+ INFOPLIST_FILE = HelloWorldTests/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ OTHER_LDFLAGS = (
+ "-ObjC",
+ "-lc++",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HelloWorld.app/HelloWorld";
+ };
+ name = Release;
+ };
+ 13B07F941A680F5B00A75B9A /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CURRENT_PROJECT_VERSION = 1;
+ DEAD_CODE_STRIPPING = NO;
+ INFOPLIST_FILE = HelloWorld/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ OTHER_LDFLAGS = (
+ "$(inherited)",
+ "-ObjC",
+ "-lc++",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
+ PRODUCT_NAME = HelloWorld;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Debug;
+ };
+ 13B07F951A680F5B00A75B9A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CURRENT_PROJECT_VERSION = 1;
+ INFOPLIST_FILE = HelloWorld/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ OTHER_LDFLAGS = (
+ "$(inherited)",
+ "-ObjC",
+ "-lc++",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
+ PRODUCT_NAME = HelloWorld;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Release;
+ };
+ 2D02E4971E0B4A5E006451C7 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_TESTABILITY = YES;
+ GCC_NO_COMMON_BLOCKS = YES;
+ INFOPLIST_FILE = "HelloWorld-tvOS/Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ OTHER_LDFLAGS = (
+ "-ObjC",
+ "-lc++",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.HelloWorld-tvOS";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = appletvos;
+ TARGETED_DEVICE_FAMILY = 3;
+ TVOS_DEPLOYMENT_TARGET = 9.2;
+ };
+ name = Debug;
+ };
+ 2D02E4981E0B4A5E006451C7 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_NO_COMMON_BLOCKS = YES;
+ INFOPLIST_FILE = "HelloWorld-tvOS/Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ OTHER_LDFLAGS = (
+ "-ObjC",
+ "-lc++",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.HelloWorld-tvOS";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = appletvos;
+ TARGETED_DEVICE_FAMILY = 3;
+ TVOS_DEPLOYMENT_TARGET = 9.2;
+ };
+ name = Release;
+ };
+ 2D02E4991E0B4A5E006451C7 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_TESTABILITY = YES;
+ GCC_NO_COMMON_BLOCKS = YES;
+ INFOPLIST_FILE = "HelloWorld-tvOSTests/Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ OTHER_LDFLAGS = (
+ "-ObjC",
+ "-lc++",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.HelloWorld-tvOSTests";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = appletvos;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HelloWorld-tvOS.app/HelloWorld-tvOS";
+ TVOS_DEPLOYMENT_TARGET = 10.1;
+ };
+ name = Debug;
+ };
+ 2D02E49A1E0B4A5E006451C7 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_NO_COMMON_BLOCKS = YES;
+ INFOPLIST_FILE = "HelloWorld-tvOSTests/Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ OTHER_LDFLAGS = (
+ "-ObjC",
+ "-lc++",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.HelloWorld-tvOSTests";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = appletvos;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HelloWorld-tvOS.app/HelloWorld-tvOS";
+ TVOS_DEPLOYMENT_TARGET = 10.1;
+ };
+ name = Release;
+ };
+ 83CBBA201A601CBA00E9B192 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ };
+ name = Debug;
+ };
+ 83CBBA211A601CBA00E9B192 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = YES;
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "HelloWorldTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 00E356F61AD99517003FC87E /* Debug */,
+ 00E356F71AD99517003FC87E /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "HelloWorld" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 13B07F941A680F5B00A75B9A /* Debug */,
+ 13B07F951A680F5B00A75B9A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "HelloWorld-tvOS" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2D02E4971E0B4A5E006451C7 /* Debug */,
+ 2D02E4981E0B4A5E006451C7 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "HelloWorld-tvOSTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2D02E4991E0B4A5E006451C7 /* Debug */,
+ 2D02E49A1E0B4A5E006451C7 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "HelloWorld" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 83CBBA201A601CBA00E9B192 /* Debug */,
+ 83CBBA211A601CBA00E9B192 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
+}

template/ios/HelloWorld.xcodeproj/xcshareddata/xcschemes/HelloWorld-tvOS.xcscheme

@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "0940"
+ version = "1.3">
+ <BuildAction
+ parallelizeBuildables = "NO"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "2D2A28121D9B038B00D4039D"
+ BuildableName = "libReact.a"
+ BlueprintName = "React-tvOS"
+ ReferencedContainer = "container:../node_modules/react-native/React/React.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
+ BuildableName = "HelloWorld-tvOS.app"
+ BlueprintName = "HelloWorld-tvOS"
+ ReferencedContainer = "container:HelloWorld.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "NO"
+ buildForArchiving = "NO"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "2D02E48F1E0B4A5D006451C7"
+ BuildableName = "HelloWorld-tvOSTests.xctest"
+ BlueprintName = "HelloWorld-tvOSTests"
+ ReferencedContainer = "container:HelloWorld.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES">
+ <Testables>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "2D02E48F1E0B4A5D006451C7"
+ BuildableName = "HelloWorld-tvOSTests.xctest"
+ BlueprintName = "HelloWorld-tvOSTests"
+ ReferencedContainer = "container:HelloWorld.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
+ BuildableName = "HelloWorld-tvOS.app"
+ BlueprintName = "HelloWorld-tvOS"
+ ReferencedContainer = "container:HelloWorld.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </TestAction>
+ <LaunchAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable
+ runnableDebuggingMode = "0">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
+ BuildableName = "HelloWorld-tvOS.app"
+ BlueprintName = "HelloWorld-tvOS"
+ ReferencedContainer = "container:HelloWorld.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ buildConfiguration = "Release"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable
+ runnableDebuggingMode = "0">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
+ BuildableName = "HelloWorld-tvOS.app"
+ BlueprintName = "HelloWorld-tvOS"
+ ReferencedContainer = "container:HelloWorld.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Debug">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>

template/ios/HelloWorld.xcodeproj/xcshareddata/xcschemes/HelloWorld.xcscheme

@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "0940"
+ version = "1.3">
+ <BuildAction
+ parallelizeBuildables = "NO"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "83CBBA2D1A601D0E00E9B192"
+ BuildableName = "libReact.a"
+ BlueprintName = "React"
+ ReferencedContainer = "container:../node_modules/react-native/React/React.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
+ BuildableName = "HelloWorld.app"
+ BlueprintName = "HelloWorld"
+ ReferencedContainer = "container:HelloWorld.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "NO"
+ buildForArchiving = "NO"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "00E356ED1AD99517003FC87E"
+ BuildableName = "HelloWorldTests.xctest"
+ BlueprintName = "HelloWorldTests"
+ ReferencedContainer = "container:HelloWorld.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES">
+ <Testables>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "00E356ED1AD99517003FC87E"
+ BuildableName = "HelloWorldTests.xctest"
+ BlueprintName = "HelloWorldTests"
+ ReferencedContainer = "container:HelloWorld.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
+ BuildableName = "HelloWorld.app"
+ BlueprintName = "HelloWorld"
+ ReferencedContainer = "container:HelloWorld.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </TestAction>
+ <LaunchAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable
+ runnableDebuggingMode = "0">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
+ BuildableName = "HelloWorld.app"
+ BlueprintName = "HelloWorld"
+ ReferencedContainer = "container:HelloWorld.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ buildConfiguration = "Release"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable
+ runnableDebuggingMode = "0">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
+ BuildableName = "HelloWorld.app"
+ BlueprintName = "HelloWorld"
+ ReferencedContainer = "container:HelloWorld.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Debug">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>

template/metro.config.js

@@ -0,0 +1,17 @@
+/**
+ * Metro configuration for React Native
+ * https://github.com/facebook/react-native
+ *
+ * @format
+ */
+
+module.exports = {
+ transformer: {
+ getTransformOptions: async () => ({
+ transform: {
+ experimentalImportSupport: false,
+ inlineRequires: false,
+ },
+ }),
+ },
+};

template/__tests__/App-test.js

@@ -0,0 +1,14 @@
+/**
+ * @format
+ */
+
+import 'react-native';
+import React from 'react';
+import App from '../App';
+
+// Note: test renderer must be required after react-native.
+import renderer from 'react-test-renderer';
+
+it('renders correctly', () => {
+ renderer.create(<App />);
+});

template/_watchmanconfig

@@ -0,0 +1 @@
+{}
\ No newline at end of file

third-party-podspecs/DoubleConversion.podspec

@@ -1,3 +1,8 @@
+# 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.
+
Pod::Spec.new do |spec|
spec.name = 'DoubleConversion'
spec.version = '1.1.6'

third-party-podspecs/Folly.podspec

@@ -1,6 +1,11 @@
+# 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.
+
Pod::Spec.new do |spec|
spec.name = 'Folly'
- spec.version = '2016.10.31.00'
+ spec.version = '2018.10.22.00'
spec.license = { :type => 'Apache License, Version 2.0' }
spec.homepage = 'https://github.com/facebook/folly'
spec.summary = 'An open-source C++ library developed and used at Facebook.'
@@ -12,18 +17,31 @@
spec.dependency 'DoubleConversion'
spec.dependency 'glog'
spec.compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1'
- spec.source_files = 'folly/Bits.cpp',
+ spec.source_files = 'folly/String.cpp',
'folly/Conv.cpp',
'folly/Demangle.cpp',
- 'folly/StringBase.cpp',
+ 'folly/Format.cpp',
+ 'folly/ScopeGuard.cpp',
'folly/Unicode.cpp',
'folly/dynamic.cpp',
'folly/json.cpp',
- 'folly/portability/BitsFunctexcept.cpp',
- 'folly/detail/MallocImpl.cpp'
+ 'folly/json_pointer.cpp',
+ 'folly/container/detail/F14Table.cpp',
+ 'folly/detail/Demangle.cpp',
+ 'folly/hash/SpookyHashV2.cpp',
+ 'folly/lang/Assume.cpp',
+ 'folly/lang/ColdClass.cpp',
+ 'folly/memory/detail/MallocImpl.cpp'
# workaround for https://github.com/facebook/react-native/issues/14326
spec.preserve_paths = 'folly/*.h',
+ 'folly/container/*.h',
+ 'folly/container/detail/*.h',
'folly/detail/*.h',
+ 'folly/functional/*.h',
+ 'folly/hash/*.h',
+ 'folly/lang/*.h',
+ 'folly/memory/*.h',
+ 'folly/memory/detail/*.h',
'folly/portability/*.h'
spec.libraries = "stdc++"
spec.pod_target_xcconfig = { "USE_HEADERMAP" => "NO",

third-party-podspecs/glog.podspec

@@ -1,3 +1,8 @@
+# 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.
+
Pod::Spec.new do |spec|
spec.name = 'glog'
spec.version = '0.3.5'